🚫 아마존 웹사이트를 클론해보면서 CSS를 학습하는 내용입니다.
구현은 되었으나 정확한 코드가 아니며 더 좋은 방법은 학습해가며 수정하려고 합니다.
백틱(`)을 사용한 문자열
Tagged Template Literals 문법 :: 마이구미 :: 마이구미의 HelloWorld (tistory.com)
DOM에서 요소를 다른 요소의 앞에 삽입하는 메서드다.
삽입하려는 요소와 삽입할 위치를 인수로 받아오며, 삽입할 위치를 지정할 수 있다.
삽입하고자 하는 부모노드.insertBefore(삽입할 노드, 삽입할 위치(부모 노드의 자식이어야 한다.)
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
const myList = document.querySelector("#myList");
const newItem = document.createElement("li");
newItem.textContent = "New Item";
myList.insertBefore(newItem, myList.firstChild);
위 예시에서 newItem이라는 li를 myList 자식 중 첫번째 자식 위에 삽입한다.
이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 말한다.
const divs = document.querySelectorAll("div");
divs.forEach(function (div) {
div.addEventListener("click", logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className); // three
}
위 예제 코드처럼 one div > two div > three div 트리 구조를 가지고 모든 div에 클린 이벤트를 주었을 때,
three만 클릭을 해도 이벤트는 3 → 2 → 1 순으로 발생한다.
이것을 이벤트 버블링 이라 한다.
이벤트 캡쳐는 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식이다.
// 이벤트 캡쳐링
const divs = document.querySelectorAll("div");
divs.forEach(function (div) {
div.addEventListener("click", logEvent, {
capture: true, // default 값은 false다.
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
three를 클릭시 1 → 2 → 3 순으로 이벤트가 전파 된다.
이벤트 버블링과 캡쳐를 막기위한 메서드다.
const divs = document.querySelectorAll("div");
divs.forEach(function (div) {
div.addEventListener("click", logEvent);
});
function logEvent(event) {
event.stopPropagation();
console.log(event.currentTarget.className);
}
3번을 클릭하면 3번에서만 이벤트가 발생한다.
자식 요소가 많은 상위 요소에서 이벤트 핸들링을 하는 기술이다.
각각의 자식 요소에 이벤트 핸들러를 등록하면 코드의 양이 많아지고, 성능 문제를 야기 할 수 있다.
때문에 상위 요소에서 이벤트를 처리하고, 이벤트가 발생한 자식 요소를 식별하는 것이 가능하다.
const container = document.querySelector("#container");
container.addEventListener("click", function (event) {
// 클릭 이벤트가 발생한 요소 확인
const clickedElement = event.target;
// 클릭된 요소가 특정 자식 요소인지 확인
if (clickedElement.classList.contains("myClass")) {
// 특정 자식 요소가 클릭되었을 때 실행되는 코드
// ...
}
});
.homeSidebar {
overflow-y: scroll;
}
.homeSidebar::-webkit-scrollbar {
display: none;
}
CSS에서 "-webkit-"은 웹킷(WebKit) 기반 브라우저에서만 동작하는 비표준(vendor-prefixed) CSS 속성 접두사(vendor prefix)다.
WebKit은 과거에 Apple 사의 사파리(Safari) 브라우저에서 사용되는 렌더링 엔진이었으며, 현재는 몇몇 브라우저(예: 사파리, 크롬 등)에서 공통으로 사용되는 엔진으로 발전하였다.
WebKit 기반 브라우저에서 사용되는 비표준 CSS 속성 접두사로는 "-webkit-" 이외에도, "-moz-"(Firefox), "-o-"(Opera), "-ms-"(Internet Explorer) 등이 존재한다.
따라서, ".homeSidebar::-webkit-scrollbar"는 웹킷 기반 브라우저에서만 동작하는 스크롤바의 스타일을 지정하는 CSS 선택자로 -webkit기반 브라우저가 아닌 곳에서는 적용이 안될 수 있다.
/* 생성될 li가 들어갈 ul과 기능 버튼만 남긴다. */
<ul class="homeSidebar__lists hideLists">
<li class="homeSidebar__mode--close hoverIcon">
<span>간단히 보기</span>
<i class="fa-solid fa-chevron-up"></i>
</li>
</ul>
const sideBarExtend = () => {
// 확장하면 나오는 리스트 타이틀 항목들
const DOWN_LIST = [
"자동차 용품",
"유아",
"뷰티 및 퍼스널 케어",
"여성 패션",
"남성 패션",
"여아용 의류",
"남아용 의류",
"건강 및 가정용품",
"가정 및 주방",
"산업용 및 과학용",
"여행 가방",
"영화 및 TV",
];
const appendExtentionList = () => {
let count = 8;
DOWN_LIST.forEach((item) => {
const ul = document.querySelector(".hideLists");
const li = document.createElement("li");
const icon = document.createElement("i");
const closeMore = document.querySelector(".homeSidebar__mode--close");
li.innerText = item;
li.classList.add("homeSidebar__subTitle", "hoverIcon");
li.dataset.columns = count;
count++;
icon.classList.add("fa-solid", "fa-chevron-right");
ul.insertBefore(li, closeMore);
li.appendChild(icon);
});
};
};
👍 JS로 HTML 요소를 만들어줌으로서 오는 장점
어떤 리스트를 클릭 했을 때 해당 리스트의 내용을 가진 레이아웃으로 전환하기 위해서
각 리스트 항목에 data-columns 값을 부여 해준다.
<li class="homeSidebar__subTitle hoverIcon" data-columns="1">
<span>Amazon Music</span>
<i class="fa-solid fa-chevron-right"></i>
</li>
데이터 속성 참고 자료 - mdn
데이터 속성 dataset 사용하기 (ft. JS/CSS 활용)
How to Use HTML5 Data Attributes
const sideBar = document.querySelector(".homeSidebar");
const sidebarLists = document.querySelector(".homeSidebar__lists");
const selectListInSidebar = (event) => {
// li전체, li이름, li버튼 어디를 클릭해도 이벤트 타겟은 li가 되도록 해준다.
const liEventTarget = event.target.closest("li");
// 이벤트 타겟이 li가 아닌 경우는 예외처리 해준다.
if (!liEventTarget) return;
// 클릭된 li의 고유번호 data-columns를 찾는다.
const columnNumber = liEventTarget.dataset.columns;
// 클릭된 li의 고유번호를 가진 세부항목 ul을 찾는다.
const selector = `ul[data-columns="${columnNumber}"]`;
const element = sideBar.querySelector(selector);
// 고유번호를 가진 ul이 아닌 경우 예외처리
if (!element) return;
const elementColumns = element.getAttribute("data-columns");
// 세부항목 ul중에서 클릭된 li의 columns과 같은 ul을 찾는다.
if (columnNumber === elementColumns) {
element.classList.add("show", "showSidebarDetailAnimation");
sidebarLists.classList.add("none");
}
};
// 사이드바 에서 리스트들을 가지고 있는 ul에 이벤트를 부여한다. (이베
sidebarLists.addEventListener("click", selectListInSidebar);
closest()
메서드는 주어진 CSS 선택자와 일치하는 요소를 찾을 때까지, 자기 자신을 포함해 위쪽(부모 방향, 문서 루트까지)으로 문서 트리를 순회한다.addEventListener로 클릭 이벤트를 등록하여 이벤트 타겟(클릭된 요소)를 사용하던 중,
사용되지 않는 요소를 클릭시 이벤트 타겟 값이 Null이되는 경우 에러가 발생한다.
이를 해결하기 위해 이벤트 타겟으로 정의되지 않은 요소가 클릭될 시 return 해주는 예외 처리가 필요하다.
const sidebar = document.querySelector(".homeSidebar");
const sidebarlists = document.querySelector(".homeSidebar__lists");
const selectListInSidebarDeail = (event) => {
const thisElement = event.target.closest("ul");
const liEventTarget = event.target.closest("li");
// liEventTarget가 타겟 된다면 실행, 아니면 return
if (liEventTarget) {
const backButtons = document.querySelectorAll(".homeSidebar__mode--back");
const selected = [...backButtons].find((button) => {
return button.contains(event.target);
});
// 타겟된 liEventTarget가 selected라면 실행, 아니면 return
if (selected && liEventTarget.className === selected.className) {
sidebarlists.classList.add("hideSidebarDetailAnimation");
sidebarlists.classList.remove("none");
thisElement.classList.remove("show", "showSidebarDetailAnimation");
thisElement.classList.remove("hideSidebarDetailAnimation");
}
}
};
sidebar.addEventListener("click", selectListInSidebarDeail);