드롭다운을 구현할 일이 있어서 정리 후 남겨본다. 드롭다운은 웹 프론트를 하다보면 꽤나 빈번히 만들 일이 생기는데, 그때그때 다른 방식으로 하다보니 나 역시도 전문성이 생긴다기보다는 그냥 그때그때의 능력껏 처리했던 것 같다. 이 기회에 정리해두고 참고하고자 한다.
드롭다운 구현 원리
특정 div 요소에 mouseover 이벤트가 발생하면 show 클래스리스트를 추가하여 css에서 드롭다운 메뉴를 보이도록 변경하고, mouseout 이벤트가 발생하면 show 클래스리스트를 제거하여 css에서 드롭다운 메뉴를 사라지게 하는 방식으로 구현하였다.
mouseover, mouseout이 아니라 클릭으로 구현하고 싶다면 addEventListener() 메서드의 첫 번째 argument로 click 이벤트를 활용하자.
javascript에서 html요소 정의하기
웹페이지에서 헤더 부분은 페이지가 변경되더라도 계속해서 쓰여야 하기 때문에, 별도의 자바스크립트에서 구현해두고 여러 페이지에서 돌려 쓰고 있던 상황이었다. 헤더메뉴 가장 우측에는 유저 id가 나오고, 유저 id에 마우스를 올리면 드롭다운 메뉴가 내려와서 POLICY, LICENSE, LOGOUT 버튼이 보여지는 드롭다운을 구현했다.
const body = document.body;
const header = $el('header', {}, [
// 앞부분 생략
$el('div.header-menu', { id: "user-id-menu" }, [
$el('span.header-text', `Hello, ${localStorage.getItem('user-id')}`),
$el('img', { src: "/SVG/arrow_drop_down.svg" }),
// user-id-menu에 mouseover, mouseout이벤트를 감지해서 드랍다운 구현
$el('div.user-id-dropdown-submenu', { id: "user-id-dropdown-submenu" }, [
$el('a', {
onclick: () => { alert("[개발 중] 사용자 정책 고지"); }
}, 'POLICY'),
$el('a', {
onclick: () => { alert("[개발 중] Stable Diffusion 모델, ComfyUI, 생성된 이미지의 저작권 안내"); }
}, 'LICENSE'),
$el('a', {
onclick: () => { this.userLogout(); }
}, 'LOGOUT')
])
]),
]);
body.append(header);
this.initUserIdDropdown();
initUserIdDropdown() {
const userIdMenu = document.getElementById('user-id-menu');
function showUserIdMenuDropdown() {
const userIdDropdownSubmenu = document.getElementById('user-id-dropdown-submenu');
userIdDropdownSubmenu.classList.add('show');
}
function hideUserIdMenuDropdown() {
const userIdDropdownSubmenu = document.getElementById('user-id-dropdown-submenu');
userIdDropdownSubmenu.classList.remove('show');
}
userIdMenu.addEventListener('mouseover', showUserIdMenuDropdown);
userIdMenu.addEventListener('mouseout', hideUserIdMenuDropdown);
}
export function $el(tag, propsOrChildren, children) {
const split = tag.split(".");
const element = document.createElement(split.shift());
if (split.length > 0) {
element.classList.add(...split);
}
if (propsOrChildren) {
if (typeof propsOrChildren === "string") {
propsOrChildren = { textContent: propsOrChildren };
} else if (propsOrChildren instanceof Element) {
propsOrChildren = [propsOrChildren];
}
if (Array.isArray(propsOrChildren)) {
element.append(...propsOrChildren);
} else {
const {parent, $: cb, dataset, style} = propsOrChildren;
delete propsOrChildren.parent;
delete propsOrChildren.$;
delete propsOrChildren.dataset;
delete propsOrChildren.style;
if (Object.hasOwn(propsOrChildren, "for")) {
element.setAttribute("for", propsOrChildren.for)
}
if (style) {
Object.assign(element.style, style);
}
if (dataset) {
Object.assign(element.dataset, dataset);
}
Object.assign(element, propsOrChildren);
if (children) {
element.append(...(children instanceof Array ? children : [children]));
}
if (parent) {
parent.append(element);
}
if (cb) {
cb(element);
}
}
}
return element;
}
위의 코드에서 html 요소 정의에 사용된 $el 메서드는 오픈소스 프로젝트인 ComfyUI 코드를 분석하다 발견했는데, 이후에도 꽤나 잘 사용하고 있다.
css 코드
.header-menu {
display: flex;
margin-right: 15px;
font-weight: bold;
color: rgba(255, 255, 255, 1);
line-height: 30px;
font-weight: 700;
font-size: 13px;
cursor: pointer;
}
.header-menu a {
color: inherit;
text-decoration: none;
display: inline-block;
width: 100%;
height: 100%;
}
.header-text:hover {
background-size: 100% 2px;
background-image: linear-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 1));
background-repeat: no-repeat;
background-position: left 0 bottom 0;
}
.header-text {
padding-bottom: 2px;
background-size: 0 2px;
}
.user-id-dropdown-submenu {
display: none; /* 기본적으로 숨김 */
position: absolute;
top: 41px;
background-color: rgba(0, 0, 0, 0.6);
color: #333333;
z-index: 1;
overflow: hidden;
max-height: 0;
transition: max-height 0.7s ease;
padding-top: 10px;
padding-right: 5px;
padding-left: 5px;
}
.user-id-dropdown-submenu a {
color: rgba(255, 255, 255, 1);
text-decoration: none;
display: block;
padding-right: 20px;
padding-left: 20px;
margin-bottom: 5px;
}
.user-id-dropdown-submenu a:hover {
background-color: rgba(100, 100, 100, 0.6);
}
.user-id-dropdown-submenu.show {
display: block;
max-height: 200px;
}
기본적으로 user-id-dropdown-submenu가 display: none;으로 보이지 않다가, 자바스크립트에서 동적으로 show 클래스리스트를 추가하면 보이도록 만들어 두었다. 애니메이션을 넣고싶은데 이건 나중에 시간 날때 해보도록 하자.
'🔨 개발 > 🖥️ 웹개발' 카테고리의 다른 글
자바스크립트에서 큐(Queue) 사용하기 (3) | 2024.09.27 |
---|---|
로컬 스토리지(LocalStorage)란 무엇인가?, 어떻게 사용하는가? (1) | 2024.09.19 |
CORS(Cross-Origin Resource Sharing)란 무엇인가? (1) | 2024.09.06 |
JWT 로그인 인증 방식: Stateful vs Stateless (1) | 2024.09.06 |
textarea의 blur 이벤트와 click 이벤트 발생 순서 문제 (0) | 2024.08.11 |