JS에서 scroll 메서드를 활용해서 브라우저의 스크롤을 조정할 수 있다. 스크롤 메서드는 다음과 같이 작성한다.
// 1.
scroll(x-coord, y-coord)
// 2.
scroll({
top: 0,
left: 0,
behavior: 'smooth',
})
1번 코드, 2번코드는 동일하나, 2번 코드에서 behavior 옵션을 추가하여 'smooth'라고 작성했을 경우에는 부드럽게 화면 스크롤이 진행된다.
더보기
더보기
HTML
<!DOCTYPE html>
<html lang='ko'>
<head>
<meta charset='UTF-8'>
<title>Document</title>
<!-- css -->
<link rel='stylesheet' href='css/style.css'>
<!-- script -->
<script defer src="js/script.js"></script>
<!-- fontawesome cdn-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css">
</head>
<body>
<section class="box1"></section>
<section class="box2"></section>
<section class="box3"></section>
<section class="box4"></section>
<ul class="btns">
<li class="on"></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
</html>
CSS
// reset css import
@import "reset.scss";
section {
width: 100%;
height: 100vh;
&.box1 {
background: pink;
}
&.box2 {
background: lightsalmon;
}
&.box3 {
background: lightblue;
}
&.box4 {
background: lightgreen;
}
}
.btns {
position: fixed;
top: 50%;
right: 50px;
transform: translateY(-50%);
>li {
width: 20px;
height: 20px;
border-radius: 10px;
background: #fff;
margin-top: 20px;
transition: 0.5s;
&.on {
background: #000;
height: 50px;
}
}
}
스크롤 거리를 구한 뒤, 스크롤의 위치에 따라 버튼을 활성화하도록 코드를 구성했다.
const sections = document.querySelectorAll('section');
const btns = document.querySelectorAll('.btns li');
let posArr = [];
sections.forEach(section => {
posArr.push(section.offsetTop);
})
window.addEventListener("scroll", () => {
console.clear();
// 스크롤 거리 구하기
let scroll = window.scrollY;
let base = 300;
for (let i = 0; i < posArr.length; i++) {
if (scroll >= posArr[i] &&
(scroll < posArr[i+1] || i+1 == posArr.length)) {
for (let btn of btns) {
btn.classList.remove('on');
}
btns[i].classList.add('on');
}
}
})
하지만 posArr로 전역변수를 사용하는 것이 낭비라는 생각이 들었고, 나중에 HTML 코드를 추가하거나 하는 등의 상황이 발생했을 경우에 유연하지 못한 코드라고 생각했기 때문에 코드를 수정해주었다.
const sections = document.querySelectorAll('section');
const btns = document.querySelectorAll('.btns li');
window.addEventListener("scroll", () => {
console.clear();
// 스크롤 거리 구하기
let scroll = window.scrollY;
let base = 300;
sections.forEach((section, idx) => {
// section 안에 스크롤이 들어왔을 경우에만 실행
if (scroll >= section.offsetTop - base &&
(idx+1 == sections.length || scroll < sections[idx+1].offsetTop - base)) {
for (let btn of btns) {
btn.classList.remove('on');
}
btns[idx].classList.add('on');
}
});
})
posArr 변수를 삭제하였고, forEach를 통해 section 값과 index 값을 가져와 리팩토링했다.
// 버튼 클릭 이벤트 바인딩
btns.forEach((btn, idx) => {
btn.addEventListener("click", (e) => {
// 활성화된 버튼이 아닐 경우에만 실행
let isOn = e.currentTarget.classList.contains('on');
if (!isOn) {
window.scroll({
top: sections[idx].offsetTop,
left: 0,
behavior: 'smooth',
});
}
});
})
버튼들에 클릭이벤트를 바인딩하여 클릭했을 때 화면이 스크롤되어 버튼에 매칭되는 section이 보이도록 개발했다. 활성화된 버튼일 경우 실행되지 않아도 되기 때문에 예외처리를 해주었다.
// 리사이징 시 화면 재조정
window.addEventListener('resize', () => {
const btnArr = Array.from(btns);
let activeBtn = document.querySelector('.btns li.on');
const activeIdx = btnArr.indexOf(activeBtn);
console.log(activeIdx);
window.scroll({
top: sections[activeIdx].offsetTop,
left: 0,
})
})
사용자가 화면을 리사이징했을 경우, 활성화된 버튼과 화면에 보여지는 section이 매칭이 되지 않는 문제가 발생했다. 따라서 리사이징 이벤트 리스너를 따로 구현하여 재조정하는 코드를 작성해주었다.
// 휠 스크롤 시 실행
sections.forEach(((section, idx) => {
section.addEventListener('mousewheel', (e) => {
e.preventDefault();
const sectionArr = Array.from(sections);
let activeSection = document.querySelector('section.on');
const activeIdx = sectionArr.indexOf(activeSection);
// down -> 100
if (e.deltaY > 0) {
// 맨 아래일 경우 스킵
if (idx == sections.length - 1) {
return;
}
window.scroll({
top: sections[activeIdx + 1].offsetTop,
left: 0,
behavior: 'smooth',
});
}
// up -> -100
else if (e.deltaY < 0) {
// 맨 위일 경우 스킵
if (idx == 0) {
return;
}
window.scroll({
top: sections[activeIdx - 1].offsetTop,
left: 0,
behavior: 'smooth',
});
}
})
}))
사용자가 휠 스크롤을 했을 경우에 자연스럽게 다음 section이 보여지도록 개발했다. 맨 위이거나 맨 아래일 때 예외처리를 해주었다.
'Today I Learned > JS' 카테고리의 다른 글
[JS] 람다표현식 (0) | 2024.08.24 |
---|---|
[JS] Cookie - 에이블런 프론트엔드부트캠프 24일차 (0) | 2024.08.16 |
[JS] Form Validation 2 - 에이블런 프론트엔드 부트캠프 21일차 (0) | 2024.08.12 |
[JS] Form Validation - 에이블런 프론트엔드부트캠프 20일차 (4) | 2024.08.12 |
[JS] Kakao Map - 에이블런 프론트엔드부트캠프 18일차 (0) | 2024.08.08 |