[JS/Node] DOM - 이벤트

LEE JI YOUNG·2021년 9월 26일
0

JS/Node

목록 보기
9/23
  • HTML을 바라보는 또 다른 관점, DOM(Document Object Model).
  • DOM : 프로그래머 관점에서 바라 본 HTML.
    • 브라우저 환경에서 자바스크립트를 이용해 HTML을 조작 가능.
    • DOM을 이해, 조작 => HTML을 단순한 문서에서 웹 앱으로 업그레이드 가능.
    • HTML 문서에 작성되어 있는 엘리먼트에 접근, 새로운 엘리먼트를 생성, 삭제 가능.
    • HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model
    • DOM을 위해 웹 개발자들이 모여, HTML을 철저히 분석하여 HTML의 아주 작은 부분까지 접근할 수 있는 구조(Model; Structure)를 만듦. 이렇게 만들어진 구조를 이용하여 HTML로 구성된 웹 페이지를 동적으로 움직이게 만듦.
    • 자바스크립트는 다양한 일을 할 수 있지만, 웹 페이지를 제어하기 위한 목적으로 오랜 기간 사용함. DOM은 홈페이지를 조금 더 다이나믹하게 만듦.
    • HTMl 문서의 구조와 관계를 객체(Object)로 표현한 모델
    • 트리 구조 : 트리 구조의 가장 큰 특징은 부모가 자식을 여러 개 가지고, 부모가 하나인 구조가 반복되는 점. HTML, JavaScript객체 둘 다 트리 구조. HTML 구조가 Javascript의 객체 구조와 같은 트리구조라서, 자바스크립트의 DOM이 브라우저에 접근하기 가장 바람직함.
    • document라는 전역변수로 접근이 가능. DOM은 document 객체를 통해 HTML(root document)에 접근. (참고 - BOM(Browser Object Model)이 window 객체를 통해 브라우져에 접근)
    • DOM이 자바스크립트가 아니다. DOM 구조접근을 자바스크립를 이용해서 하는 것임. 다른 언어도 DOM을 가지고 있지만, 자바스크립트의 DOM이 전통적으로 오래 쓰여왔고 안정적임.
  • innerHTML vs innerText vs textContent - 1
  • innerHTML vs innerText vs textContent - 2



DOM 이해하기


HTML에 JavaScript 적용하기

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <div id="msg">Hello JavaScript!</div>
    <!-- script 요소 삽입 위치 -->
    <script src="myScriptFile.js"></script>
  </body>
</html>

console.dir

: 엘리먼트를 객체의 형태로 볼 수 있는 방법

  • console.dir 은 console.log 와 달리 DOM을 객체의 모습으로 출력

자식 엘리먼트 찾기

  • console.dir(document.body) 출력하여 children 찾으면 자식 요소 확인 가능
  • console.dir(document.body.children[1]) : 1번째 자식요소 확인 가능

부모 엘리먼트 찾기

  • <div id="news-contents">의 부모 엘리먼트 찾기
    • Node.parentElement : 부모 엘리먼트를 가리키는 속성.
    • getElementById를 이용해서 부모 엘리먼트 찾기.
let newsC = document.getElementById('news-contents') 
//newsC라는 변수에 자식요소를 담아주고
let parent = newsC.parentNode;  
// newsC의 부모 엘리먼트를 찾는다. 이렇게 되면 부모엘리먼트를 가르킬 수 있다.
// let parent = newsC.parentElement; 같은의미다.
console.dir(parent)




DOM으로 HTML 조작하기

  • CRUD(Create, Read, Update and Delete) : 만들고(CREATE), 조회하고(READ), 갱신하고(UPDATE), 삭제하는(DELETE) 하는 방법
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Document</title>
  </head>
  <body>
    <div id="container">
      <h2>Tweet List</h2>
      <div class="tweet">hello</div>
      <div class="tweet">world</div>
      <div class="tweet">code</div>
      <div class="tweet">states</div>
    </div>
  </body>
  <script src="script.js"></script>
</html>

CREATE - createElement

  • document.createElement('div') : div 엘리먼트 만들기
  • const tweetDiv = document.createElement('div') : 만든 엘리먼트를 변수에 담아 활용하기
  • document.innerHTML = '<div></div>'

APPEND - append, appendChild

  • document.body.append(tweetDiv) : append 라는 메소드를 사용해서, 변수 tweetDiv 를 body 자식 맨 끝에 넣기
  • document.body.prepend(tweetDiv) : append 라는 메소드를 사용해서, 변수 tweetDiv 를 body 자식 맨 앞에 넣기

READ - querySelector, querySelectorAll

  • 셀렉터: HTML 태그("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용
  • const oneTweet = document.querySelector('.tweet') : 클래스 이름이 tweet 인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회하기
    -const tweets = document.querySelectorAll('.tweet') : 클래스 이름이 tweet 인 HTML 여러 개의 엘리먼트를 한 번에 가져오기
    • .querySelectorAll 로 조회한 HTML 엘리먼트들은 배열처럼 for문을 사용가능.
    • 주의~~! 앞서 조회한 HTML 엘리먼트들은 배열 X !! 유사 배열( 배열형 객체 등 다양한 이름으로 부름, 정식 명칭은 Array-like Object )
  • const getOneTweet = document.getElementById('container') : get으로 시작하는 DOM 조회 메소드는 옛날 방식. 만약 이전 버전의 브라우저(인터넷 익스플로러) 호환성을 신경 써야 한다면, 이런 옛날 방식을 사용해야함.
    • document.getElementsByTagName('div') : 태그가 div인 것 전부 조회.
    • document.getElementById('div') : id가 div 인 element 하나를 조회합니다.
    • document.getElementsByClassName('div') : class가 div 인 element 여러 개를 조회.
const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true

CREATE, READ, APPEND - 만들어서 조회한 곳에 붙이기

const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)

UPDATE - textContent, classList.add

  • .textContent = '컨텐츠 내용' : 문자열 입력
console.log(oneDiv) // <div></div>
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>
  • .classList.add('클래스이름') : tweet 클래스 추가
oneDiv.classList.add('tweet')
console.log(oneDiv) // <div class="tweet">dev</div>
  • .classList.remove('클래스이름') : tweet 클래스 제거
oneDiv.classList.remove('tweet')
console.log(oneDiv) // <div>dev</div>
  • .append(붙이려는 변수) : append를 이용해 container의 자식 요소로 추가
const container = document.querySelector('#container')
container.append(oneDiv)

  • 아이디가 "javascript"이고, 내용이 "awesome"인 a 태그를 생성
let aElement = document.createElement('a')
aElement.setAttribute('id', 'javascript')
aElement.textContent = 'awesome'
let aElement = document.createElement('a')
aElement.id = 'javascript'
aElement.innerHTML = 'awesome' //  innerHTML 사용은 꼭 필요하지 않으면 지양.  
///HTML tag를 직접 삽입하여 실행하는 형태의 메소드는 늘 이런 위험을 가짐. 
//<script> tag를 활용하여 강제로 해커가 원하는 스크립트를 실행시키는 XSS Attack이 대표적.

DELETE - remove, removeChild

  • 지우고싶은변수.remove() : 엘리먼트 지정 삭제
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // 이렇게 append 했던 엘리먼트를 삭제할 수 있다.
const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
    tweet.remove();
})
// or
for (let tweet of tweets){
    tweet.remove()
}
// 클래스 이름이 tweet인 엘리먼트만 찾아서 제거합니다.
  • 여러 개의 자식 엘리먼트를 지우기. innerHTML 을 이용하는 방법은 분명 간편하고 편리한 방식이지만, 보안에서 몇 가지 문제를 가지고 있음. ===> removeChild : 자식 엘리먼트를 지정해서 삭제하는 메소드 사용하기. 모든 자식 엘리먼트를 삭제하기 위해, 반복문(while, for, etc.)을 활용
  • innerHTML : 모든 자식 엘리먼트를 지우기 (보안 문제, 권장X)
document.querySelector('#container').innerHTML = '';
// id가 container인 엘리먼트 아래의 모든 엘리먼트를 지웁니다.
  • removeChild : 자식 엘리먼트를 지정해서 삭제
const container = document.querySelector('#container');
while (container.firstChild) {
  container.removeChild(container.firstChild);
}
//container의 첫 번째 자식 엘리먼트가 존재하면, 첫 번째 자식 엘리먼트를 제거합니다.
const container = document.querySelector('#container');
while (container.children.length > 1) {
  container.removeChild(container.lastChild);
}
// container의 자식 엘리먼트가 1개만 남을 때까지, 마지막 자식 엘리먼트를 제거합니다.
  • Quiz - DOM 7번 ) document.querySelector("#world").remove(aElement) : world 엘리먼트 전부 지움




Sprint - 유효성 검사

  • 유효성 검사(Form validation) : 조건에 맞게 반드시 형식을 맞추도록 하는 것
  • 유효성 검사의 목표(예. 회원 가입)의 핵심 기능에 대해, 작동이 가능한 MVP(Minimum Viable Product)를 만들어 내는 것

    유효성 검사 퀴즈 (1)

    • DOM으로 <input type="text"> 또는 <textarea>와 같은 엘리먼트의 입력 값을 설정하거나, 또는 얻어내고 싶을 때
      • 해당 엘리먼트를 querySelector 등을 이용해 가져온 후 value라는 속성으로 접근하기.
        ex)
        <input type="text" id="username">의 값을 가져오려면...
        console.log(document.querySelector('#username').value); 으로 접근.
        값을 설정하려면...
        document.querySelector('#username').value = '새로운 값';

    • 해당 엘리먼트가 논리적으로 존재하나, 화면상에 모든 영역이 표시되지 않게 만들기
      • display: none : 실제로 DOM 상에서는 엘리먼트가 존재하나, 브라우저에서 표시할 때는, 마치 해당 엘리먼트가 레이아웃 상에서 없는 것처럼 취급
      • visibility: hidden : display: none 처럼 보이지는 않으나, 엘리먼트가 차지하는 영역은 그대로 남김.

    • 자바스크립트를 이용해 다음과 같이 스타일을 직접 조작가능하나 CSS 클래스를 이용해서 간접적으로 바꾸는 것을 권장 - '관심사 분리' !!
      • 디자인의 디테일한 요소가 자바스크립트 코드에 담기는 것을 방지하기 위해
      • 따로 클래스를 이용하면, 해당 디자인을 디자이너가 쉽게 바꿀 수 있기 때문에
      • CSS는 디자인, 자바스크립트는 로직에 집중할 수 있게 하기 위해
    //  CSS 클래스를 이용해서 간접적으로 바꾸는 것
    /* style.css */
    .invalid { 
      border: 2px solid red;
      color: red;
    }
    /* script.js */
    inputBox.classList.add('invalid');
    
    //  js로 직접 조작하는 방법 (권장 X)
    /* script.js */
    inputBox.style.border = '2px solid red';
    inputBox.style.color = 'red'; 
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>유효성 검사</title>
  <link rel="stylesheet" href="style.css">
  <script src="validator.js"></script>
</head>

<body>
  
  <h1>회원가입</h1>
  
  <fieldset>
    <label>아이디</label>
    <input type="text" id="username">
    <div class ="failure-message hide">아이디는 네 글자 이상이어야 합니다.</div>
    <div class ="success-message hide">사용할 수 있는 아이디입니다.</div>
  </fieldset>

  <fieldset>
    <label>비밀번호</label>
    <input type = "password" id="password">
  </fieldset>

  <fieldset>
    <label>비밀번호 확인</label>
    <input type = "password" id="password-retype">
    <div class ="mismatch-message hide">비밀번호가 일치하지 않습니다.</div>
  <fieldset>
    <button>회원가입</button>
  </fieldset>


  <!-- 동영상 강의에 나온 코드를 그대로 실습하세요 -->

  <script src="script.js"></script>
</body>

</html>
// 동영상 강의에 나온 코드를 그대로 실습하세요
// TODO : DOM으로부터 필요한 엘리먼트를 불러오세요.
let elInputUsername = document.querySelector('#username');
console.log(elInputUsername)

let elInputPassword = document.querySelector('#password');
let elInputPasswordRetype= document.querySelector('#password-retype');

let elFailureMessage = document.querySelector('.failure-message');
let elSuccessMessage = document.querySelector('.success-message');

let elMismatchMessage = document.querySelector('.mismatch-message');



elInputUsername.onkeyup = function(){
  if(isMoreThan4Length(elInputUsername.value)){
    elFailureMessage.classList.add('hide');
    elSuccessMessage.classList.remove('hide');
    

  } else {
    elFailureMessage.classList.remove('hide');
    elSuccessMessage.classList.add('hide');


  }
}


elInputPasswordRetype.onkeyup = function(){
  if(isMatch(elInputPassword.value, elInputPasswordRetype.value)){
    elMismatchMessage.classList.add('hide');
    

  } else {
    elMismatchMessage.classList.remove('hide');

  }
}


function isMoreThan4Length(value) {
  return value.length >=4
  // TODO : 동영상 강의를 보고 이 함수를 완성하세요.
}

function isMatch (password1, password2) {
  return password1 === password2
  // TODO : 동영상 강의를 보고 이 함수를 완성하세요.
}




이벤트 객체

  • DOM에서 이벤트 : 마우스를 클릭하거나, 키보드를 누름, 브라우저 창 크기를 조절하거나, 스크롤 등의 사용자 액션에 의해 발생
  • 이벤트 핸들러 : 이벤트가 발생할 때 실행되는 함수를 말함.
  • 이벤트와 관련된 속성은 on이라는 접두어가 붙는다. (onclick, onkeyup 등)
  • 이벤트란? 이벤트(event)는 어떤 사건을 의미. 브라우저에서의 사건이란 사용자가 클릭을 했을 '때', 스크롤을 했을 '때', 필드의 내용을 바꾸었을 '때'와 같은 것을 의미.
    • event target
      target은 이벤트가 일어날 객체를 의미한다. 예를 들어 버튼을 누르면 새로운 창이 열리는 객체가 있다고 하자. 그렇다면 여기서 버튼은 event target이 된다.
    • event type
      이벤트의 종류를 의미한다. 위의 예에서는 click이 이벤트의 타입이 된다. 그 외에도 스크롤이나 마우스가 움직였을 때 발생하는 것들도 이벤트 타입이다.
    • event handler
      이벤트가 발생했을 때 동작하는 코드를 의미한다.

  • 화면에 아메리카노와 카페라떼를 선택하도록 하는 두 개의 버튼이 있습니다. 이 두 개의 버튼을 클릭할 때, 각각 아메리카노를 클릭하셨습니다. 또는 카페라떼를 클릭하셨습니다. 라고 출력하는 단순한 프로그램을 작성하시오.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>이벤트 객체</title>
  </head>
  <body>
    <button>아메리카노</button>
    <button>카페라떼</button>
    <script>
      let menus = document.querySelectorAll("button"); //모든 버튼을 가져옵니다.

      let btnAmericano = menus[0];
      let btnCaffelatte = menus[1];
      function handleClick(event) {
        // // 아래의 빈 칸(____)을 채우세요.
        // console.log(event);
        let currentMenu = event.target.textContent; // TODO
        console.log(currentMenu + "를 클릭하셨습니다.");
      }
      btnAmericano.onclick = handleClick;
      btnCaffelatte.onclick = handleClick; 
      // 이상으로 for 문으로 충분히 구현할 수 있는 내용입니다.
    </script>
  </body>
</html>

event.target : 현재 이벤트 된 element 불러오기.

  • 어떤 버튼(btn)을 클릭할 때 콘솔에 "버튼이 눌렸습니다!"가 출력되게 만드는 방법 3가지
btn.onclick = function() {
  console.log('버튼이 눌렸습니다!');
}
btn.addEventListener('click', function() {
  console.log('버튼이 눌렸습니다!');
});
function handler() {
  console.log('버튼이 눌렸습니다!');
}
btn.onclick = handler;
  • 어떤 이벤트 발생 시 작동하는 함수를 할당하는 방법 2가지

1) DOM 객체에 onclick을 직접 지정

function displayAlert() {
  alert('코드스테이츠에 오신 것을 환영합니다')
}
document.querySelector('#apply').onclick = displayAlert

2) DOM 객체에 addEventListener라는 메소드를 사용해서 할당

document.querySelector('#apply').addEventListener('click', function(){
   alert("코드스테이츠에 오신 것을 환영합니다")
})





  • addEventListener 쓰는 이유 ; 통일성, 범용성

onclick에는 하나의 콜백만 지정가능.

addEventListener를 사용하면 여러 개의 이벤트 리스너를 추가할 수 있다.

  • DOM :

element를 동적으로 다룰 수 있다

html을 다루기위한 프로그래밍언어의 객체..

javascript를 이용해서 엘리먼트의 속성값을 얻고 변경하는 방법

Document Object Module

(면접용) : HTML을 조작할 수 있도록 마련된 객체 형태의 구조나 모델 이며 JS로 접근 가능하다.

브라우저마다 기능이 다르게 구현되어 있기도 하다. DOM이 없다면 직접 접근해서 수정해야해서

프로젝트의 크기가 큰 경우 일일히 접근하기 비효율적이게 된다.

  • 퀴즈 9) 이벤트를 함수를 만들어서 걸어주는 방법 & 함수를 바로 걸어주는 방법 (문제7)
  • 파싱 parsing : 컴퓨터에서 컴파일러 또는 번역기 원시 부호를 기계어로 번역하는 과정의 한단계로 각 문장의 문법적인 구성 또는 구문을 분석하는 과정.
  • innerHTML : 텍스트 컨텐츠와 다르게 스트링을 일일히 파싱해서 넣어주어 보안에 문제가 우려된다.

  • textContent : 스트링만 넣어주는 것이기 때문에 보안에 위험은 없다.

  • 문제 9) 유효성 검사 코드를 말로 해보기 !
  • 문제 10) 함수로 쪼개는 것이 좋은 이유 : 다른 곳에서도 재사용이 가능하고 코드간의 일관성이 좋아서.
  • 리액트에서도 이벤트함수 쓴다! 열공하길

*function(event) - > function() 로 넣기보다는 event, e(약어)매개변수를 넣어줘야 세밀하게 진행된다.

??? 더 알아보기 handleClick() 부분 - 아메리카노 누르는 부분

*inputtype : 여러가지 알아보기 tel. date.

profile
프론트엔드 개발자

0개의 댓글