Javascript 정리 ④

영긔·2024년 4월 21일
1

📒 Vanilla JS

목록 보기
4/8
post-thumbnail

✨ 스크롤 이벤트

📋 스크롤 내리면 로고 작게 만들기

🔎 스크롤 이벤트 리스너

window.addEventListener('scroll',function(){})

스크롤을 움직일 때마다 발생한다.

window.addEventListener('scroll',function(){
	console.log(window.scrollY);
})

window.scrollY: 유저가 얼마나 스크롤바 내렸는지(=window.pageOffset)
window.scrollX: 가로 스크롤바 측정할때
window.scrollTo(x,y): 강제로 스크롤 할때
부트스트랩에서는 스크롤 기능할때 다 스무스하게 하도록 함.
그래서 이걸 없애주고 싶다면 css에서

:root{
	scroll-behavior: auto;
}

이걸 입력하면 된다.
window.scrollBy(x,y): 현재 위치에서부터 강제로 스크롤하기

html

<nav class="navbar navbar-light bg-light">
        <div class="container-fluid">
            <span class="navbar-brand">JSShop</span>
            <span class="badge bg-white" style="color: black;" id="darkButton">Light 🔄</span>
            <button class="navbar-toggler" type="button">
                <span class="navbar-toggler-icon"></span>
            </button>
        </div>
    </nav>

js

window.addEventListener('scroll',function(){
  if (window.scrollY>100){
    document.querySelector('.navbar-brand').style.fontSize = "20px";
  }
  else{
    document.querySelector('.navbar-brand').style.fontSize = "30px";
  }
})

css

.navbar{
  position: fixed;
  width: 100%
  /* z-index: 5; */
}
.navbar-brand{
  font-size: 30px;
  transition : all 1s;
}

이런식으로 작성하면 밑과 같이 작동한다.

📋 스크롤바 끝까지 내리면 알림 띄우기

< div>스크롤바 내린 높이는 셀렉터.scrollTop하면 된다.
< div>실제 높이는 셀렉터.scrollHeight;

그런데 실제 적용해보면 셀렉터.scrollTop해도 scrollHeight에 미치지 못하는데, 스크롤 내린 길이에다가 실제 해당 눈에 보이는 div의 높이를 더해주어야 되기때문이다.

html

<div class="lorem" style="width: 200px; height: 100px; overflow-y: scroll">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quae voluptas voluptatum minus praesentium fugit debitis at, laborum ipsa itaque placeat sit, excepturi eius. Nostrum perspiciatis, eligendi quae consectetur praesentium exercitationem.
      </div>

js

document.querySelector('.lorem').addEventListener('scroll',function(){
  var scrollAmount = document.querySelector('.lorem').scrollTop;
  var realAmount = document.querySelector('.lorem').scrollHeight;
  var eyeAmount = document.querySelector('.lorem').clientHeight;
  if(scrollAmount+eyeAmount==realAmount){
    alert('약관을 다 읽었습니다!');
  }
})

이런식으로 작성하면 아래와 같이 동작한다.

📋 페이지 내릴 때 마다 페이지를 얼마나 읽었는지 진척도를 알려주는 UI

html

		<div class="progress" role="progressbar" aria-label
="Example with label" aria-valuemin="0"
            aria-valuemax="100">
            <div class="progress-bar" style="width: 0%"></div>
        </div>

js

window.addEventListener('scroll',function(){
  if (window.scrollY>100){
    document.querySelector('.navbar-brand').style.fontSize = "20px";
  }
  else{
    document.querySelector('.navbar-brand').style.fontSize = "30px";
  }
  document.querySelector('.progress-bar').style.width = (document.querySelector('html').scrollTop / (document.querySelector('html').scrollHeight-document.querySelector('html').clientHeight)) * 100 + '%';
})

작동화면은 다음과 같다.

document.querySelector('.progress-bar').style.width = (document.querySelector('html').scrollTop / (document.querySelector('html').scrollHeight-document.querySelector('html').clientHeight)) \* 100 + '%';

🤔주의할점: 처음에는

document.querySelector('.progress-bar').style.width = (document.querySelector('html').scrollTop / document.querySelector('html').scrollHeight) * 100 + '%';

이렇게 코드를 짰는데 바가 끝까지 차지 않았다.. 요주의 필요

✨ 탭 기능

📋 탭기능 만들기


위와같은 기능을 만들어보려고 한다.
먼저 css에 오렌지색 선이 생기는 orange와 내용을 보여주는 show를 정의해준다.
그리고, 버튼을 누를 때마다 orange, show 클래스를 전부 없애준다음, 클릭한 버튼에만 클래스를 추가하도록 했다.

html

	<div class="container mt-5">
        <ul class="list">
            <li class="tab-button">Products</li>
            <li class="tab-button">Information</li>
            <li class="tab-button">Shipping</li>
        </ul>
        <div class="tab-content">
            <p>상품설명입니다. Product</p>
        </div>
        <div class="tab-content">
            <p>스펙설명입니다. Information</p>
        </div>
        <div class="tab-content">
            <p>배송정보입니다. Shipping</p>
        </div>
    </div>

css

.tab-button {
  display: block;
  padding: 10px 20px 10px 20px;
  float: left;
  margin-right: -1px;
  margin-bottom: -1px;
  color: grey;
  text-decoration: none;
  cursor: pointer;
}
.orange {
  border-top: 2px solid orange;
  border-right: 1px solid #ccc;
  border-bottom: 1px solid white;
  border-left: 1px solid #ccc;
  color: black;
  margin-top: -2px;
}
.tab-content {
  display: none;
  padding: 10px;
}
.show {
  display: block;
}

js

var num = document.querySelectorAll(".tab-button").length;
for(let i=0;i<num;i++){
    document.querySelectorAll(".tab-button")[i].addEventListener("click", function () {
        document.querySelectorAll(".tab-button").forEach(function(btn) {
            btn.classList.remove("orange");
        });
        document.querySelectorAll(".tab-button")[i].classList.add("orange");
        document.querySelectorAll(".tab-content").forEach(function(btn) {
            btn.classList.remove("show");
        });
        document.querySelectorAll(".tab-content")[i].classList.add("show");
        
    });
}

🤔 주의점:

document.querySelectorAll(".tab-button").classList.remove("orange");

이런식으로 짜지 않도록 해야함. nodelist가 반환되어 classList.remove가 동작하지 않음
그러므로 forEach문을 사용하여 배열을 순회하여 처리하여야 함

🤔 주의점2:
js에서 반복문을 작성할 때 for(var i=0;i<3;i++)로 처리하니 작동하지 않았다. 그래서 let을 쓰니 작동했다. 이유는 var과 let의 범위가 다르기 때문. var은 범위가 function이라 for문 바깥에 생성되는데, let은 범위가 {}이라서 for 안쪽에서 생성된다. 따라서 var을 쓸 경우는 var i가 3이 된상태에서 참조해 에러를 일으키나, let i를 쓸 경우 각각 0,1,2를 쓰기 때문에 잘 수행된다.

🔎 좋은 코드를 짜는 법

💡 원하는 기능이 잘 구현되었는가?
💡 확장성이 좋은가?
💡 유지보수가 쉬운가?
💡 성능에 문제가 없는가?

✨ 이벤트 버블링

📋 모달창 누르면 닫히게


이런식으로 검은 배경 누르면 모달창이 닫히게 구현할 것이다.

html

	<div class="black-bg">
        <div class="white-bg">
            <h4>로그인하세요</h4>
            <form action="success.html">
                <div class="my-3">
                    <input type="text" id="email" class="form-control">
                </div>
                <div class="my-3">
                    <input type="password" id="pw" class="form-control">
                </div>
                <button type="submit" class="btn btn-primary" id="send">전송</button>
                <button type="button" class="btn btn-danger" id="close">닫기</button>
            </form>
        </div>
    </div>

js

document.querySelector('.black-bg').addEventListener('click', function(){
  document.querySelector('.black-bg').classList.remove('show-modal');
})

js에 이런 코드를 추가해주었다.
분명 black-bg를 누르면 모달창이 닫히게 구현하였으나, 그외를 눌러도 모달창이 닫힌다(!)

🔎 이벤트 버블링 (Event Bubbling)

html 태그에 이벤트가 발생하면 모든 상위요소까지 이벤트가 실행되는 것을 이벤트 버블링이라고 한다.

black-bg를 누르면 모달창이 닫히게 하였으나, white-bg를 눌러도 이벤트 버블링 때문에 black-bg를 누른 것과 같이 작동한다.

그러므로, 이벤트 리스너 안에 이벤트 함수를 작성해 위와같은 상황을 방지해야 한다.

e.target
이벤트가 발생한 타겟 가르킨다

e.currentTarget
addEventListener가 붙어 있는 타겟을 가르킨다

e.preventDefault()
이벤트의 고유동작을 막아준다

e.stopPropagation()
상위 엘리먼트들로의 이벤트 버블링을 막는다.

이런 함수들을 사용해 앞서 작성했던 js를 수정해볼 수 있다.

js

document.querySelector('.black-bg').addEventListener('click', function(e){
  if(e.target==document.querySelector('.black-bg')){
    document.querySelector('.black-bg').classList.remove('show-modal');
  }
  })

🤔 주의점:
e.target과 같은 함수를 쓸때 function(e)를 사용하는 것을 잊지않기.
e를 넣어야 쓸수 있다.

🔎 dataset 문법

<div data-데이터이름=""></div>

이런 방식으로 작성한 후에

document.querySelector().dataset.데이터이름;

이런 식으로 데이터를 부를 수 있다.

📋 탭기능 만들기(2)

앞서 배운 이벤트 버블링, dataset을 사용하여 다시 작성해보자

html

<div class="container mt-5">
        <ul class="list">
            <li class="tab-button" data-id="0">Products</li>
            <!-- data-id를 추가해주었다-->
            <li class="tab-button" data-id="1">Information</li>
            <li class="tab-button" data-id="2">Shipping</li>
        </ul>
        <div class="tab-content">
            <p>상품설명입니다. Product</p>
        </div>
        <div class="tab-content">
            <p>스펙설명입니다. Information</p>
        </div>
        <div class="tab-content">
            <p>배송정보입니다. Shipping</p>
        </div>
    </div>

js

document.querySelector(".list").addEventListener("click", function (e) {
  tabOpen(parseInt(e.target.dataset.id));
});
function tabOpen(i) {
  document.querySelectorAll(".tab-button").forEach(function (btn) {
    btn.classList.remove("orange");
  });
  document.querySelectorAll(".tab-button")[i].classList.add("orange");
  document.querySelectorAll(".tab-content").forEach(function (content) {
    content.classList.remove("show");
  });
  document.querySelectorAll(".tab-content")[i].classList.add("show");
}

🤔 주의할 점: js에서 처음에 tabOpen(e.target.dataset.id); 이렇게 작성했으나 작동하지 않았다. e.target.dataset.id가 숫자가 아닌 문자로 인식되어 tabOpen에서 제대로 인식되지않았다. 그래서 parseInt를 사용해 숫자로 변환해주니 작동하였다.

✨ 번외. 자바스크립트 라이브러리

Swiper
Chart.js
Animate On Scroll
EmailJS
Lodash
Fullpage.js

profile
SKYDeveloper

0개의 댓글