ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 혼자 공부하는 자바스크립트 7장 - 문서 객체 모델
    자바스크립트/혼자 공부하는 자바스크립트 2021. 8. 8. 23:51

    문서 객체 모델

    DOM, Document Object Model: 문서 객체를 조합해서 만든 전체적인 형태

    HTML 요소를 자바스크립트에서는 문서 객체라고 부른다. 즉, 문서 객체를 조작한다는 말은 HTML 요소를 조작한다는 의미이다.

     

    DOMContentLoaded 이벤트

    문서 객체를 조작할 때는 DOMContentLoaded 이벤트를 사용한다. 이때, 오탈자를 입력해도 오류가 발생하지 않으므로 주의한다.

    document.addEventListner("DOMContentLoaded", () => {
    
    })

    HTML 문서에서, <head> > <script> > document.body 의 문장은 실행되지 않는다. body 태그에 앞서 body를 조작했기 때문이다. head 태그 안에서 body 태그에 접근 하려면 DOMContentLoaded 이벤트를 사용해 문서 객체를 모두 읽고 나서 실행되도록 해야한다.

    <head>
      <title>DOMContentLoaded</title>
      <script>
          document.addEventListner("DOMContentLoaded", () => {
          const h1 = (text) => `<h1>${text}</h1>`;
          document.body.innerHTML += h1("DOMContentLoaded 이벤트 발생");
        })
      </script>
    </head>

    웹 브라우저가 문서 객체를 모두 읽고 나면(즉, DOMContentLoaded 상태가 되면), 콜백함수를 호출해 문서 body에 DOMContentLoaded 이벤트 발생 이라는 내용의 h1 태그가 생성된다.

     

    문서 객체 가져오기

    document.body, document.head, document.title 등으로 HTML 요소를 불러올 수 있다. 이외의 다른 요소들은 별도의 메소드를 사용한다.

    document.querySelector(CSS 선택자)
    document.querySelectorAll(CSS 선택자)

    querySelector() 메소드는 요소를 하나만 추출하고, querySelectorAll() 메소드는 문서 객체를 여러 개 추출한다.

     

    글자 조작하기

    textContent는 입력된 문자열을 그대로 넣고, innerHTML은 입력된 문자열을 HTML 형식으로 넣는다.

    <head>
      <script>
          document.addEventListner("DOMContentLoaded", () => {
          const a = document.querySelector("#a");
          const b = document.querySelector("#b");
    
          a.textContent = `<h1>textContent 속성</h1>`
          b.innerHTML = `<h1>innerHTML 속성</h1>`
        })
      </script>
    </head>
    <body>
      <div id = a></div>
      <div id = b></div>
    </body>

    실행해보면 div#a의 경우에는 내용에 <h1>textContent 속성</h1>이 그대로, 태그까지 적혀있지만, div#b의 경우에는 innerHTML 속성이라는 내용이 h1 요소로 변환된 채로 적혀있는 것을 확인할 수 있다.

     

    속성 조작하기

    객체.setAttribute(속성, 값)은 특정 속성에 값을 지정하고, 객체.getAttribute(속성, 값)은 특정 속성을 추출한다.

     

    스타일 조작하기

    문서 객체의 스타일을 조작할 때는 style 속성을 사용한다. style 속성은 객체이며, 내부에는 CSS를 사용해 지정할 수 있는 스타일들이 있다. 이때, CSS에선 background-color와 같이 하이픈 기호가 쓰인 속성은 자바스크립트에선 backgroundColor와 같이 캐멀 케이스로 나타낸다.

    h1.style.backgroundColor = "red";        // 이 방식을 가장 많이 사용한다.
    he.style["backgroundColor"] = "red";
    h1.style["background-color"] = "red";
    const divs = document.querySelectorAll("body > div");
            // body 태그 아래의 div 태그 25개를 선택한다.
    
    divs.forEach( (div, index) =>{
      console.log(div, index);
      const val = index * 10;
      div.style.height = `10px`;
      div.style.backgroundColor = `rgb(${val}, ${val}, ${val})`;
    })

    divs 배열에 들어있는 25개 div 요소들의 인덱스에 10을 곱한 값을 rgb로 배경색으로 지정하는 코드이다. bodydiv 태그 25개를 생성하면 rgb(0, 0, 0)에서 rgb(250, 250, 250)까지의 div들을 볼 수 있다.

     

    문서 객체 생성하기

    문서 객체를 생성하고 싶을 때엔 document.createElement(문서 객체 이름)을 사용한다. 만든 뒤, 부모 객체에 추가하기 위해 부모 객체.appendChild(자식 객체) 메소드를 사용한다.

    이때, 문서 객체의 부모는 언제나 하나여야 하므로, 다른 문서 객체에 appendChild() 를 사용하면 해당 객체는 이동한다.

    제거할 때는 부모 객체.removeChild(자식 객체) 메소드를 사용한다.

     

    이벤트 설정하기

    모든 문서 객체는 생성, 클릭 등을 할 때 이벤트가 발생한다. 이벤트가 발생할 때 실행할 함수를 이벤트 리스너 또는 이벤트 핸들러라고 하고, 변수 또는 상수로 미리 선언한 뒤, 이를 연결과 제거할 때 사용한다.

    추가할 땐 addEventListner() 메소드, 제거할 땐 removeEventListener() 메소드를 사용한다.

    객체.addEventListner(이벤트 이름, 이벤트 리스너);
    객체.removeEventListener(이벤트 이름, 이벤트 리스너);

     

    이벤트 활용

    이벤트 모델

    이벤트를 연결하는 방법을 이벤트 모델이라고 하며, addEventListenter() 메소드는 현재 표준 이벤트 모델이다.

    과거에는 문서 객체가 갖고 있는 onXXX 속성에 함수를 할당해 이벤트를 연결했는데, 이를 고전 이벤트 모델이라고 한다.

    document.body.onkeyup = (event) => {
    
    }

    onXXX 속성을 HTML 요소에 직접 넣어서 이벤트를 연결하는 것을 인라인 이벤트 모델이라고 한다.

    const listner = (event) => {  }// HTML<body onkeyup="listener(event)">  </body>

    인라인 이벤트 모델은 고전 이벤트 모델처럼, onXXX 속성에 자바스크립트 코드를 넣는 것이다. 위의 코드에선 onkeyup 속성에서 listener() 함수를 호출하고 있다. 이때, listener 함수의 매개변수는 event이다.

    모든 이벤트 모델의 이벤트 리스너는 첫 번째 매개변수로 이벤트 객체를 받는다. 이 이벤트 객체에는 이벤트와 관련된 정보가 들어있다.

    2000년대 이전의 웹은 인라인 이벤트 모델을 주로 사용했다. 이후 2010년대 이전까진 자바스크립트의 활용이 늘어나며 고전 이벤트 모델을 많이 사용했다. 하지만 고전 이벤트 모델은 이벤트 리스너를 하나만 연결할 수 있다는 단점이 있으므로, 현재는 표준 이벤트 모델을 사용해 이벤트 리스너를 여러 개 연결하는 방식을 많이 사용한다.

    인라인 이벤트 모델을 사용되지 않은지 오래 되었지만, 최근 프론트엔드 프론트엔드 프레임워크들이 인라인 이벤트 모델을 활용하는 형태로 코드를 작성해서, 현재에는 인라인 이벤트 모델 역시 많이 사용한다.

     

    키보드 이벤트

    키가 눌릴 때 실행되는 keydown, 키가 입력되었을 때 실행되는 keypress, 키가 떨어질 때 실행되는 keyup 이벤트가 있다. keydown 이벤트와 keypress 이벤트는 웹 브라우저에 따라 한, 중, 일어 등의 아시아권 문자를 제대로 처리하지 못하는 문제가 있어 일반적으로 keyup 이벤트를 사용한다.

    키보드 이벤트를 실행할 때는 이벤트 객체로 어떤 키를 눌렀는지와 관련된 속성들이 따라온다.

    altKey, ctrlKey, shiftKey 속성은 해당 키를 눌렀는 지 불 자료형 값이 들어있고, code 속성은 입력한 키를 나타내는 문자열이 들어있다.

    트위터 메인 페이지에서 N을 누르면 새 트윗 작성, I를 누르면 새 쪽지 작성 등을 할 수 있는데, 이러한 단축키는 키보드 이벤트 속성을 사용하여 구현할 수 있다.

    IE나 구 버전의 엣지 브라우저는 code 속성을 지원하지 않으므로, 해당 웹 브라우저까지 지원하려면 입력한 키를 숫자로 나타내는 keyCode 속성을 사용해야 한다.

     

    이벤트 발생 객체

    코드의 규모가 커지면 이벤트 리스너를 외부로 분리하는 경우가 많아지는데, 이때 이벤트 리스너 내부에서 문서 객체 변수에 접근할 수 없는 경우가 있다. 이땐 event.currentTarget 속성을 사용하거나, this 키워드를 사용한다. 전엔 this 키워드를 사용하는 방식이 많이 쓰였지만, 화살표 함수 등장 이후 두 가지 방식 모두 많이 쓰인다.

    event.currentTarget

    const listener = (event) => {
      const length = event.currentTarget.value.length;
      h1.textContent = `글자 수: ${length}`;
    }
    
    document.addEventListener("DOMContentLoaded", () => {
      const textarea = document.querySelector("textarea");
      const h1 = document.querySelector("h1");
      textarea.addEventListener("keyup", listner);
    })

    만일 event.currentTarget 속성을 사용하지 않았다면 textarea 변수에 지정할 수 없어 오류가 났을 것이다.

    this

    const listener = (event) => {
      const length = this.value.length;
      h1.textContent = `글자 수: ${length}`;
    }
    
    document.addEventListener("DOMContentLoaded", () => {
      const textarea = document.querySelector("textarea");
      const h1 = document.querySelector("h1");
      textarea.addEventListener("keyup", listner);
    })

     

    글자 입력 양식 이벤트

    사용자로부터 입력을 받을 때 사용하는 요소를 입력 양식이라고 부른다. HTML의 input, textarea, button, select 태그 등이 모두 입력 양식이다.

    inch 단위를 cm로 바꾸는 프로그램:

    document.addEventListener("DOMContentLoaded", () => {
      const input = document.querySelector("input");
      const button = document.querySelector("button");
      const p = document.querySelector("p");
      
      button.addEventListener("click", () => {
        const inch = Number(input.value);
        
        if(isNaN(inch)) {
          p.textContent = `숫자를 입력해주세요`;
          return;
        }
        
        const cm = inch * 2.54;
        p.textarea = `${cm}cm`;
      })
    })

    버튼을 클릭할 때마다 입력받은 값을 isNaN() 메소드를 통해 숫자인지 검사하고, 숫자임이 확인되면 2.54를 곱해 출력한다.

    숫자가 아닌 경우 return 키워드를 리턴해 이후의 코드는 실행되지 않는다. 조기 리턴이라는 이름의 패턴으로, 자주 사용되는 패턴이다.

     

    const input = document.querySelector("input")
    const value = input.value;
    
    const isEmail = (value) => {
      return (value.indexOf("@") >= 1)		// @를 갖고 있고
      	&& (value.split("@")[1].indexOf(".") > 1)		// 골뱅이 뒤에 점이 있다면 true 리턴
    }
    
    isEmail(value);

    해당 방식으로 입력받은 값이 이메일의 형식인지 아닌지 알 수 있다. indexOf("@") >= 1를 통해 @을 갖고 있는지, indexOf(".") > 1를 통해 @ 뒤에 점이 있는지를 따져 true 혹은 false를 리턴한다.

    이 함수는 간단한 형태로, garudanish@k.를 입력해도 이메일 형식으로 인식한다. 일반적으로 이런 유효성 검사를 할 땐 정규표현식을 사용하면 더 쉽고 확실하게 구현할 수 있다.

     

    드롭다운 목록 활용하기

    드롭다운 목록은 기본적으로 select 태그로 구현한다.

    <select>
      <option>떡볶이</option>
      <option>순대</option>
      <option>오뎅</option>
      <option>튀김</option>
    </select>

    드롭다운 목록에서 항목을 선택하면 select 태그의 options.selectedIndex 속성이 선택한 항목의 인덱스로 바뀐다. 이를 활용하면 드롭다운 선택 항목에 따라 출력을 달리하는 코드를 짤 수 있다.

    const select = document.querySelector("select");
    
    select.addEventListener("change", (event) => {
      const options = event.currentTarget.options;
      const index = event.currentTarget.options.selectedIndex;
      
      p.innerText = `선택: ${options[index].textContent}`
    })

     

    select 태그에 multiple 속성을 부여하면 ctrl이나 shift 키로 여러 항목을 선택할 수 있다. 이를 multiple select 태그라고 한다.

    const select = document.querySelector("select");
    
    select.addEventListener("change", (event) => {
      const options = event.currentTarget.options;
      const list = [];
      
      for (const option of options) {
        if (option.selected) {
          list.push(option.textContent);
        }
      }
      
      p.textContent = `선택: ${list.join(",")}`;
    })

    options 속성에는 forEach() 메소드가 없으므로 반복문을 돌려 선택되었는지 여부를 확인한다. 선택되었다면 빈 배열에 추가하고 반복문이 완료되면 출력한다.

     

    체크 박스 활용하기

    HTML에서 input:checkbox로 생성한 체크 박스는 checked 속성을 가지므로 이를 활용한다.

     

    라디오 버튼 활용하기

    라디오 버튼은 input:radio로 생성한다.

    <input type="radio" name="pet" value="강아지">
    <span>강아지</span>
    <input type="radio" name="pet" value="고양이">
    <span>고양이</span>
    <input type="radio" name="pet" value="햄스터">
    <span>햄스터</span>
    <input type="radio" name="pet" value="기타">
    <span>기타</span>

    이때 항목에 name 속성을 입력하지 않으면 다중 선택이 가능하며, 선택 후 선택을 취소할 수 없으므로 name 속성을 반드시 사용하여야 한다.

    라디오 버튼은 체크박스와 마찬가지로 checked 속성을 가지므로 이를 활용하면 된다.

    const radios = document.querySelectorAll("[name=pet]")
    
    radios.forEach((radio) => {
      radio.addEventListener("change", (event) => {
        const current = event.currentTarget
        if (current.checked) {
          p.textContent = `좋아하는 애완동물은 ${current.value}군요!`
        }
      })
    })

     

    기본 이벤트 막기

    우클릭 시 컨텍스트 메뉴가 나타나는 것처럼 웹 브라우저가 기본적으로 처리해주는 이벤트를 기본 이벤트라고 부른다. 기본 이벤트에는 그 외에도 링크 클릭 시 이동, 제출 버튼 클릭 시 이동 등이 있다. 이런 기본 이벤트를 제거할 때는 event.preventDefault() 메소드를 사용한다.

    이미지 우클릭 시 컨텍스트 메뉴가 뜨는 기본 이벤트를 방지하는 코드:

    const img = document.querySelector("img");
    
    img.addEventListener("contextmenu", (event) => {
      event.preventDefault();
    })

    댓글

Designed by Tistory.