13.포트폴리오 클론코딩 만들기 Javascript(별 100만개)
- 내 코드가 엉망진창이라, Ellie님의 HTML을 활용해서 먼저 Javascript를 구현하고 비교해보았다.
코딩비교
-
- 기능에 맞는 javascript 코딩을 구현했는가?
Javascript 비교(1) - Transparent navbar
- Expert
//Make navbar transparent when it is on the top
const navbar = document.querySelector("#navbar");
const navbarHeight = navbar.getBoundingClientRect().height;
document.addEventListener("scroll", () => {
if (window.scrollY > navbarHeight) {
navbar.classList.add("navbar--dark");
} else {
navbar.classList.remove("navbar--dark");
}
});
javascript 비교(2) - Scroll to section
- Expert
- list를 가져온것이 아닌 menu 자체를 가져왔다. querySelectorAll()를 사용하지 않았으므로, 당연히 forEach()를 해줄 필요가 없었다.
- data-link에 #을 주어서 그 값을 통해 document를 해주어서 해당 section을 찾았다.
<div class="navbar__menu">
<ul class="navbar__menu">
<li class="navbar__menu__item active" data-link="#home">home</li>
<li class="navbar__menu__item" data-link="#about">About</li>
<li class="navbar__menu__item" data-link="#skills">Skills</li>
<li class="navbar__menu__item" data-link="#work">My Work</li>
<li class="navbar__menu__item" data-link="#testimonials">
Testimonials
</li>
<li class="navbar__menu__item" data-link="#contact">Contact</li>
</ul>
</div>
const navbarMenu = document.querySelector(".navbar__menu");
navbarMenu.addEventListener("click", (e) => {
const target = e.target;
const link = target.dataset.link;
if (link == null) {
return;
}
const scrollTo = document.querySelector(link);
scrollTo.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest",
});
});
-
Yosup
-
forEach()를 두번이나 쓰고 이 기능을 실행했다니..
-
시간면에서도 전문가가 훨씬 빠르게 동작을 하겟다.
<div class="navbar__menu">
<ul class="navbar__menu">
<li class="navbar__menu__item active" data-name="home">home</li>
<li class="navbar__menu__item" data-name="about">About</li>
<li class="navbar__menu__item" data-name="skills">Skills</li>
<li class="navbar__menu__item" data-name="work">My Work</li>
<li class="navbar__menu__item" data-name="testimonials">
Testimonials
</li>
<li class="navbar__menu__item" data-name="contact">Contact</li>
</ul>
</div>
// Scroll to section
// 내가 클릭한 list의 값과 section이 id값이 일치할경우
// 일치하는 section으로 이동한다.
// list에 name의 속성을 주거나 , data속성을 주어서 그 값을 가져오는게 textContent로 가져오는것보다 좋을것 같다라는 생각이 들었다.
const menuItems = document.querySelectorAll(".navbar__menu__item");
const sections = document.querySelectorAll("section");
menuItems.forEach((item) => {
item.addEventListener("click", (e) => {
sections.forEach((section) => {
if (section.getAttribute("id") === e.target.dataset.name) {
section.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest",
});
}
});
});
});
javascript 비교(3) - Handle contact me button
-
Expert
-
첫번재 방법
const homeContactBtn = document.querySelector(".home__contact");
homeContactBtn.addEventListener("click", () => {
const scrollTo = document.querySelector("#contact");
scrollTo.scrollIntoView({ behavior: "smooth" });
});
- 두번째 방법 링크의 이동이 계속 반복되므로, 이 코드를 굳이 반복해서 쓰기 보다는 함수를 만들어 재활용해서 씀
const homeContactBtn = document.querySelector(".home__contact");
const navbarMenu = document.querySelector(".navbar__menu");
navbarMenu.addEventListener("click", (e) => {
const target = e.target;
const link = target.dataset.link;
if (link == null) {
return;
}
scrollIntoView(link);
});
homeContactBtn.addEventListener("click", () => {
scrollintoView("#contact");
});
function scrollIntoView(selector) {
const scrollTo = document.querySelector(selector);
scrollTo.scrollIntoVie({ behavior: "smooth" });
}
-
Yosup
-
어차피 클릭하면 하나로만 이동하는데 굳이 e.target을 쓸 필요가 있었을까 싶고, 거기에 데이터를 넣어주지 않아도 이동할수 있었음에도 이렇게 작성한것에 반성하자.
// Handle contact me Button
const contactBtn = document.querySelector(".home__contact");
contactBtn.addEventListener("click", (e) => {
const link = e.target.dataset.link;
const section = document.querySelector(link);
section.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest",
});
});
javascript 비교(4) - Transparent home
- Expert : inline으로 작성되는것도 두려워하지 말자.. (inline으로 작성될수도 있는거임..)
const home = document.querySelector(".home__container");
const homeHeight = home.getBoundingClientRect().height;
document.addEventListener("scroll", () => {
home.style.opacity = 1 - window.scrollY / homeHeight;
});
javascript 비교(5) - Arrow up button
-
Expert
-
line style을 주기 보다는 classlist를 주고 , trasition을 주었다.
.arrow-up {
right: 25px;
bottom: 25px;
position: fixed;
z-index: 3;
font-size: 40px;
transition: all var(--animation-duration) ease;
opacity: 0;
pointer-events: none;
/* 클릭이 안돼게 함 */
}
.arrow-up.visible {
opacity: 1;
pointer-events: auto;
}
const arrowUp = document.querySelector(".arrow-up");
document.addEventListener("scroll", () => {
if (window.scrollY > homeHeight / 2) {
arrowUp.classList.add("visible");
} else {
arrowUp.classList.remove("visible");
}
});
arrowUp.addEventListener("click", () => {
scrollIntoView("#home");
});
- Yosup
const arrow = document.querySelector(".arrow");
arrow.addEventListener("click", () => {
home.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest",
});
});
document.addEventListener("scroll", () => {
if (window.scrollY / 1000 > 1) {
arrow.style.opacity = 1;
} else {
arrow.style.opacity = window.scrollY / 1000;
}
});
javascript 비교(6) - Project filtering&animation
-
Expert
-
클릭했던것의 filtering된 요소들은 invisible 을 remove 하고, 그게 아닌요소들은 invisible 을 add 함으로써 간단하게 해결함..
const workBtnContainer = document.querySelector(".work__categories");
const projectContainer = document.querySelector(".work__projects");
const projects = document.querySelectorAll(".project");
workBtnContainer.addEventListener("click", (e) => {
const filter = e.target.dataset.filter || e.target.parentNode.dataset.filter;
// span을 눌렀을때에는 filter를 반납할수 없으므로
if (filter == null) {
return;
}
projects.forEach((project) => {
if (filter === "*" || filter === project.dataset.type) {
project.classList.remove("invisible");
} else {
project.classList.add("invisible");
}
});
});
-
Yosup(1) : CSS를 통해서 filtering 하는방법
-
버튼을 눌렀을때 그 데이터에 맞는요소들이 아닌 것들을 안보이게 하는 방법
-
기존의 것을 안보이게 한다음에, filtering 된 요소들만 보이게 해도 됬지만, 이미 project class가 flex가 되어버린 상태이기 때문에 display:none을 해줄수가 없어서, 이 방법을 채택해봤다.
-
코드를 더 복잡하게 짜는 능력이 있는듯…
//1. CSS를 통해 분류 하는방법
const workCategories = document.querySelector(".work__categories");
const projects = Array.from(document.querySelectorAll(".project"));
workCategories.addEventListener("click", (e) => {
if (e.target.dataset.field === undefined) {
return;
}
const clickBtn = e.target.dataset.field;
//clickbtn를 제외한 나머지에 CSS를 display:none을 해준다
const filterprojects = projects.filter((project) => {
if (clickBtn == "all") {
return;
}
return project.dataset.field !== clickBtn;
});
projects.forEach((project) => {
project.classList.remove("invisible");
});
//누른것을 제외한 나머지를 invisible로 둠
filterprojects.forEach((filterproject) => {
filterproject.classList.add("invisible");
});
});
- Yosup(2) : javascript를 통해서 filtering 하는방법
const workCategories = document.querySelector(".work__categories");
const projects = Array.from(document.querySelectorAll(".project"));
const workProjects = document.querySelector(".work__projects");
workCategories.addEventListener("click", (e) => {
if (e.target === undefined) {
return;
}
const dataName = e.target.dataset.field;
const filterProjects = projects.filter((project) => {
if (dataName == "all") {
return project;
} else {
return project.dataset.field === dataName;
}
});
// 전체 자식요소 제거
while (workProjects.lastChild) {
workProjects.removeChild(workProjects.lastChild);
}
// filtering한 요소 추가
for (let i = 0; i < filterProjects.length; i++) {
workProjects.appendChild(filterProjects[i]);
}
});
javascript 비교(7) - project animation
- Expert
- js 의 동작방식에 따라서 코드를 짰다.
- 특징으로는 setTime 안에 코드를 넣었다는것 , 그 이유는??
-
첫번째 경우 filtering이 된 상태에서 내려간다.
-
두번쨰 경우는 내려간뒤에 필러딩을 한것을 올려보낸다.
const workBtnContainer = document.querySelector(".work__categories");
const projectContainer = document.querySelector(".work__projects");
const projects = document.querySelectorAll(".project");
workBtnContainer.addEventListener("click", (e) => {
const filter = e.target.dataset.filter || e.target.parentNode.dataset.filter;
// span을 눌렀을때에는 filter를 반납할수 없으므로
if (filter == null) {
return;
}
//순서가 눈에 안보였다가 분류했다가 , 3초뒤 눈에보이게
projectContainer.classList.add("anim-out");
projects.forEach((project) => {
if (filter === "*" || filter === project.dataset.type) {
project.classList.remove("invisible");
} else {
project.classList.add("invisible");
}
});
projectContainer.classList.remove("anim-out");
setTimeout(() => {}, 300);
});
const workBtnContainer = document.querySelector(".work__categories");
const projectContainer = document.querySelector(".work__projects");
const projects = document.querySelectorAll(".project");
workBtnContainer.addEventListener("click", (e) => {
const filter = e.target.dataset.filter || e.target.parentNode.dataset.filter;
// span을 눌렀을때에는 filter를 반납할수 없으므로
if (filter == null) {
return;
}
projectContainer.classList.add("anim-out");
setTimeout(() => {
projects.forEach((project) => {
if (filter === "*" || filter === project.dataset.type) {
project.classList.remove("invisible");
} else {
project.classList.add("invisible");
}
});
projectContainer.classList.remove("anim-out");
}, 300);
});
javascript 비교(7) - Final touch on button state
-
Expert
-
그전에 선택된것만 지움 —> 선택자를 어떻게 적느냐고 엄청 중요할듯
-
이 코드가 핵심
const active = document.querySelector(".category__btn.selected");
- 하지만 전문가님의 코드의 문제점중 하나가 숫자를 눌렀을때는 button이 클릭되지 않는다는것이지.
const workBtnContainer = document.querySelector(".work__categories");
const projectContainer = document.querySelector(".work__projects");
const projects = document.querySelectorAll(".project");
workBtnContainer.addEventListener("click", (e) => {
const filter = e.target.dataset.filter || e.target.parentNode.dataset.filter;
// span을 눌렀을때에는 filter를 반납할수 없으므로
if (filter == null) {
return;
}
const active = document.querySelector(".category__btn.selected");
if (active != null) {
active.classList.remove("selected");
}
e.target.classList.add("selected");
//순서가 눈에 안보였다가 분류했다가 , 3초뒤 눈에보이게
projectContainer.classList.add("anim-out");
projects.forEach((project) => {
if (filter === "*" || filter === project.dataset.type) {
project.classList.remove("invisible");
} else {
project.classList.add("invisible");
}
});
setTimeout(() => {
projectContainer.classList.remove("anim-out");
}, 3000);
});
-
Yosup
-
나는 특정 부분을 지운것이 아닌 다 class를 제거해버렸네.. (불필요하다.)
const Categoires = document.querySelector(".work__categories");
const cateogriesBtns = document.querySelectorAll(".category__btn");
Categoires.addEventListener("click", (e) => {
const filter = e.target.dataset.filter || e.target.parentNode.dataset.filter;
if (filter === null) {
return;
}
if (e.target.nodeName === "BUTTON" && filter !== null) {
removeActive(); //
e.target.classList.add("active");
} else if (e.target.nodeName === "BUTTON" && filter !== null) {
removeActive();
e.target.parentNode.classList.add("active");
}
});
function removeActive() {
cateogriesBtns.forEach((btn) => {
console.log(btn);
btn.classList.remove("active");
});
}
javascript 비교(8) - Navbar toggle button
- Expert
const navbarToggle = document.querySelector(".navbar__toggle-btn");
navbarToggle.addEventListener("click", () => {
navbarMenu.classList.toggle("display");
});
- Yosup : 비슷해서 할게없음
const navbarToggle = document.querySelector(".navbar__toggle-btn");
navbarToggle.addEventListener("click", () => {
navbarMenu.classList.toggle("display");
});
Leave a comment