목표
마우스를 따라 내려오는 메뉴 만들기
내가 만든 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
const ul = document.querySelector('.cool');
const lists = document.querySelectorAll('.cool > li');
const triggers = Array.from(lists).map(list => list.querySelector('a'));
const background = document.querySelector(".dropdownBackground")
function dropDown() {
const dropdown = this.nextElementSibling;
dropdown.style.opacity = 1;
dropdown.style.display = "flex";
dropdown.style.flexDirection = "column";
const dropdownRect = dropdown.getBoundingClientRect();
const coords = {
top: dropdownRect.top - 66,
left: dropdownRect.left,
height: dropdown.offsetHeight,
width: dropdown.offsetWidth
}
background.style.opacity = 1;
background.style.height = coords.height + 'px';
background.style.width = coords.width + 'px';
background.style.left = coords.left + 'px';
background.style.top = coords.top + 'px';
}
function hideDropDown() {
this.nextElementSibling.style.opacity = 0;
background.style.opacity = 0;
}
triggers.forEach(trigger => trigger.addEventListener('mouseover', dropDown));
triggers.forEach(trigger => trigger.addEventListener('mouseleave', hideDropDown)); |
cs |
구현하긴 했는데 버튼 사이에 있을 때 메뉴가 사라진다. 자연스럽게 이어지지 않는 것 같다.
마우스가 dropdown 메뉴로 내려가면 사라진다. 메뉴 안에 있을 때 유지되어야 한다는 사실을 신경쓰지 못했다.
영상 따라하기
1
2
3
4
5
|
const triggers = document.querySelectorAll('.cool > li');
const background = document.querySelector('.dropdownBackground');
triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter));
triggers.forEach(trigger => trigger.addEventListener('mouseleave', handleLeave));
|
cs |
trigger에 mouseenter 이벤트 -> handleEnter 함수 / mouseleave 이벤트 -> handleLeave 함수 연결
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
function handleEnter() {
this.classList.add('trigger-enter');
setTimeout(() => this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'), 150);
background.classList.add('open');
const dropdown = this.querySelector('.dropdown');
const dropdownCoords = dropdown.getBoundingClientRect();
const navCoords = nav.getBoundingClientRect();
const coords = {
height: dropdownCoords.height,
width: dropdownCoords.width,
top: dropdownCoords.top - navCoords.top,
left: dropdownCoords.left - navCoords.left
};
background.style.setProperty('height', `${coords.height}px`);
background.style.setProperty('width', `${coords.width}px`);
background.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px`);
}
|
cs |
setTimeout의 익명함수의 형태에 따라 this가 달라진다
익명함수 setTimeout(function() {}) | 화살표 함수 setTimeout(() => {}) | |
this | window | trigger(li element) |
화살표 함수를 사용해야 우리가 원하는 this.classList.contains() 를 실행할 수 있다.
CSS에서 opacity와 display를 따로 설정해주는 이유
class | CSS 설정 |
.dropdown | opacity: 0; display: none; |
.trigger-enter .dropdown | display: block; |
.trigger-enter-active .dropdown | opacity: 1; |
handleEnter 함수가 실행되면 즉시 classList.add('trigger-enter')를 통해 display: block;을 해준다.
setTimeout으로 시간차를 두고 classList.add('trigger-enter-active') 를 통해 opacity: 1;을 설정해준다.
// 자연스러운 애니메이션을 위해
나는 정확히 버튼 위에 마우스가 올라가야 dropdown 메뉴가 나오는 것으로 생각하고 코드를 짰다.
그런데 굳이 그럴 필요가 없었고, trigger를 li로 설정하니까 li 사이를 움직일 때 공백이 없으므로 메뉴가 사라지지 않는다.
그리고 li에 eventListener가 있으므로 li의 child인 dropdown으로 마우스를 옮겨도 메뉴가 사라지지 않는다.
1
2
3
4
|
function handleLeave() {
this.classList.remove('trigger-enter', 'trigger-enter-active');
background.classList.remove('open');
}
|
cs |
classList.remove인 경우는 굳이 따로 나누지 않고 'trigger-enter'와 'trigger-enter-active'를 동시에 제거해준다.
background도 class 'open'을 제거한다.
새롭게 알게된 사실
무엇을 목표로 하는지 명확하게 알고 시작하자
바로 코드를 만들려고 하지말고 index 문서를 확인한 후 사용할 수 있는 class를 사용하자.
style을 바로 설정하는 것 보다 class를 통해 CSS에서 설정해 주는 것이 더 편하다.
if (A) {B} 는 A && B 로 간단하게 쓸 수 있다.
*절대좌표와 상대좌표에 대한 것
offsetTop, offsetLeft는 상대좌표로, 상위객체에 position=relative;가 있으면 그 상위 객체를 기준으로 한 좌표를 알려준다.
절대좌표는 getBoundingClientRect();로 구할 수 있다.
위치설정 - CSS에서 transform
'Javascript' 카테고리의 다른 글
Javascript30 - day28 Video Speed Controller UI (0) | 2021.05.06 |
---|---|
Javascript30 - day27 Click and Drag to Scroll (0) | 2021.05.04 |
Javascript30 - Day 25 Event Capture, Propagation, Bubbling and Once (0) | 2021.04.29 |
Javascript30 - day24 Sticky Nav (0) | 2021.04.28 |
Javascript30 - day23 Speech Synthesis (0) | 2021.04.27 |