코딩 기록/코딩 소스 [HTML & CSS & JS]
자바스크립트 제이쿼리 header gnb 탑메뉴 예제 3 (PC & 모바일)
kimyang-Sun
2023. 2. 1. 21:39
See the Pen 자바스크립트 header gnb 탑메뉴 예제 3 (PC & 모바일) by kimyangsun (@kimyangsun) on CodePen.
https://codepen.io/kimyangsun/pen/YzjJgLL
자바스크립트 header gnb 탑메뉴 예제 3 (PC & 모바일) 코드펜 소스입니다.
저번에 두번째 예제까지 올리고 나서 생각해보니까 또 다른 자주 쓰이는 방식을 깜빡해서 예제 샘플을 하나 더 만들었습니다 :)
예제 1 처럼 2차 메뉴까지 보여주는데 이건 한번에 보여주는게 아닌 각각 해당하는 1차 메뉴에 대한 2차 메뉴만 보여주는 방식입니다.
"use strict";
// 헤더 gnb 스크립트
const header = document.querySelector('.header');
const mobileGnb = document.querySelector('.mobile-gnb');
window.addEventListener('DOMContentLoaded', () => {
initGnb(header);
initMobileGnb(mobileGnb);
})
// PC
function initGnb(header){
let gnb = header.querySelector('.header-gnb');
let gnbMenus = gnb.querySelectorAll('.gnb-depth-1 .depth-1');
[...gnbMenus].forEach(menu => {
menu.addEventListener('mouseenter', (event) => {
gnbOpen(event.target);
});
menu.addEventListener('focusin', (event) => {
gnbOpen(event.target.closest('.depth-1'));
});
menu.addEventListener('mouseleave', (event) => {
gnbClose(event.target);
});
menu.addEventListener('focusout', (event) => {
gnbClose(event.target.closest('.depth-1'));
});
});
function gnbOpen(target){
let targetItem = target.querySelector('.depth-item');
let targetMenu = target.querySelector('.gnb-depth-2');
let targetHeight = targetMenu.getBoundingClientRect().height;
header.classList.add('open');
target.classList.add('current');
targetItem.style.height = `${targetHeight}px`;
}
function gnbClose(target){
let targetItem = target.querySelector('.depth-item');
header.classList.remove('open');
target.classList.remove('current');
targetItem.style.height = '0px';
}
}
// Mobile
function initMobileGnb(mobileGnb){
let html = document.querySelector('html');
let sidebarButton = mobileGnb.querySelector('.sidebar-btn');
let mobileMenuButtons = mobileGnb.querySelectorAll('.depth-1 a');
sidebarButton.addEventListener('click', (event) => {
if (mobileGnb.classList.contains('open')) {
mobileGnbClose(mobileGnb);
} else {
mobileGnbOpen(mobileGnb);
}
});
mobileMenuButtons.forEach(button => {
button.addEventListener('click', (event) => {
event.preventDefault();
let $this = event.target;
openAccordion($this);
});
})
window.addEventListener('resize', function(){
if (window.innerWidth > 1024) {
mobileGnbClose(mobileGnb);
}
});
function mobileGnbOpen(gnb){
gnb.classList.add('open');
html.classList.add('not-scroll');
}
function mobileGnbClose(gnb){
gnb.classList.remove('open');
html.classList.remove('not-scroll');
}
// 모바일 메뉴 아코디언
function openAccordion($this) {
let target = $this.parentElement;
let depthTarget = $this.nextElementSibling;
if (!depthTarget) return;
let otherLinks = siblings(target);
let otherItems = otherLinks.map(link => link.querySelector('ul'));
if (target.classList.contains('open')){
target.classList.remove('open');
depthTarget.style.maxHeight = '0px';
} else {
otherLinks.forEach(link => link.classList.remove('open'));
otherItems.forEach(item => item ? item.style.maxHeight = '0px' : '');
target.classList.add('open');
depthTarget.style.maxHeight = depthTarget.scrollHeight + 'px';
}
}
}
function siblings(element) {
return [...element.parentElement.children].filter(value => value != element);
}