강의 출처 : The Complete JavaScript Course 2022 Jonas (Udemy)
event handler에 event 이외의 추가 인자를 넣어야하는 상황 해결하기 + Refactoring 꿀팁(흔한 로직)
- 반복적인 코드를 함수로 만든다.
- 반복되지 않는 부분을 인자로 받는다. ex) opacity
but! eventHandler 함수는 e 만을 인자로 받음!
callback 함수를 bind로 묶어주고 그 안의 인자에 opacity넣어주기. bind함수는 그 인자에 this를 부여한다.
Menu fade animation
const handleHover = function (e) {
if (e.target.classList.contains('nav__link')) {
const link = e.target;
const siblings = link.closest('.nav').querySelectorAll('.nav__link');
const logo = link.closest('.nav').querySelector('img');
siblings.forEach(el => {
if (el !== link) {
el.style.opacity = this;
}
logo.style.opacity = this;
});
}
};
//Passing "argument" into handler
nav.addEventListener('mouseover', handleHover.bind(0.5));
nav.addEventListener('mouseout', handleHover.bind(1));
Implementing a Sticky Navigation
const initialCoords = section1.getBoundingClientRect();
window.addEventListener('scroll', e => {
//console.log(window.scrollY); //viewport의 top에서 page의 top까지
if (window.scrollY > initialCoords.top) {
nav.classList.add('sticky');
} else {
nav.classList.remove('sticky');
}
});
참고) scroll event는 되도록 쓰지 않는 것이 좋음. 너무 빈번하게 일어나므로.
entries : an array of threshold 로 볼 수도 있음.
const obsCallback = function (entries, observer) {
entries.forEach(entry => console.log(entry));
};
const obsOptions = {
root: null, //null : entire view port. root : intersecting 하고 싶은 target
threshold: [0, 0.2], //view port의 percent => 이 percent 이상으로 intersecting 하면 callback 함수를 실행한다.
rootMargin : '10px' //visual margin of root(target element).
};
const observer = new IntersectionObserver(obsCallback, obsOptions);
observer.observe(section1);
const header = document.querySelector('.header');
const navHeight = nav.getBoundingClientRect().height;
const stickyNav = function (entries) {
const [entry] = entries; // = entry = entries[0] destructuring
if (!entry.isIntersecting && entry.intersectionRatio === 0) {
nav.classList.add('sticky');
} else {
nav.classList.remove('sticky');
}
};
const headerObserver = new IntersectionObserver(stickyNav, {
root: null,
threshold: 0,
rootMargin: `-${navHeight}px`,
});
headerObserver.observe(header);
The Intersection Observer API를 이용하여 스크롤 할 때마다 해당 section별 효과 주기
const allSections = document.querySelectorAll('.section');
const revealSection = function (entries, observer) {
const [entry] = entries; // threshold 하나만 있으므로.
if (!entry.isIntersecting) return;
entry.target.classList.remove('section--hidden');
sectionObserver.unobserve(entry.target); // 한번만 실행하고자. 더이상 관찰할 이유가 없음.
};
const sectionObserver = new IntersectionObserver(revealSection, {
root: null,
threshold: 0.15,
});
allSections.forEach(section => {
sectionObserver.observe(section);
section.classList.add('section--hidden');
});
The Intersection Observer API를 이용하여 이미지 로딩 기능 구현하기
Lazy loading images
const imgTargets = document.querySelectorAll('img[data-src]');
const loadImg = function (entries, observer) {
const [entry] = entries;
console.log(entry);
if (!entry.isIntersecting) return;
//Replace src with data-src
entry.target.src = entry.target.dataset.src;
entry.target.addEventListener('load', () => {
entry.target.classList.remove('lazy-img');
// img가 다 load 된 다음에 실행시키는 것이 좋다.
//느린 컴퓨터에서는 src가 바뀌기도 전에 blur 가 없어지기도 하므로,,
});
observer.unobserve(entry.target);
};
const imgObserver = new IntersectionObserver(loadImg, {
root: null,
threshold: 0,
rootMargin: '200px',
});
imgTargets.forEach(img => imgObserver.observe(img));
이미지의 src를 대체한 후 load event를 실행시켜주는 점 기억할 것! 이미지가 다 load된 후 효과주기 위해.