S1. DOM/유효성검사/이벤트객체

Haizel·2022년 11월 16일
0

Front-End Developer 되기

목록 보기
16/70
post-thumbnail

노션으로 보기

DOM이란?


  • Document Object Model의 약자 → HTML의 요소를 Object처럼 조작할 수 있는 Model을 말한다,
  • JS와 DOM을 이용해 HTML에 접근 및 조작 → HTML로 구성된 웹페이지를 동적으로 움직일 수 있다.

HTML에 JavaScript 삽입 위치의 차이


  • HTML에 JavaScript 적용
<script src="myScriptFile.js"></script>

**<script>** 요소는 등장과 함께 실행된다.

<head> 태그에 위치

  • HTML 페이지 파싱 우선 진행 → JS파일을 찾고 → 실행
  • 브라우저 렌더링에 방해가 되어 무거운 스크립트가 실행되는 경우 → 화면 로딩이 오래 걸린다.
  • 문서를 초기화, 설정하는 가벼운 스크립트들이 주로 사용된다.
  • 문서의 DOM 구조가 필요한 스크립트는 ⇒ **document.onload** 와 같은 로드 이벤트가 추가되야 에러없이 작동한다.

<body> 태그가 끝나기전 하단에 위치

  • DOM을 먼저 생성할 수 있도록 <body> 하단에 스크립트 태그를 넣어주는 경우로 → DOM구조가 완료된 시점에 실행되어 별다른 추가 설정이 필요없다.
  • HTML 파싱이 다 끝난 후 → Js스크립트 실행함으로 페이지 로딩시간이 단축된다.

**async 속성 사용**

  • <head><script>async 속성과 함께 사용한다.
<script async src="scripy.js></script>
  • 파싱과 JS 불러오기를 병렬로 진행 → 다운받는 시간이 절약된다.

  • 주의점 : **async** 속성은 script 태그 선언 순서와 상관없이 다운 받아지는 순서대로 js파일을 실행한다.

    → 따라서 순서에 의존적인 페이지라면 문제가 될 수 있음으로 주의

defer 속성 사용

  • <head><script>defer 속성과 함께 사용한다.
<script defer src="scripy.js></script>
  • 파싱과 JS 불러오기를 병렬로 진행 → 다운받는 시간이 절약된다.
  • **async 속성과 달리 JS파일을 다운받고 파싱이 끝난후 순서대로 JS 파일을 실행** → 원하는 방향대로 스크립트를 실행할 수 있다,

참고 자료

DOM 구조를 조회


  • 아래 HTML에서 body의 자식 요소인 nav, news-contents, footer 를 조회하고 싶다면?
<html>
  <body>
    **<div id="nav">**
      <div class="logo"></div>
      <div class="menu-wrapper">
        <div class="menu">menu</div>
        <div class="menu">menu</div>
        <div class="menu">menu</div>
        <div class="profile-photo">photo</div>
      </div>
    </div>
    **<div id="news-contents">**
      <div class="news-content-wrapper">
        <div class="news-picture">news-picture</div>
        <div class="news-title">news-title</div>
        <div class="news-description">news-description</div>
      </div>
    </div>
    **<div id="footer">footer</div>**
  </body>
</html>
  • JS에서 DOM은 <document> 객체에 구현되어 있다.
    → 브라우저에서 작동되는 JS 코드에서는 어디서나 <document> 객체를 조회할 수 있다.

Console.dir

  • DOM 구조를 조회할 때 사용 → DOM을 객체의 모습으로 출력
//1. body안의 모든 요소를 찾고 싶다면
console.dir(document.boby)

//2. body안의 자식요소를 찾고 싶다면
console.dir(document.body.children)

//3. body안의 첫번째 자식요소를 찾고 싶다면
console.dir(document.body.children[1])

//4. 변수 선언
console.dir(document.body.children[1])
div#news-contents

let newCon = document.body.children[1];
newCon; // <div id = "news=contents"> ...

DOM 요소 검색 키워드

  • children : 자식 요소
  • firstElementChild , lastElementChild : 첫 번째 및 마지막 자식 요소
  • previousElementSibling , nextElementSibling : 형제 요소(태그만)
  • parentElement : 상위 부모 요소(태그만)
  • parentNode : 부모 요소(노드 전체)

Node(노드) 와 element(요소) 차이점

DOM의 CRUD(Create, Read, Update and Delete)


CREATE

새로운 <div>요소 만들기

document.createElement('div')   //<div></div>

div element에 변수 tweetDiv 할당하기

const tweetDiv = document.createElement('div')  //undefined
  • 현재 tweetDiv 는 body와 연결되어있지 않다(공중부양 상태)

append 메소드로 변수tweetDiv<body>에 넣기

document.body.append(tweetDiv) //undefined
  • 현재 <body> 안에 textcontext 없이 있는 상태 → 화면엔 보이지 않는다.

READ

💡 **조회하는 방법**
  • 원시자료형 : 변수의 이름으로 직접 조회
  • 참조자료형 : 배열은 index, 객체는 key를 이용해 값을 조회
  • DOM으로 HTML 엘리먼트 정보 조회 : querySelector의 첫번째 인자로 selector을 전달해 조회
    • 셀렉터론 HTML요소(’div’), id(’#tweetList), class(.tweet)가 가장 많이 사용된다.
    • query란 질문하다, 조회하다라는 의미

querySelector로 하나의 엘리먼트 조회

  • querySelector'.tweet' 을 첫 번째 인자로 넣으면, 클래스 이름이 tweet인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회
//querySelector로 클래스 이름이 tweet인 HTML 요소를 조회
const oneTweet = document.querySelector('.tweet')

querySelector로 특정 조건의 모든 엘리먼트 조회

//querySelectorAll로 클래스 이름이 tweet 인 모든 HTML 요소를 유사 배열로 받아온다.
const tweets = document.querySelectorAll('.tweet')

유사배열(Array-like Object)란?
querySelectorAll
로 조회한 HTML 요소들은 배열처럼 for문을 사용할 수 있다.
하지만 진짜 배열은 아니기에 이런 ‘배열아닌 배열’을 → 유사배열, 배열형 객체 등으로 부른다.

➕ querySelector === getElementById

//'getElementById'는 DOM의 옛날 방식의 조회 메서드
// =querySelector와 비슷한 역할을 하는 오래된 방식(이전 버전의 호환성을 신경써야 할때 사용)

const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true

특정 id<div> 요소 넣어주기

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

//id(#container)의 맨 마지막 자식 요소로 tweetDiv를 추가
container.append(tweetDiv)

엘리먼트의 입력 값을 설정하거나 얻어내고 싶으면? → value 속성 사용

  • 해당 엘리먼트를 querySelector 등을 이용해 가져온 후 value라는 속성으로 접근
//<input type="text" id="username">의 값을 가져오려면, 다음과 같이 접근
console.log(document.querySelector('#username').value);
  • 값을 설정하고 싶다면
document.querySelector('#username').value = '새로운 값

UPDATE

oneDiv라는 이름의 <div>요소 만들기

const oneDiv = document.createElement('div'); // <div></div>

textContentdiv엘리먼트에 문자열 입력하기

oneDiv.textContent = 'dev'; //<div>dev</div>

div 엘리먼트에 class를 추가 (기존 CSS 스타일링 동일 적용된다)

oneDiv.classList.add('tweet') //<div class="tweet">dev</div>

append를 이용해 id(#container)의 자식요소로 추가

const container = document.querySelector('#container')
container.append(oneDiv)

class와 id 말고 다른 attribute를 추가하려면? setAttribute

aElement**.setAttribute('id', 'javascript')**

DELETE

삭제하려는 요소의 위치를 알고 있는 경우 → remove메서드

//id가 container인 요소 아래에 tweetDiv를 추가하고, remove로 삭제하는 코드
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)

tweetDiv.remove() // append 했던 요소를 삭제할 수 있다.

여러 개의 자식 요소를 지우려면? → innerHTML 메서드

//id가 container인 요소 아래의 모든 요소를 지운다.
document.querySelector('#container').innerHTML = '';
  • innerHTML 메서드는 간편하지만 여러 보안상의 문제를 가진다. 따라서 대신할 아래 메서드들의 활용을 추천한다.

자식 요소를 지정해 삭제하려면? → removeChild메서드

  • 반복문(while, for, etc.)과 같이 활용할 수 있다.

예제1 : 자식 요소가 남지않을 때까지 첫번째 자식 요소를 삭제한다.

🚫  removeChildwhile을 이용해 자식 요소를 삭제하면 → 제목에 해당하는 H2 "Tweet List"까지 삭제된다.

//container의 첫 번째 자식 요소가 존재하면, 첫 번째 자식 요소를 제거한다.

const container = document.querySelector('#container');
while (container.firstChild) {
  container.removeChild(container.firstChild);
}
  • 이를 방지하기 위한 방법

방법1 : container의 자식 요소가 1개만 남을 때까지, 마지막 자식 요소를 제거

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

//1보다 작을 때는 멈추기 -> 1보다 작다는 것은 containe안에 자식요소가 없단 뜻이니까!
while (container.children.length > 1) {
  container.removeChild(container.lastChild);
}

방법2 : 클래스이름이 ‘tweet’인 요소만 찾아 제거하기.

//1)
const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
    tweet.remove();
})

//2)

그 밖의 방법 :

  • 새로운 변수를 생성해 제목에 해당하는 H2 "Tweet List”를 할당하고 → 반복문이 끝나면 새롭게 추가
  • 자식 요소를 하나만 남기기

CSS 속성

엘리먼트가 존재하지만, 화면 상 모든 영역에 표시되지 않게 하고싶다면 ?


//CSS에 다음과 같이 설정
//나타내고 싶다면 'block'

.hide {
  display: none;
}

관심사 분리란 ?


: 자바스크립트를 이용해 스타일을 직접 조작하지 않고 → CSS 클래스를 이용해 간접적으로 바꾸는 것(그리고 이를 권장한다.)

  • 이유는?
  1. 디자인의 디테일한 요소가 자바스크립트 코드에 담기는 것을 방지하기 위해
  2. 따로 클래스를 이용하면, 해당 디자인을 디자이너가 쉽게 바꿀 수 있기 때문에
  3. CSS는 디자인, 자바스크립트는 로직에 집중할 수 있게 하기 위해

심화학습

유효성 검사


  • 사이트에서 원하는 조건/형식에 맞게 입력했는지 검사하는 것

유효성 검사 과제


  1. 아이디는 4글자 이상일 때
//1) 아이디 입력창(elInputUsername)에 글자를 키보드로 입력할 때
let elInputUsername = document.querySelector('#username') //-> 아이디 입력창

//2) 글자수가 4개 이상이면,
function isMoreThan4Length(value) {
  return value.length >= 4
}

//3) '사용할 수 있는 아이디입니다' 라는 메세지가 출력된다.

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

elInputUsername.onkeyup =function() {
  if(isMoreThan4Length(elInputUsername.value)) {
  //성공 메세지가 보여지고
  elSuccessMessage.classList.remove('hide')
  //실패 메세지가 가려져야함
  elFailureMessage.classList.add('hide')
  } else { 
   //성공 메세지가 가려지고
  elSuccessMessage.classList.add('hide')
  //실패 메세지가 보여져야함
  elFailureMessage.classList.remove('hide')
  }
}
  1. 비밀번호랑 비밀번호 확인이랑 일치한다면
let elInputPassword = document.querySelector('#password')
let elInputRetypePassword = document.querySelector('#password-retype')
let elMissmatchMessage = document.querySelector('.mismatch-message');

//1)비밀번호의 value와 비밀번호 확인의 value가 일치하다면,
function isMatch(password1, password2){
  return password1 == password2;
}

//2.비밀번호 확인 창에 입력했을 때,
elInputRetypePassword.onkeyup= function() {
  if(isMatch(elInputPassword.value, elInputRetypePassword.value)){
    //실패 메세지 가려진다.
    elMissmatchMessage.classList.add('hide');
    } else {
    //틀리면 실패 메세지가 보인다
    elMissmatchMessage.classList.remove('hide');
    }
  }

//! 내가 놓쳤던 것! //
// -> 비밀번호, 비밀번호 확인의 값을 비교하는게 아니라 -> 비밀번호의 value와 비밀번호 확인의 value를 비교해야한다.
//즉 value를 빼먹음! -> 명심하자 ~!
  1. 추가할 수 있는 항목들
  • 정규식표현 이용해서 유효성 검사하기
  • 아이디는 영어와 숫자만 가능
  • 비밀번호는 최소 8자 이상, 알파벳과 숫자 그리고 특수문자 하나 이상 포함해야 한다. 등

이벤트 객체


이벤트 : DOM에서 마우스를 클릭하거나, 키보드를 누르는 등의 사용자 액션에 의해 발생한다.

  • 브라우저 창 크기를 조절하거나, 스크롤 하는것도 DOM 이벤트의 일종이다.
  • 이벤트와 관련된 속성은 **on**이라는 접두어가 붙는다(onclick, onkeyup 등)

이벤트 핸들러 : 이벤트가 발생할 때 실행되는 함수

Q. 화면에 아메리카노와 카페라떼를 선택하는 두개의 버튼이 있고,

두 개의 버튼을 클릭할 때, 각각 아메리카노를 클릭하셨습니다.또는 카페라떼를 클릭하셨습니다라고 출력


let menus = document.querySelectorAll("button"); //모든 버튼을 가져온다.
//<button>아메리카노</button>
//<button>카페라떼</button>

let btnAmericano = menus[0];
let btnCaffelatte = menus[1];
//menus = [btnAmericano, btnCaffelatte] //각각 [0], [1]

btnAmericano.onclick = handleClick;
btnCaffelatte.onclick = handleClick; // for 문으로도 충분히 구현할 수 있는 내용임.

function handleClick() {
  let currentMenu = document.querySelector('menus')
  console.log(currentMenu + "를 클릭하셨습니다.");
}

Q. 질문

  • event 객체에는 어떤 내용이 출력되는가?
  • event.target은 어떤 값을 담고 있는가?
  • '아메리카노', '카페라떼'라는 문자열은 어디에 담겨는가?

종합퀴즈


Q. 어떤 버튼(btn)이 존재하고, 버튼을 클릭할 때 콘솔에 "버튼이 눌렸습니다!"를 출력하고 싶다면?

//1) 오답 : onClick -> onclick
btn.onClick = function() {
  console.log('버튼이 눌렸습니다!');
} 

//2) 정답
btn.onclick = function() {
  console.log('버튼이 눌렸습니다!');
}

//3) 정답
btn.addEventListener('click', function() {
  console.log('버튼이 눌렸습니다!');
});

//4)정답
function handler() {
  console.log('버튼이 눌렸습니다!');
}
btn.onclick = handler;

//5) 오답 : 이벤트 속성(onclick(을 이벤트 핸들러에 등록할 땐 -> 
       //  함수의 실행을 등록(x) -> 함수 그 자체로 등록해야 한다.
function handler() {
  console.log('버튼이 눌렸습니다!');
}

btn.onclick = handler(); //handler로 수정(함수 그 자체로 등록)

메소드

insertAfter() 메서드 : 선택한 요소 뒤에 HTML 요소를 삽입한다.

insertBefore() 메소드 : 선택한 요소 앞에 HTML 요소를 삽입한다.

원하는 노드.cloneNode() : 노드 복제를 복제하는 메소드

  • 자식노드까지 복사하려면 원하는 노드.cloneNode(true);

**.appendChild(aElement)** :

**.prependChild(aElement)** :

**document.importNode** : template 을 활용하여 내용을 붙여 넣을 때 사용하는 메서드

조회

**document.querySelector('div')** : 최상단 <div> 요소 하나만 조회

**document.getElementById('div')** : id가 <div> 요소 하나를 조회

**document.getElementsByClassName('div') :** class가 <div> 요소 여러개를 조회

document.querySelectorAll('div') , document.getElementsByTagName('div') : <div> 요소 모두 조회 삭제

엘리먼트 삭제

document.querySelector("#world").remove()
, document.querySelector("#world").remove(aElement)

Q. 아이디가 "javascript"이고, 내용이 "awesome"인 <a>요소를 생성하는 방법 2가지

//1.
let aElement = document.createElement('a')
aElement.setAttribute('id', 'javascript')
aElement.textContent = 'awesome'

//2. 하지만 innerHTML 사용은 왠만하면 지양된다.
let aElement = document.createElement('a')
aElement.id = 'javascript'
aElement.innerHTML = 'awesome'
profile
한입 크기로 베어먹는 개발지식 🍰

0개의 댓글