코드잇 Codeit/Front-End

[코드잇] 인터랙티브 자바스크립트 ① 시작하기, 브라우저와 자바스크립트

꼽파 2023. 12. 23. 14:31


  • 1. 인터랙티브 자바스크립트 시작하기

  • 2. 브라우저와 자바스크립트

  • 1. 인터랙티브 자바스크립트 시작하기

    id로 태그 선택하기

    document.getElementsById('id')

    →   id에 해당하는 태그 하나

    const myTag = document.getElementById('id');

     

    존재하지 않는 id 넣으면 null이 리턴됨.

    const myTag2 = document.getElementById('no_id');
    consoel.log(myTag2)  // null

    class로 태그 선택하기

    document.getElementsByClassName('class')

    →  class에 해당하는 태그 모음(HTMLCollection)

    유사배열 형태로 출력됨.

    배열의 형태이지만 완벽한 배열은 아님.

    · splice, push같은 배열의 메소드 사용 X

    · 대괄호 표기로 인덱스 접근 O

    · length 프로퍼티 사용 O

    · for of문으로 반복 O

    const myTags1 = document.getElementsByClassName('color-btn');
    console.log(myTags1);
    console.log(myTags1[1]);
    console.log(myTags1.length);  // 8
    
    for (let tag of myTags1) {
    	console.log(tag);
    }
    
    // 하나밖에 없는 클래스 
    // → 똑같이 유사배열 형태, 인덱스로 접근해야 됨
    const myTags2 = document.getElementsByClassName('red');
    console.log(myTags2);  // HTMLCollection(Int16Array)
    console.log(myTags2[0]);
    
    // 존재하지 않는 클래스 
    // → null (X), 빈 HTMLCollection 출력
    const myTags3 = document.getElementsByClassName('white');
    console.log(myTags3);  // HTMLCollection(0)
    console.log(myTags3 === null);  // false
    console.log(myTags3.length);  // 0


    유사 배열(Array-Like Object)

    유사배열의 종류가 다양해서 아래 특징이 반드시 적용되는 것은 아님.
    - length 프로퍼티가 있음
    - 배열의 기본 메소드를 사용할 수 없음
    - Array.isArray(유사배열)은 false


    태그 이름으로 태그 선택하기

    document.getElementsByTagName('태그이름') 메소드
    → tag에 해당하는 태그 모음(HTMLCollection)

    const btns = document.getElementsByTagName('button');
    const allTags = document.getElementsByTagName('*');


    이렇게 한꺼번에 많은 요소들을 다루면 실수할 가능성이 높아지기 때문에 많이 사용되는 메소드는 아님.


    css 선택자로 태그 선택하기

    • 하나의 요소 : querySelector
    여러 개의 요소가 존재하는 선택자를 쓰더라도 그 중 가장 첫번째 요소 하나만 선택
    → 존재하지 않는 요소를 선택하는 경우 null값을 리턴함

    const myTag = document.querySelector('#myNumber');  // 아이디 이름
    console.log(myTag);
    
    // <div id="myNumber">0</div>
    const myTag = document.querySelector('.color-btn');  // 클래스 이름
    console.log(myTag);
    
    // <button class="color-btn red" data-color="#FF0000"></button>
    // color-btn 클래스가 붙어있는 태그들 중에서 가장 첫번째 요소가 선택됨.

     

    • 여러 개의 요소 : querySelectorAll
    NodeList라는 이름의 유사 배열에 각 요소가 담김
    → 존재하지 않는 요소를 선택하는 경우 undefined나 null값이 리턴되는 것이 아니라 비어있는 NodeList가 리턴됨.

    const myTags = document.querySelectorAll('.color-btn');
    console.log(myTags);

     

    HTML class 속성으로 태그 선택

    const myTags2 = document.getElementsByClassName('color-btn');
    console.log(myTags2);


    이벤트와 버튼 클릭

     이벤트 : 웹 페이지에서 발생하는 대부분의 일들 (클릭, 스크롤 등)

    • 이벤트 핸들링 : 이벤트가 발생했을 때 어떤 특별한 동작을 하도록 다루는 것
     이벤트 핸들러 : 구체적인 동작들을 코드로 표현한 함수 부분 ( = 이벤트 리스너(Event Listener))

     

    자바스크립트로 해당 DOM 객체의 onclick 프로퍼티에 등록하기

    // 이벤트(Event)와 버튼 클릭
    const btn = document.querySelector('#myBtn');
    
    // 이벤트 핸들링(Event Handling)
    btn.onclick = function() { // 이벤트 핸들러(Event Handler)
    	console.log('Hello World!');
    };

     

    html의 <body>에 onclick 속성으로 바로 표시하기

    <body>
      <div>
        <button id="myBtn" onclick="console.log('Hello World!')">Click!</button>
      </div>
      <script src="index.js"></script>
    </body>

    해당 방법은 잘 사용되는 방법이 아님.
    - HTML 파일 가독성 떨어짐
    - HTML과 Javascript 코드가 섞여서 유지 보수에 큰 어려움이 생김.


    2. 브라우저와 자바스크립트

    윈도우 객체 (전역 객체, global object)

    브라우저의 창을 대변함.

    자바스크립트의 최상단에 위치한 객체임.

    윈도우 객체가 다른 객체를 포함하고 있음.

    자바스크립트의 어느 곳에서나 접근할 수 있음.
    자바스크립트로 브라우저가 가지고 있는 다양한 정보들을 얻거나 혹은 브라우저를 자유롭게 제어할 수 있음.

    → 어떤 프로퍼티나 메소드든 결국 전역 객체 내부의 것이므로 앞에 'window.'을 생략

    // window: 전역객체 Global Object
    console.log(window);
    console.log(window.innerWidth);  // 탭 내부 너비 1004
    console.log(window.innerHeight);  // 탭 내부 높이 744
    
    window.open() // 새로운 창이 열림
    window.close() // close 메소드를 호출한 창이 닫힘


    DOM

    DOM(Document Object Model) 문서 객체 모델

    · 웹페이지에 나타나는 HTML 문서 전체를 객체로 표현한 것
    · document 객체가 이 웹문서의 최상단 객체로 진입점의 역할을 함.

    · 각 객체 = 노드(Node), 태그는 요소노드, 문자는 텍스트 노드로 구분됨.

    console.log(document);
    console.log(typeof document);  // object

    console.log(document)처럼 document 객체를 직접 출력하면 DOM에 해당하는 HTML이 출력됨.

     

    console.dir(document);

     

    dom을 태그가 아니라 객체로 보고 싶으면 console.log가 아니라 콘솔 객체의 dir 메소드를 활용하면 됨.

     

    const title = document.querySelector('#title');

     


    console.dir과 console.log

      console.dir console.log
    출력하는 자료형 원래 값의 자료형 그대로 문자열 형식
    출력하는 내용 파라미터로 전달받은 값을 위주로 출력 객체의 속성을 좀 더 자세히 출력
    파라미터로 전달하는 값의 개수 여러값 전달 시 모든 값을 출력 여러값 전달하더라도 첫 번째 값만 출력
    DOM 객체 HTML 형태로 출력 객체 형태로 출력

    DOM 트리

    • 요소 노드 (Element Node): HTML 또는 XML 문서에서 태그를 나타내는 노드

    이 노드들은 문서의 구조를 형성하며, 각 요소 노드는 특정한 태그를 나타냄.

    • 텍스트 노드 (Text Node)문자열을 나타내는 노드로, 주로 요소 노드의 내용을 포함함.

    - 일반적으로 요소 노드의 자식노드가 됨.
    - 스스로는 자식 노드를 가질 수 없음.


    • 코멘트 노드 (Comment Node): 주석을 나타내는 노드로 <!-- --> 표현됨.

    • 문서 노드 (Document Node): 문서 전체를 나타내는 노드입니다. 

    - HTML 문서의 최상위 노드로, 모든 요소, 텍스트, 주석 등이 이 노드 아래에 포함됨.

    - HTML 문서의 시작 부분에는 과 같은 선언문이 있고, 그 아래에 문서 노드가 시작됨.

     

    노드 유형별 프로퍼티

    // DOM 트리 여행하기
    const myTag = document.querySelector('#list-1');
    console.log(myTag);
    
    // 형제 요소 노드
    console.log(myTag.previousElementSibling);
    console.log(myTag.nextElementSibling);
    
    // 부모 요소 노드
    console.log(myTag.parentElement);
     프로퍼티 유형 결과
    element.children 자식 요소 노드 element의 자식 요소 모음(HTMLCollection)
    element.firstElementChild 자식 요소 노드 element의 첫 번째 자식 요소 하나
    element.lastElementChild 자식 요소 노드 element의 마지막 자식 요소 하나
    element.parentElement 부모 요소 노드 element의 부모 요소 하나
    element.previousElementSibling 형제 요소 노드 element의 이전(previous) 혹은 좌측(left)에 있는 요소 하나
    element.nextElementSibling 형제 요소 노드 element의 다음(next) 혹은 우측(right)에 있는 요소 하나

    요소 노드 프로퍼티

    innerHTML

    · 해당 요소의 HTML 콘텐츠를 가져옴. 줄바꿈, 띄어쓰기 포함됨.

    · innerHTML은 요소 안 HTML을 확인하는 것보다 수정하는 데 더 활용됨.

    <div id="myDiv">
      <p>Hello, <strong>world!</strong></p>
    </div>
    
    <script>
      const myDiv = document.getElementById('myDiv');
      console.log(myDiv.innerHTML); 
      // 출력: "<p>Hello, <strong>world!</strong></p>"
    </script>

     

    outerHTML

    · 해당 요소를 포함한 전체 HTML 코드를 문자열로 리턴해줌. 줄바꿈, 띄어쓰기 포함됨.

    · 해당 요소 자체를 가리키는 특성 때문에 요소 자체가 새로운 요소로 교체됨.
    · outerHTML 에 값을 할당하게 되면 처음 선택한 요소는 사라짐.

    <div id="myDiv">
      <p>Hello, <strong>world!</strong></p>
    </div>
    
    <script>
      const myDiv = document.getElementById('myDiv');
      console.log(myDiv.outerHTML);
      // 출력: "<div id="myDiv"><p>Hello, <strong>world!</strong></p></div>"
    </script>

     

    textContent 

    · 요소 안에 있는 내용 중에서 HTML을 제외한 텍스트를 가져옴.
    · 텍스트만 다르기 때문에 특수문자도 텍스트로 처리함.
    원치 않은 HTML코드가 추가되는 걸 방지할 수 있음.

    <div id="myDiv">
      <p>Hello, <strong>world!</strong></p>
    </div>
    
    <script>
      const myDiv = document.getElementById('myDiv');
      console.log(myDiv.textContent); 
      // 출력: "Hello, world!"
    </script>

    요소 노드 추가하기

    // 현재 날짜로 선택된 요소에 내용 추가하기
    const today = document.querySelector('#today');
    
    // 현재 날짜의 내용 앞에 새로운 <li> 요소 추가 (맨 처음에)
    today.innerHTML = '<li>처음</li>' + today.innerHTML;
    
    // 현재 날짜의 내용 뒤에 새로운 <li> 요소 추가 (맨 마지막에)
    today.innerHTML = today.innerHTML + '<li>마지막</li>';
    
    // 현재 날짜 요소 자체를 변경하여 외부에 <p> 요소 추가 (이전에)
    today.outerHTML = '<p>이전</p>' + today.outerHTML;
    
    // 변경된 DOM에서 다시 현재 날짜로 선택된 요소 가져오기
    const newToday = document.querySelector('#today');
    
    // 현재 날짜의 내용 뒤에 <p> 요소 추가 (맨 뒤에)
    newToday.outerHTML = newToday.outerHTML + '<p>다음</p>';
    
    // 변경된 DOM에서 다시 현재 날짜로 선택된 요소 가져오기
    const newToday = document.querySelector('#today');
    
    // 현재 날짜의 내용 뒤에 <p> 요소 추가 (맨 뒤에)
    newToday.outerHTML = newToday.outerHTML + '<p>다음</p>';
    
    // 새로운 날짜로 선택된 요소에 요소 노드 추가하기
    const tomorrow = document.querySelector('#tomorrow');
    
    // 새로운 <li> 요소 만들기
    const first = document.createElement('li');
    first.textContent = '처음';
    
    // 첫 번째 자식으로 추가하기
    tomorrow.prepend(first);
    
    // 새로운 <li> 요소 만들기
    const last = document.createElement('li');
    last.textContent = '마지막';
    
    // 마지막 자식으로 추가하기
    tomorrow.append(last);
    
    // 새로운 <p> 요소 만들기
    const prev = document.createElement('p');
    prev.textContent = '이전';
    
    // 현재 요소의 이전 형제로 추가하기
    tomorrow.before(prev);
    
    // 새로운 <p> 요소 만들기
    const next = document.createElement('p');
    next.textContent = '다음';
    
    // 현재 요소의 다음 형제로 추가하기
    tomorrow.after(next);


    노드 삭제와 이동하기

    • 요소 노드 만들기 : document.createElement('태그이름')
    • 요소 노드 꾸미기 : element.textContent, element.innerHTML, ...
    • 요소 노드 추가 혹은 이동하기 : 
    - 부모 요소의 자식 노드 중 맨 에 추가 : element.prepend 
    - 부모 요소의 자식 노드 중 맨 에 추가 : element.append 
    현재 요소의 에 추가 : element.after
    현재 요소의 에 추가 : element.before
    • 요소 노드 삭제 : element.remove()

    // 노드 삭제와 이동
    const today = document.querySelector('#today');
    const tomorrow = document.querySelector('#tomorrow');
    
    // 노드 삭제하기: Node.remove()
    tomorrow.remove();
    today.children[2].remove();  // today의 세 번째 자식 요소
    
    // 노드 이동하기: prepend, append, before, after
    today.append(tomorrow.children[1]);
    tomorrow.children[1].after(today.children[1]);
    tomorrow.children[2].before(today.children[1]);
    tomorrow.lastElementChild.before(today.children[1]);

    HTML 속성 다루기

    대부분의 HTML 속성들은 이름 그대로 요소 노드의 프로퍼티로 생성이 됨.
    모든 HTML 속성이 요소 노드의 프로퍼티로 생성되는 것은 아님.

     

    비표준속성의 예시

    <ol id="tomorrow" href="https://www.codeit.kr">
    console.log(tomorrow.href);  // undefined

     

    ol 태그에 href 속성을 추가하는 건 HTML 표준이 아님.

    HTML 태그의 클래스 속성은 className이라는 이름으로 프로퍼티가 생성됨.
    클래스 속성은 이름이 살짝 다름.

    console.log(item.className);  // item


    그럼 HTML 표준이 아닌 속성은 접근 불가인가? 아님.
    프로퍼티에 직접 접근하는 방식으로는 비표준 속성에는 접근할 수 없지만 getAttribute, setAttribute, removeAttribute 메소드를 활용하면 표준 여부와 관계없이 HTML 문서에서 해당 태그에 추가된 모든 속성들에 접근할 수 있음.

    getAttribute() 안에 오는 것들은 속성 이름 모두 대소문자를 구분하지 않음.
    HTML 표준 속성은 모두 소문자이기 때문에 만약 속성 이름에 대문자를 섞어 사용하더라도 소문자로 변환돼서 동작함.

     

    • 속성에 접근하기 : element.getAttribute('속성')
    • 속성 추가(수정)하기 : element.setAttribute('속성', '값')
    • 속성 제거하기 : element.removeAttribute('속성')

    // HTML 속성 (HTML attribute)
    const tomorrow = document.querySelector('#tomorrow');
    const item = tomorrow.firstElementChild;
    const link = item.firstElementChild;
    
    // elem.getAttribute('속성'): 속성에 접근하기
    console.log(tomorrow.getAttribute('href'));
    console.log(item.getAttribute('class'));
    
    // elem.setAttribute('속성', '값'): 속성 추가(수정)하기
    tomorrow.setAttribute('class', 'list'); // 추가
    link.setAttribute('href', 'https://www.codeit.kr'); // 수정
    link.setAttribute('href', undefined);  // 삭제 X, undefined값으로 수정 O
    
    // elem.removeAttribute('속성'): 속성 제거하기
    tomorrow.removeAttribute('href'); 
    tomorrow.removeAttribute('class');


    참고링크 : https://html.spec.whatwg.org/#attributes-3


    스타일 다루기

    Javascript로 HTML 요소에 스타일을 적용하는 방식은 크게 2개가 있음.
    style 프로퍼티 활용하기 : element.style.styleName = 'value';
    class 변경을 통해 간접적으로 스타일을 적용하기 : element.className, element.classList

     

    style 프로퍼티 활용

    // style 프로퍼티 
    today.children[0].style.textDecoration = 'line-through';
    today.children[0].style.backgroundColor = '#DDDDDD';
    today.children[2].style.textDecoration = 'line-through';
    today.children[2].style.backgroundColor = '#DDDDDD';


    · 여러 단어를 하이픈(-)으로 이어서 만든 속성(styleName)은 무조건 카멜표기법
    ex. backgroud-color → backgroudColor, font-size → fontSize

    main.style.boxSizing = 'border-box';

     

    · 의도된 상황이 아니라면 일반적으로 JavaScript를 활용해서 스타일을 입힐 때 style 프로퍼티를 사용하는 것보다 태그의 클래스를 변경하는 방식이 좀 더 권장됨.

     

    element.className

    .done {
      opacity: 0.5;
      text-decoration: line-through;
    }
    
    // elem.className
    today.children[1].className = 'done';

    done 클래스에 미리 작성해둔 스타일이 입혀지는 방식으로 동작함.

     

    element.classList

    · 클래스 리스트 프로퍼티 활용
    · 클래스의 속성값을 유사배열로 다룸.

    · add, remove, toggle 메소드로 추가/삭제/추가 혹은 삭제 가능함.

    // elem.classList
    
    // 스타일 다루기
    const today = document.querySelector('#today');
    const tomorrow = document.querySelector('#tomorrow');
    
    // elem.classList: add, remove, toggle
    const item = tomorrow.children[1];
    
    // add
    itehttp://m.classList.add('done');
    
    //중복으로 추가해도 결국 하나만 추가됨
    itehttp://m.classList.add('done', 'other');
    itehttp://m.classList.add('done', 'other');
    
    // remove
    itehttp://m.classList.remove('done');
    
    // toggle : 클래스 없으면 추가, 있으면 삭제
    itehttp://m.classList.toggle('done') // 위 설명대로 동작
    itehttp://m.classList.toggle('done', true);  // 추가
    itehttp://m.classList.toggle('done', false);  // 삭제

    비표준 속성 다루기

    html의 비표준 속성 활용 용도
    • 선택자로 활용
    • 객체 형태의 데이터에서 값을 표시할 태그를 구분할 때 사용 
    • 스타일이나 데이터 변경에 활용

     

    선택자로 활용

    비표준 속성을 사용하여 특정 요소를 선택

    <div selector-type="custom-selector">
    	<p>This is a content inside the div.</p>
    </div>
    [selector-type="custom-selector"] {
    	background-color: lightblue;
    }

     

    값을 표시할 태그를 구분할 때 사용 

    객체 형태의 데이터가 있을 때, 각 프로퍼티 값들이 들어갈 태그를 구분하는데 활용

    <span field="title"></span>
    <span field="manager"></span>
    <span field="status"></span>
    // HTML 문서에서 [field] 속성을 가진 모든 요소를 선택
    const fields = document.querySelectorAll('[field]');
    
    const task = {
      title: '코드 에디터 개발',
      manager: 'CastleRing, Raccoon Lee',
      status: '',
    };
    
    for (let tag of fields) {
      // 각 요소의 field 속성 값을 가져옴
      const field = tag.getAttribute('field');
      
      // 해당 요소의 텍스트 내용을 작업 객체의 속성 값으로 설정
      tag.textContent = task[field];
    }

     

    스타일이나 데이터 변경에 활용

    getAttribute 메소드를 활용해서 속성값을 가져오고, setAttribute 메소드를 활용해서 속성값을 설정해주는 원리

    <button class="btn" status="In Progress">Start</button>
    <button class="btn" status="Completed">Finish</button>
    // ...... 위 내용에 이어서
    const btns = document.querySelectorAll('.btn');
    for (let btn of btns) {
      const status = btn.getAttribute('status');
      btn.onclick = function () {
        fields[2].textContent = status;
        fields[2].setAttribute('status', status);
      };
    }

    [field] 속성을 가진 모든 요소를 선택하고, task 객체의 속성 값을 해당 요소에 할당한 후, .btn 클래스를 가진 버튼 요소들에 대해 클릭 이벤트를 처리하는 역할

     

    비표준 속성 사용 방식 : data-* 속성
    • data-로 시작하는 속성은 모두 dataset이라는 프로퍼티에 저장됨.

    • data-status라는 속성이 있다면, element.dataset.status라는 프로퍼티에 접근해서 그 값을 가져올 수 있음.

     

    위 예제코드에서 속성 이름 앞에 'data-'를 붙여주면 됨.

    <p>할 일 : <b data-field="title"></b></p>
    <p>담당자 : <b data-field="manager"></b></p>
    <p>상태 : <b data-field="status"></b></p>
    <button class="btn" data-status="대기중">대기중</button>
    <button class="btn" data-status="진행중">진행중</button>
    <button class="btn" data-status="완료">완료</button>

     

    CSS에서 대괄호를 사용하는 속성 선택자에서 속성 이름 앞에 모두 'data-'를 붙임.

    /* CSS */
    [data-status] {
      padding: 5px 10px;
    }

     

    자바스크립트 코드에서도 속성 이름에 'data-'를 붙임.

    const fields = document.querySelectorAll('[data-field]');
    for (let tag of fields) {
      const field = tag.dataset.field;
      tag.textContent = task[field];
    }
      const status = btn.dataset.status;
      btn.onclick = function () {
        fields[2].textContent = status;
        fields[2].dataset.status = status;
    728x90