25.04.02 (수) 37일차 JS

허배령·2025년 4월 2일

괴발개발 TIL

목록 보기
47/54

DOM (Document Object Model)

  • HTML(웹문서, 웹페이지) 문서를 객체 기반으로 표현한 것.
    -> HTML 문서에 작성된 내용을 트리구조(계층형으로 표현)로 나타냈을 때
    각각의 태그, TEXT, COMMENT 등을 Node라고 한다.
        document : {
          DOCTYPE : html,
          HTML : {
              HEAD : {
                TITLE : { TEXT : "문서 제목" },
                STYLE : {...},
                META : {...}
              } ,
              BODY : {
                H1 : { TEXT : "제목", ATTRIBUTE : "속성" },
                COMMNET : {TEXT : "주석 내용"},
                DIV : {...}
                ul#test{ childNodes : [], innerText : 123,   }
              }
            }
        }
       

Node 확인하기

  <h1>Node 확인하기</h1>

  <ul id="test">
    <!-- Node 확인 테스트 주석입니다. -->

    <li id="li1">1번</li>
    <li class="cls">2번</li>
    <!-- 중간주석 -->
    <li style="background-color: yellow;">3번</li>
    <li>
      <a href="#">4번</a>
    </li>
  </ul>

  <button id="btn1">확인하기</button>
# JS

// Node 확인하기

document.querySelector("#btn1").addEventListener("click", () => {

  const test = document.querySelector("#test"); // ul

  console.log(test);

  // #test 의 모든 자식 노드 얻어오기
  // 요소.childNodes -> 배열
  const list = test.childNodes;
  console.log(list);

Node 탐색 방법

1) 부모 노드 탐색 : parentNode

2) 첫 번째 자식 노드 탐색 : firstChild

3) 마지막 자식 노드 탐색 : lastChild

4) 원하는 위치(인덱스)에 존재하는 자식 노드 탐색
    : childNodes[인덱스]
      
  <!-- Sibling : 형제, 자매, 남매 -->
5) 이전 형제 노드 탐색 : previousSibling

6) 다음 형제 노드 탐색 : nextSibling
# JS

  // 자식 노드 중 첫번째 li 요소
  console.log( list[3] );

  // 1. 부모 노드 찾기 (요소.parentNode)
  // li1 부모 노드를 찾아서 배경색 변경하기
  list[3].parentNode.style.backgroundColor = "skyblue";

  // 2. 첫번째 자식 노드 찾기 (요소.firstChild)
  // #test(ul) 의 첫번째 자식 노드 찾기
  console.log( test.firstChild );

  // 3. 마지막 자식 노드 찾기 (요소.lastChild)
  // #test(ul) 의 마지막 자식 노드 찾기
  console.log( test.lastChild );

  // 4. 원하는 위치(index)에 존재하는 자식 노드 찾기
  // (요소.childNodes[index])
  // #test(ul)의 자식 노드 중 
  // 3번째 li 태그를 찾아서 배경색 pink 지정하기
  test.childNodes[9].style.backgroundColor = "pink";

  // 5. 이전/다음 형제 노드 찾기
  // 이전 형제 노드 : 요소.previousSibling 
  // 다음 형제 노드 : 요소.nextSibling

  // -> 탐색용 코드는 연달아서 작성 가능!

  // test.childNodes[9]의 다음 다음 형제 노드 선택
  // == test.childNodes[11]
  console.log( test.childNodes[9].nextSibling.nextSibling );

  // #test의 마지막 자식 노드의 이전 형제 노드 선택
  console.log( test.lastChild.previousSibling );

Node 추가

1) appendChild(노드) : 마지막 자식 노드로 추가

2) append("내용" 또는 노드 또는 요소)
: 마지막 자식으로 내용/노드/요소를 추가
+ 매개변수로 여러 값을 작성해 한 번에 추가 가능

3) prepend("내용" 또는 노드 또는 요소)
: 첫번째 자식으로 내용/노드/요소를 추가
+ 매개변수로 여러 값을 작성해 한 번에 추가 가능

4) before("내용" 또는 노드 또는 요소) : 이전에 추가

5) after("내용" 또는 노드 또는 요소) : 다음으로 추가

  // 노드 추가

  // 1. 마지막 자식 노드로 추가 ( 요소.appendChild(노드) )

  // -> list[11]의 마지막 자식으로 "ZZZ" 라는 TextNode 추가
  list[11].appendChild( document.createTextNode("ZZZ") );

  // 2. 마지막 자식으로 추가 ( append("내용" 또는 노드 또는 요소 n개) )
  list[11].append("12345", "abcd", "가나다라");

  // 3. 첫 번째 자식으로 추가 ( 요소.prepend("내용" 또는 노드 또는 요소 n개) )
  list[11].prepend("오늘", "점심", "뭐먹지?");

  // 4. 이전/다음 형제로 추가 (요소.before / 요소.after("내용" 또는 노드 또는 요소 n개) )
  // #test 전/후에 내용추가
  test.before("이전입니다", "ㅎㅎ");
  test.after("이후입니다");
});

Node와 Element의 차이

Node : 태그(요소 노드), 속성 , 주속, 내용(텍스트 노드) 등을 모두 표현.
Element : Node의 하위 개념으로 요소 노드만을 표현

[Element만 탐색하는 방법]

children : 자식 요소만 모두 선택
parentElement : 부모 요소 선택

firstElementChild : 첫 번째 자식 요소 선택
lastElementChild : 마지막 자식 요소 선택

previousElementSibling : 이전 형제 요소 선택
nextElementSibling : 다음 형제 요소 선택

Node 테스트

    <ul id="test2">
      <!-- Node 확인 테스트 주석입니다. -->
 
      <li>1번</li>
      <li class="cls">2번</li>
      <!-- 중간주석 -->
      <li style="background-color: yellow;">3번</li>
      <li>
        <a href="#">4번</a>
      </li>
    </ul>
 
    <button id="btn2">확인하기</button>
# JS

document.querySelector("#btn2").addEventListener("click", () => {

  // #test2 얻어오기 (ul)
  const test2 = document.querySelector("#test2");

  // #test2 의 모든 자식 요소 얻어오기 (children)
  console.log( test2.children ); // HTMLCollecion

  // #test2 의 첫번째 자식 요소
  console.log( test2.firstElementChild );

  // #test2 의 마지막 자식 요소
  console.log( test2.lastElementChild );

  // #test2 의 부모 요소
  console.log( test2.parentElement );

  // #test2 의 이전 형제 요소
  console.log( test2.previousElementSibling );

  // #test2 의 다음 형제 요소
  console.log( test2.nextElementSibling );
});

요소 생성하기

  <button id="createBox">박스생성하기(createElement)</button>
  <button id="innerHTMLBox">박스생성하기(innerHTML)</button>

innerHTML과 append(또는 appendChild)는 동작방식이 다름.
차이점은 innerHTML은 DOM에 리렌더링 과정이 일어나며 전채 요소를 덮어씌고,
append는 기존 요소를 유지하면서 새로운 요소를 추가한다. (DOM 리렌더링 X)
# CSS

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.container {
  width: 80%;
  height: 300px;
  border: 1px solid black;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  overflow: auto;
}

.box {
  border: 1px solid black;
  width: 100px;
  height: 100px;
  border-radius: 10px;
  background-color: palegreen;
}

.box > input {
  width: 100%;
}
# JS

const createBox = document.querySelector("#createBox"); // button
const container = document.querySelector(".container"); // div

// createBox 버튼 클릭 시 div.box 요소를 생성하여
// container에 마지막 자식으로 추가

createBox.addEventListener("click", () => {

  // 1. div 요소 생성
  const box = document.createElement("div"); // <div></div>
  console.log(box);

  // 2. 만들어진 div 요소 "box" 클래스 추가
  box.classList.add("box"); // <div class="box"></div>

  // 3. container의 마지막 자식으로 div 요소 추가
  container.append(box);

  // 4. input 요소 생성
  const input = document.createElement("input"); // <input>
  input.type = "text"; // <input type = "text">

  // 5. 생성된 input을 box의 마지막 자식으로 추가
  box.append(input);
});

console.log(container.classList);

/*
요소.classList : 요소의 클래스 목록
-> 클래스 존재여부, 추가, 제거 등 할 수 있음

* 요소.classList
-> 요소 클래스 목록이 배열 형식으로 반환

* 요소.classList.contains("클래스명")
-> 클래스가 있으면 true, 없으면 false

* 요소.classList.add("클래스명")
-> 클래스 추가

* 요소.classList.remove("클래스명")
-> 클래스 제거
*/

// innerHTML로 요소 추가하기
const innerHTMLBox = document.querySelector("#innerHTMLBox");

innerHTMLBox.addEventListener("click", () => {
  container.innerHTML += "<div class ='box'><input type='text'><./div>";
});

요소 추가 / 제거

input에 작성된 값 모두 더하기
- 추가 버튼 클릭 시 화면에 input 요소가 추가됨
    
- 계산 버튼을 클릭 했을 때
  모든 input 요소에 작성된 값의 합을 alert()로 출력

  [도전!]
- 추가 버튼 클릭 시 input 요소 옆에 x 버튼 만들기
  x 모양 만들기 : <span>&times;</span>

- x 버튼 클릭 시
  해당 줄의 input, x 버튼 삭제하기

hint. 요소 삭제 방법  :  요소.remove()
  <div>

    <button id="add">추가</button>
    <button id="calc">계산</button>

    <div class="container">
      <div class="row">
        <input type="number" class="input-number">
      </div>

      <div class="row">
        <input type="number" class="input-number">
      </div>

    </div>
# CSS

body {
  display: flex;
}

body>div {
  margin-right: 50px;
}

.row {
  margin: 5px 0;
}

/* x버튼 */
.remove-row {
  display: inline-block;
  margin-left: 5px;
  font-size: 20px;
  cursor: pointer;
  user-select: none;
}

.remove-row:hover {
  font-weight: bold;
}

.remove-row:active {
  font-weight: bold;
  color: red;
}
# JS

// 요소.remove() : 요소 제거

// 공통적으로 사용되는 요소를 전역 변수 선언
const addBtn = document.querySelector("#add"); // 추가버튼
const calcBtn = document.querySelector("#calc"); // 계산버튼

const container = document.querySelector(".container"); // div
// 동적으로 만들어진 요소를 최종적으로 붙여야하는 요소

// 추가 버튼 클릭 시
addBtn.addEventListener("click", () => {

  /* <div class="row">
        <input type="number" class="input-number">
        <span class="remove-row">&times;</span>
    </div>
     */

    // 1. div 요소 생성하기
    const row = document.createElement("div"); // <div></div>

    // 2. row 요소에 class 추가하기
    row.classList.add("row"); // <div class="row"></div>

    // 3. input 요소 생성하기
    const input = document.createElement("input"); // <input>

    // 4. type="number" 추가하기
    //input.type = "number";
    input.setAttribute("type", "number"); // <input type="number">

    // 5. 클래스 "input-number" 추가하기
    //input.setAttribute("class", "test");
    input.classList.add("input-number"); 
    // <input type="number" class="input-number">

    // 6. span 요소 생성하기
    const span = document.createElement("span"); // <span></span>

    // 7. span태그에 클래스 "remove-row" 추가
    span.classList.add("remove-row"); // <span class="remove-row"></span>

    // 8. 내용으로 &times; 추가 (innerHTML 사용)
    span.innerHTML = "&times;"; // <span class="remove-row">&times;</span>

    // ----- 조립하기 -----

    // 9. div.row 요소에게 자식으로 input, span 추가
    row.append(input, span);

    /* 
    <div class="row">
        <input type="number" class="input-number">
        <span class="remove-row">&times;</span>
    </div>
     */

    // 10. 완성된 div.row 를 container의 마지막 자식으로 추가하기
    container.append(row);

    //*************************** */

    // 클릭된 x 버튼의 부모 요소를 제거

    // 1. 만들어진 x버튼(span)에 이벤트 리스너 추가
    span.addEventListener("click", (e) => {
    
      // 2. 현재 이벤트가 발생한 요소 (클릭된 x버튼) 의
      // 부모 요소를 선택(탐색)
      const parent = e.target.parentElement; // div.row

      // 3. 부모 요소를 제거하기
      parent.remove();
    });

});

// -----------------------

// 계산 버튼 클릭 시
calcBtn.addEventListener("click", () => {

  // 1) 모든 .input-number 요소 얻어오기
  const numbers = document.querySelectorAll(".input-number");

  // 2) for문 으로 모든 요소 접근하여
  // 작성된 값(value)을 얻어와
  // 숫자로 변경(Number()) 한 후
  // 합계 저장 변수 sum 에 누적
  let sum = 0;

  for(let i=0; i<numbers.length; i++) {
    sum += Number(numbers[i].value);
  }

  // 3) for문 끝나면 alert 결과 출력
  alert("결과 : " + sum); // alert에서 문자열 이어쓰려면 +
                          // console 에선 ,
});

window 내장객체

  • 브라우저 창 자체를 나타내는 객체
  • window 객체는 자바스크립트의 최상위 객체이며 DOM, BOM으로 분류된다.

DOM(Document Object Model) : document
BOM(Browser Object Model) : location, history, screen, navigator\

  • window 객체는 창 자체를 나타내고 있으므로
    어디서든 접근이 가능하다.
    그래서 window 라는 객체 호출부를 생략할 수 있다.
    ex) window.alert() == alert()
  <h2>window.setTimeout(함수, 지연시간(ms))</h2>
  <p>지연 시간 후 함수가 1회 실행</p>

  <button id="btn1">setTimeout 확인</button>

  <hr>

  <h2>window.setInterval(함수, 지연시간(ms))</h2>
  <p>지연시간 마다 함수 실행</p>

  <div id="clock" > 12 : 40 : 30</div>

  <h2>window.clearInterval(setInterval이 저장된 변수)</h2>
  <button id="stop">STOP</button>
# JS

// window.setTimeout()
document.getElementById("btn1").addEventListener("click", () => {
  setTimeout(function() {
    alert("3초 후 출력!");
  }, 3000);
});

// window.setInterval()
let interval; // setInterval을 저장하기 위한 전역변수

// 현재 시간을 문자열로 반환하는 함수
function currentTime() {

  const now = new Date();

  // console.log(now)
  let hour = now.getHours(); // 시
  let min = now.getMinutes(); // 분
  let sec = now.getSeconds(); // 초
  // 1의 자리만 나올 때 1, 2 이렇게 나옴
  // 디지털 시계 모양에 따라 1의 자리여도 01, 02.. 표현

  if(hour < 10) hour = "0" + hour;
  if(min < 10) min = "0" + min;
  if(sec < 10) sec = "0" + sec;

  return hour + " : " + min + " : " + sec;
}
function clockFn() {
  const clock = document.getElementById("clock");
    clock.innerText = currentTime();

    interval = setInterval(function() {
      clock.innerText = currentTime();
    }, 1000);
}

clockFn(); // 함수호출

document.getElementById("stop").addEventListener("click", () => {
  clearInterval(interval);
});

정규표현식

  • 특정한 규칙을 가진 문자열 집합을 표현하는데 사용하는 형식 언어.
  • 정규표현식을 이용하면 입력된 문자열에 대한 특정 조건 검색, 일치 여부 판단, 치환에 대한
    조건문을 간단히 처리할 수 있다.

정규표현식 객체 생성 및 확인

  1. 정규표현식 객체 생성 방법
    1) const regExp = new RegExp("정규표현식");
    2) const regExp = /정규표현식/;
    -> 양쪽 '/' 기호 정규 표현식의 리터럴 표기법

  2. 문자열 패턴 확인 메서드 (함수)
    1) regExp.test(문자열)
    -> 문자열에 정규표현식과 일치하는 패턴이 있을 경우 true, 없으면 false
    2) regExp.exec(문자열)
    -> 문자열에 정규표현식과 일치하는 패턴이 있을 경우
    처음 매칭되는 문자열을 반환, 없으면 null 반환
    # JS
    
    // 정규표현식 객체 생성 + 확인하기
    document.querySelector("#btn1").addEventListener("click", () => {
    
    // 정규표현식 객체 생성
    const regExp1 = new RegExp("script");
    // "script"와 일치하는 문자열이 있는지 검사하는 정규표현식
    
    const regExp2 = /java/;
    // "java" 와 일치하는 문자열이 있는지 검사하는 정규표현식
    
    // 확인하기
    const str1 = "저희는 지금 javascript를 공부하고있습니다";
    const str2 = "jsp(java server page)도 곧 할겁니다";
    const str3 = "java, java, java";
    
    console.log( regExp1.test(str1) ); // true
    console.log( regExp1.exec(str1) );
    
    console.log( regExp2.test(str2) ); 
    console.log( regExp2.exec(str2) );
     
    console.log( regExp2.test(str3) );
    console.log( regExp2.exec(str3) );
    });

정규표현식의 메타 문자

문자열의 패턴을 나타내는 문자.
문자마다 지정된 특별한 뜻이 담겨있다.

a (일반문자열) : 문자열 내에 a라는 문자열이 존재하는 검색
[abcd] : 문자열 내에 a,b,c,d 중 하나라도 일치하는 문자가 있는지 검색
^ (캐럿) : 문자열의 시작을 의미
$ (달러) : 문자열의 끝을 의미

\w (단어) : 아무 글자(단, 띄어쓰기, 특수문자, 한글 X)
\d (숫자) : 아무 숫자 (0~9 중 하나)
\s (공간) : 아무 공백 문자(띄어쓰기, 엔터, 탭 등)

[0-9] : 0부터 9까지 모든 숫자
[ㄱ-힣] : ㄱ부터 힣 까지 모든 한글
[a-z] : 모든 영어 소문자
[A-Z] : 모든 영어 대문자

* 특수문자의 경우 각각을 입력하는 방법밖엔 없음

* 수량 관련 메타 문자
a{5} : a문자가 5개 존재
a{2,5} : a가 2개 이상 5개이하
a{2,} : a가 2개 이상
a{,5} : a가 5개 이하

* : 0개 이상
+ : 1개 이상
? : 0개 또는 1개
. : 1칸 (개행문자를 제외한 문자 하나)

\*, \+, \?, \.
# JS

// 메타문자 확인하기
document.querySelector("#btn2").addEventListener("click", () => {

  const div1 = document.querySelector("#div1");

  // [abcd] 
  const regExp1 = /[abcd]/;
  div1.innerHTML += "/[abcd]/, apple : " + regExp1.test("apple") + "<hr>"; 
  div1.innerHTML += "/[abcd]/, ssbss : " + regExp1.test("ssbss") + "<hr>"; 
  div1.innerHTML += "/[abcd]/, qwerty : " + regExp1.test("qwerty") + "<hr>"; 

  // ^ (캐럿) 
  const regExp2 = /^group/; // 문자열의 시작이 group인지 확인
  div1.innerHTML += "/^group/, group100 : " + regExp2.test("group100") + "<hr>";
  div1.innerHTML += "/^group/, 100group : " + regExp2.test("100group") + "<hr>";
 
  // $ (달러)
  const regExp3 = /group$/; // 문자열의 끝이 group인지 확인
  div1.innerHTML += "/group$/, group100 : " + regExp3.test("group100") + "<hr>";
  div1.innerHTML += "/group$/, 100group : " + regExp3.test("100group") + "<hr>";
});

이름 , 주민등록번호 유효성 검사

  <h5>한글 2~5글자</h5>
  이름 : <input type="text" id="inputName"> <br>
  <span id="inputNameResult"></span>
# JS
// 이름 유효성 검사하기
document.getElementById("inputName").addEventListener("keyup", (e) => {

  // 결과 출력용 span 얻어오기
  const span = document.getElementById("inputNameResult");

  // 한글 2~5글자 정규표현식 객체 만들기
  const regExp = /^[ㄱ-힣]{2,5}$/;

  // 빈칸인지 검사
  if(e.target.value.length == 0) {
    span.innerText = "";
    return;
  }

  // 유효성 검사
  if( regExp.test(e.target.value) ) { // 유효한 경우
    span.innerText = "유효한 이름 형식입니다";
    span.style.color = "green";
    span.style.fontWeight = "bold";

  } else { // 유효하지 않은 경우
    span.innerText = "이름 형식이 유효하지 않습니다";
    span.style.color = "red";
    span.style.fontWeight = "bold";
  }
});
  <h3>주민등록번호 유효성 검사</h3>
  주민등록번호 : <input id="inputPno"> <br>
  <span id="inputPnoResult"></span>
# JS

// 주민등록번호 유효성 검사하기
document.getElementById("inputPno").addEventListener("keyup", (e) => {

  const span = document.getElementById("inputPnoResult");

  if(e.target.value.length == 0) {
    span.innerText = "주민등록번호를 작성해주세요";

    span.classList.remove("confirm", "error");
    return;
  }

  // 생년월일(6)-고유번호(7)
  const regExp = /^\d{6}-\d{7}$/;

  if(regExp.test(e.target.value)) { 
    span.innerText = "유효한 주민등록번호 형식입니다";

    //span.classList.add("confirm");
    //span.classList.remove("error");

    span.classList.toggle("confirm", true);
    span.classList.toggle("error", false);

  } else {
    span.innerText = "유효하지 않습니다.";

    //span.classList.add("error");
    //span.classList.remove("confirm");
    span.classList.toggle("confirm", false);
    span.classList.toggle("error", true);
  }
})

profile
인생은 변수

0개의 댓글