Javascript

Javascript30 : day 26 Stripe Follow Along Dropdown

joy_lee 2021. 4. 30. 23:05

목표

마우스를 따라 내려오는 메뉴 만들기

 

내가 만든 코드

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