[프로그래밍] JavaScript

[JavaScript] DOM과 이벤트

JHVan 2024. 5. 20. 17:03

DOM

정의: 문서 객체 모델(Document Object Model), HTML/XML 문서의 프로그래밍 인터페이스

기능: 문서의 구조, 스타일, 내용 등을 변경 가능

종류:

  • Core DOM: 모든 문서 타입을 위한 모델
  • HTML DOM: HTML 문서를 위한 모델
  • XML DOM: XML 문서를 위한 모델

Document 객체

  • Document 객체는 웹 페이지를 의미
  • 웹 페이지에 존재하는 HTML 요소에 접근하고자 할 때는 반드시 Document 객체부터 시작

Document 객체 메서드

  • HTML 요소의 선택

  • HTML 요소의 생성

  • HTML 이벤트 핸들러 추가

2. 자바스크립트와 DOM

Point I

DOM 요소의 선택

// HTML <li> 요소를 선택
var selectedItem = document.getElementsByTagName("li");

// 아이디가 "id"인 요소를 선택
var selectedItem = document.getElementById("id");

// 클래스가 "odd"인 모든 요소를 선택
var selectedItem = document.getElementsByClassName("odd");

// name 속성값이 "first"인 모든 요소를 선택
var selectedItem = document.getElementsByName("first");

Point II

DOM 요소의 스타일 변경

// 아이디가 "even"인 요소를 선택
var selectedItem = document.getElementById("even");

// 선택된 요소의 텍스트 색상을 변경
selectedItem.style.color = "red";

Point III

DOM 요소의 내용 변경

// 아이디가 "text"인 요소를 선택
var str = document.getElementById("text");

// 선택된 요소의 내용을 변경
str.innerHTML = "요소의 내용을 바꿉니다";

3. Node 객체

Point I

노드 (Node)

  • 노드(Node) 정의: HTML DOM에서 정보를 저장하는 단위
  • 노드 트리: 노드들의 집합, 계층적 관계를 나타냄
  • 노드의 종류: 문서 노드, 요소 노드, 주석 노드, 속성 노드, 텍스트 노드
  • 노드 속성 접근: nodeName, nodeValue, nodeType

4. 이벤트

Point I

이벤트 (Event)

  • 정의: 웹 브라우저가 HTML 요소에 대한 사건의 발생을 알림
  • 이벤트 타입: 폼, 키보드, 마우스, HTML, DOM, Window 객체 등
// 마우스 클릭 이벤트 예시 <p onclick="changeText(this)">여길 클릭하세요!</p> 
<script>
function changeText(element) { 
	element.innerHTML = "내용이 바뀌었습니다!"; 
    }
</script>

 

  • 이벤트 핸들러: 이벤트 발생 시 처리를 담당하는 함수
// 이 함수는 HTML 문서가 로드될 때 실행됨.
window.onload = function(){ 
	// 아이디가 "text"인 요소를 선택함.
    var text = document.getElementById("text");
    text.innerHTML = "HTML 문서가 로드되었습니다."; 
}

 

DOM 요소 선택

함수 이름s가 붙는지 여부찾는 대상입력출력인덱싱 필요 여부

함수 이름s가 붙는지 여부찾는 대상입력출력인덱싱 필요 여부

(document.+)

함수 이름 복수형 찾는 대상 입력 출력 인덱싱
getElementsByTagName O
(Elements)
태그 (div 등) 문자열 요소들의 모음 필요
getElementsByClassName O
(Elements)
class 요소 문자열 요소들의 모음 필요
getElementsByName O
(Elements)
name 요소 문자열 요소들의 모음 필요
getElementById X
(Element)
id 요소 문자열 요소 불필요
  • Id는 중복되면 안됨. html 파일당 특정 id는 1번만 사용. getElementById 는 s 안붙음
  • 문자열은 문자를 ” ” 혹은 ’ ’ 로 감싸서 만듬
  • 출력에서 요소들의 모음인 경우, 마치 배열처럼 인덱싱 ( [0] 등으로 요소를 접근)가능
  • 요소들의 모음은 object - collection 으로 나타나고 요소는 object - Element 타입
  • 일반적으로 getElement~ 로 s 가 없는 경우, 바로 요소가 반환  (id로 찾는 경우 등) 하지만, getElements ~ 로 s가 있는 경우, 여러 개의 요소를 동시에 반환해야 하므로, 우선 요소들의 모음이라고 생각할 수 있는 object로 반환
  • 이후 인덱싱을 통해 특정 요소를 가져올 수 있음

Click 이벤트

버튼 요소에서

<button id="btn">버튼</button>

 

타겟을 가져오고

var target = document.getElementById("btn");

 

이벤트 함수 changeButtonOnclick()을 구현

function changeButtonOnclick() {
  target.classList.add("changeColor");
  target.innerText = "Clicked";
}

 

불러온 요소 target에 대해 addEventListnener를 이용해 "click" 이벤트로 해당 함수를 등록

target.addEventListener("click", changeButtonOnclick);

 

 

Cursor 이벤트

이미지 요소에서

<image className="image" src="./image.jpg"/>

 

이벤트 함수 zoomIn(), zoomOut() 구현

function zoomIn() {
  image.style.transform = "scale(1.2)";
  image.style.transition = "all 0.5s";
}

function zoomOut() {
  image.style.transform = "scale(1)";
  image.style.transition = "all 0.5s";
}

 

완성한 두 함수를 이벤트 리스너로 등록

마우스를 올렸을 때 발생하는 이벤트는 "mouseover"이고, 마우스를 뗐을 때 발생하는 이벤트는 "mouseleave"

image.addEventListener("mouseenter", zoomIn);
image.addEventListener("mouseleave", zoomOut);

 

DOM Tree 로 브라우저 형태 변형 - insertBefore()

createElement를 이용해 요소를 반환하는 변수 생성

<li> 태그를 생성하고 textContent로 해당 요소의 텍스트 입력

let li = document.createElement("li");
li.textContent = "Home";

 

 

id가 menu인 요소의 맨 앞에 위에서 생성한 li를 넣음

insertBefore를 이용하여 특정 요소 앞에 값 입력

menu의 제일 앞에 있는 요소를 firstElementChild로 찾고, insertBefore로 li 삽입

 

menu.insertBefore(li, menu.firstElementChild);

 

<div> 요소를 만들어서 calendar 앞에 삽입

<div> 태그는 HTML이 포함되어 있기 때문에 textContent가 아닌 innerHTML을 이용

let div = document.createElement("div");
div.innerHTML = "<strong> Here! </strong>";
calendar.insertBefore(div, calendar.firstElementChild);

 

 removeChild를 이용해 요소 삭제

menu.lastElementChild를 이용하여 menu의 제일 마지막에 있는 요소 삭제

menu.removeChild(menu.lastElementChild);

 

Submit List 만들기

아이템을 추가 (addItem) 하기

id가 item인 텍스트 박스의 값을 가져오기 위한 요소 newItem 생성

그리고 가져온 값을 리스트로 표현하기 위한 <li> 요소를 createElement 함수를 이용해 생성

  var newItem = document.getElementById("item").value;
  var li = document.createElement("li");

 

Bootstrap을 적용하기 위해 <li>의 클래스 이름을 list-group-item으로 지정

가져온 값을 createTextNode를 이용해 텍스트 노드로 만들고, appendChild를 이용해 자식 노드로 추가

  li.className = "list-group-item";
  li.appendChild(document.createTextNode(newItem));

 

button 요소인 deleteButton을 만들고,

Bootstrap을 적용하기 위한 클래스  btn btn-danger btn-sm float-right delete을 넣어 자식 노드로 추가

  var deleteButton = document.createElement("button");
  deleteButton.className = "btn btn-danger btn-sm float-right delete";

 

“삭제”라는 값을 가진 텍스트 노드를 만들어 버튼에 자식 노드로 넣어주고, 해당 버튼을 li의 자식 노드로 추가

최종적으로 만들어진 li를 id가 items인 요소의 자식 노드 즉, itemList에 자식 노드로 추가

  deleteButton.appendChild(document.createTextNode("삭제"));
  li.appendChild(deleteButton);
  itemList.appendChild(li);

 

classList.contains를 이용해 여러 클래스 중 특정 클래스를 가지고 있는지 확인

confirm을 이용해 확인, 취소 2개의 버튼이 있는 모달 출력

버튼이 아니라 버튼의 부모 노드인 <li> 요소를 삭제하므로 e.target.parentElement를 이용해 부모 노드를 가져옴

아이템 리스트에서 removeChild로 해당 노드를 제거

if (e.target.classList.contains("delete")) {
    if (confirm("Delete?")) {
      var li = e.target.parentElement;
      itemList.removeChild(li);
    }
  }

 

DOM 요소들의 개수를 세기

전체 개수 세기 (여기서는 p의 개수가 전체 개수)

getElementsByTagName를 이용하여 배열을 반환받고, 길이를 구하여 메뉴의 개수 확인

 var allParas = document.getElementsByTagName("p");
 var num = allParas.length;

 

특정 요소 개수 세기

해당하는 <div>를 가져온 뒤, 마찬가지로 <p> 요소의 개수로 확인

var div1 = document.getElementById("this");
var div1Paras = div1.getElementsByTagName("p");
var num = div1Paras.length;

 

Mouseover , Click 이벤트

window.onload = function () 안에서 코드를 작성하여 DOM을 조작하는 자바스크립트 코드가 HTML 문서보다 먼저 나오더라도, 정상적으로 동작하도록 미리 자바스크립트를 준비

<section> 의 <div> 들의 클래스 이름들이 mouseover의 타겟

(박스의 실제 CSS 색을 가져오는 것이 아닌, 작성되어 있는 클래스명을 가져오는 것입니다.)
생성되어 있는 section 변수에 mouseover 이벤트를 추가하여 화면에 출력
event.target.className을 이용해 mouseover된 요소의 클래스 이름을 가져옴

  section.addEventListener("mouseover", function (event) {
    var selectedColor = document.querySelector(".selected");
    selectedColor.innerText = event.target.className;
  });

 

Click 이벤트(버튼)

var target = document.getElementById("targetBtn");

function changeButtonOnclick() {
    target.classList.add("changeColor");
    target.innerText = "<= 버튼 클릭시 나타나는 이벤트";  
}

target.addEventListener("click", changeButtonOnclick);
----HTML----
<html>
    <button id="btn">클릭전 나타나는 텍스트</button>
    <script src="index.js"></script>
</html>

 

MouseOver 이벤트(이미지)

const image = document.getElementsByClassName("zoom-img")[0];

function zoomIn() {
  image.style.transform = "scale(1.2)";
  image.style.transition = "all 0.5s";
}

function zoomOut() {
  image.style.transform = "scale(1)";
  image.style.transition = "all 0.5s";
}

image.addEventListener("mouseenter", zoomIn);
image.addEventListener("mouseleave", zoomOut);

----HTML----
<div class="container">
    <img class="zoom-img" src="img/img.png">
</div>

 

Dom Tree 통한 요소 삽입

// createElement를 이용해 <li> 태그를 생성 하고
// textContent로 해당 요소의 텍스트를 ‘target’ 으로 변경 
let li = document.createElement("li");
li.textContent = "target";

// insertBefore()를 사용해서 menu의 <li> 태그 앞에 'Home'을 삽입
let menu = document.getElementById("menu");

menu.insertBefore(li, menu.firstElementChild);

// insertBefore()를 사용해서 calendar의 첫 번째 child로 예약 알람 문구를 삽입
let calendar = document.getElementById("calendar");

// HTML채로 삽입하므로 textContent X => innerHTML을 사용
let div = document.createElement("div");
div.innerHTML = "<strong>여기에</strong> 요소가 삽입됨.";
calendar.insertBefore(div, calendar.firstElementChild);

// removeChild()를사용해서 'Contact'라고 적힌 <li> 태그를 삭제
// .lastElementChild 로 마지막 요소 선택가능
menu.removeChild(menu.lastElementChild);

 

List 삽입

 

id가 item인 텍스트 박스의 값을 가져오기 위한 요소 만들기
그리고 가져온 값을 리스트로 표현하기 위한 <li> 요소를 createElement 함수를 이용해 생성

Bootstrap을 적용하기 위해서는 <li>의 클래스 이름을 list-group-item으로 지정
그리고 가져온 값을createTextNode를 이용해 텍스트 노드로 만들고, appendChild를 이용해 자식 노드로 연결

  //Get input value
  var newItem = document.getElementById("item").value;
  //Create new li element
  var li = document.createElement("li");
  //add Class
  li.className = "list-group-item";
  // Add text node with input value
  li.appendChild(document.createTextNode(newItem));

 

삭제버튼 추가

  //crate delete button element
  var deleteButton = document.createElement("button");
  // add classes to delete button
  deleteButton.className = "btn btn-danger btn-sm float-right delete";
  // append text node
  deleteButton.appendChild(document.createTextNode("삭제"));
  //append button to li
  li.appendChild(deleteButton);
  //append li to list
  itemList.appendChild(li);

 

통합 코드

var form = document.getElementById("addForm");
var itemList = document.getElementById("items");
var filter = document.getElementById("filter");

//form submit event
form.addEventListener("submit", addItem);
//delete event
itemList.addEventListener("click", removeItem);
//filter event
filter.addEventListener("keyup", filterItems);

//Add item
function addItem(e) {
  e.preventDefault();

  //Get input value
  var newItem = document.getElementById("item").value;
  //Create new li element
  var li = document.createElement("li");
  //add Class
  li.className = "list-group-item";
  // Add text node with input value
  li.appendChild(document.createTextNode(newItem));

  //crate delete button element
  var deleteButton = document.createElement("button");
  // add classes to delete button
  deleteButton.className = "btn btn-danger btn-sm float-right delete";
  // append text node
  deleteButton.appendChild(document.createTextNode("삭제"));
  //append button to li
  li.appendChild(deleteButton);
  //append li to list
  itemList.appendChild(li);
}

//Remove item
function removeItem(e) {
  if (e.target.classList.contains("delete")) {
    if (confirm("Are you sure?")) {
      var li = e.target.parentElement;
      itemList.removeChild(li);
    }
  }
}

//filter Event
function filterItems(e) {
  //convert to lowercase
  var text = e.target.value.toLowerCase();
  //get lis
  var items = itemList.getElementsByTagName("li");
  //conver to an array
  Array.from(items).forEach((item) => {
    var itemName = item.firstChild.textContent;
    if (itemName.toLowerCase().indexOf(text) != -1) {
      item.style.display = "block";
    } else {
      item.style.display = "none";
    }
  });
}

 

자주 쓰이는 JS 기능

스크롤 네비게이팅

var aTags = document.querySelectorAll("header a");
for(var i = 0; i < aTags.length; i ++) {
    aTags[i].onclick = function(e) {
        e.preventDefault() ;
        var target = document.querySelector(this.getAttribute("href"));

        window.scrollTo ({
            'behavior': 'smooth',
            'top':  target.offsetTop
        })
    }
}

 

이미지 자동 슬라이드

var slider = document.querySelector("#slider");
var slides = slider.querySelector(".slides");
var slide = slides.querySelectorAll(".slide");

var currentSlide = 0;

setInterval(function() {
    var from = -(1024 * currentSlide);
    var to = from - 1024;
    slides.animate({
        marginLeft: [from + "px", to + "px"]
    }, {
        duration: 500,
        easing: "ease",
        iterations: 1,
        fill: "both"
    });
    currentSlide++;
    if (currentSlide === (slide.length - 1)) {
        currentSlide = 0;
    }
}, 3000);
----HTML----
    <div id="slider">

        <ul class="slides">
            <li class="slide"><img src="img/image1.jpg" alt=""></li>
            <li class="slide"><img src="img/image2.jpg" alt=""></li>
            <li class="slide"><img src="img/image3.jpg" alt=""></li>
            <li class="slide"><img src="img/image4.jpg" alt=""></li>
            <li class="slide"><img src="img/image5.jpg" alt=""></li>
            <li class="slide"><img src="img/image1.jpg" alt=""></li>
        </ul>

    </div>

 

탭 버튼

var links = document.querySelectorAll(".tabs-list li a")
var items = document.querySelectorAll(".tabs-list li")
for (var i = 0; i < links.length; i++) {
    links[i].onclick = function(e) {
        e.preventDefault();
    }
}

for (var i = 0; i < items.length; i++) {
    items[i].onclick = function() {
        var tabId = this.querySelector("a").getAttribute("href") ;
        console.log(this.classList);
        document.querySelectorAll(".tabs-list li, .tabs div.tab").forEach(function(item) {
            item.classList.remove("active");
            console.log(item);
        });
        document.querySelector(tabId).classList.add("active");
        this.classList.add("active");
    }  
} 

----HTML----
<div class="tabs">
            <ul class="tabs-list">
                <li class="active"><a href="#tab1">탭1</a></li>
                <li ><a href="#tab2">탭2</a></li>
                <li ><a href="#tab3">탭3</a></li>
            </ul>

            <div id="tab1" class="tab active">
                <h3>탭1 title</h3>
                <p>
                    탭1 내용
                </p>
            </div>
            <div id="tab2" class="tab">
                <h3>탭2 title</h3>
                <p>
                    탭2 내용
                </p>
            </div>
            <div id="tab3" class="tab">
                <h3>탭3 title</h3>
                <p>
                    탭3 내용
                </p>
            </div>
            
            
  ----CSS----
  
/***********
*** Tabs ***
***********/
.tabs{
    width: 100%;
    height:auto;
}

.tabs .tabs-list li{
    float:left;
    width: 33.3333%;

    padding:10px 5px;

    text-align: center;
    background-color: #524fa1;
}

.tabs .tabs-list li:hover{
    cursor:pointer;
}

.tabs .tabs-list li a{
    text-decoration: none;
    color:white;
}

/* Tab Content */
.tabs .tab{
    display:none;

    width: 100%;
    min-height:250px;
    height:auto;

    padding:20px 32px;

    background-color: #efeff6;
    color:#333;
    clear:both;
}

.tabs .tab h3{
    border-bottom:3px solid #524fa1;
    letter-spacing:1px;
    font-weight:normal;
    padding:5px;

    margin-bottom: 12px;
}

.tabs .tab p{
    line-height:24px;
    letter-spacing: 1px;
}

/* Tab Active */
.active{
    display:block !important;
}
.tabs .tabs-list li.active{
    background-color: #efeff6 !important;
    color:black !important;
}
.active a{
    color:black !important;
}

 

수동 이미지 슬라이더

//오른쪽
document.querySelector(".right-arrow").onclick = function () {
    var currentSlide = document.querySelector("#photo .slide.active");
    var nextSlide = currentSlide.nextElementSibling;
    if (nextSlide === null) {
        nextSlide = currentSlide.parentElement.firstElementChild;
    }
        currentSlide.animate({
        opacity: [1, 0]
    }, {
        duration: 500,
        easing: "ease",
        iterations: 1,
        fill: "both"
    });
    currentSlide.classList.remove("active");
    nextSlide.animate({
        opacity: [0, 1]
    }, {
        duration: 500,
        easing: "ease",
        iterations: 1,
        fill: "both"
    });
    nextSlide.classList.add("active");
}

//왼쪽 
document.querySelector(".left-arrow").onclick = function () {
    var currentSlide = document.querySelector("#photo .slide.active");
    var previousSlide = currentSlide.previousElementSibling;
    if (previousSlide === null) {
        previousSlide = currentSlide.parentElement.lastElementChild;
    }
        currentSlide.animate({
        opacity: [1, 0]
    }, {
        duration: 500,
        easing: "ease",
        iterations: 1,
        fill: "both"
    });
    currentSlide.classList.remove("active");
    previousSlide.animate({
        opacity: [0, 1]
    }, {
        duration: 500,
        easing: "ease",
        iterations: 1,
        fill: "both"
    });
    previousSlide.classList.add("active");
}

----HTML----
<section id="photo">
        <div class="slider">

            <div class="slide active"></div>
            <div class="slide"></div>
            <div class="slide"></div>

        </div>

        <p class="left-arrow"></p>
        <p class="right-arrow"></p>

    </section>

'[프로그래밍] JavaScript' 카테고리의 다른 글

[JavaScript] 연산자  (0) 2024.05.13
[JavaScript] JavaScript ?  (0) 2024.05.13