[JS]scrollIntoView event handlers, bubbling & capturing, event delegation, DOM traversing
コースソース:完全JavaScript Course 2022 Jonas(Udemy)
Implementing Smooth Scrolling
スクロールに関する良い情報を理解します. getBoundingClientRect() : relative to visible viewport window.screen: ディスプレイサイズ window.outer:page以外のブラウザの合計サイズ(url+tab+page) window.inner:スクロールバー付きビューポート document.documentElement.clientHeight, document.documentElement.ClientWidth:ビューポートの高さと幅.スクロールバー は含む. window.pageXOffset, window.pageYOffset:viewportの末尾で、ページ上部の長さは です.
scrollIntoView()
addEvenetListener, removeEventListener
イベント発生原理
イベントが発生した場合は、要素ではなく一番上のDocumentに渡されます.取得フェーズ:ドキュメントからターゲットフェーズの親要素からターゲットの部分まで. targetフェーズ:イベントが発生したtarget上でコールバック関数を実行します. バブルフェーズ:targetから親要素に再移行し、最初のイベントからドキュメントの部分に移行します.このセクションでは、親要素にtargetと同じイベントがある場合、一緒に発生します.親コンテナは、イベントがどのサブエレメントで発生しても、すべてのイベントをリスニングできます. Event Propagation in Practice
rgb(255, 255, 255); ランダムカラー関数の作成
=> Event propagation
this==e.currentTarget/e.targetとは、実際にイベントが発生した要素です.泡が立つから.navのイベントが発生しても、e.targetは.nav linkを指します!
Event Delegation
Implementing Page Navigation by using Event Delegation
委任イベントの利点
同じイベントを複数の要素で実行する必要がある場合は、=>共通の親要素でイベント(委任)を実行することによって一貫した関数を作成することを省略できます.すなわち、繰り返しのイベントを処理する場合、すなわち、親の子供がイベントを共同で処理する必要がある場合、イベントリスナーを毎日サブノードに追加するよりも、親に登録するほうがよい.
イベント委任ロジック Add event listener to common parent element Determine what element originated the event Matching strategy => if(element.classList.contains('')){}
DOM Traversing
DOM Traversing : walking through the DOM, we can select an element based on another element
Going downwards : child
querySelector
closest
Going side ways : siblings
Implementing Smooth Scrolling
スクロールに関する良い情報を理解します.
scrollIntoView()
const btnScrollTo = document.querySelector('.btn--scroll-to');
const section1 = document.querySelector('#section--1');
btnScrollTo.addEventListener('click', e => {
const s1coords = section1.getBoundingClientRect();
console.log(s1coords);
console.log(e.target.getBoundingClientRect());
console.log('Current scroll (X/Y)', window.pageXOffset, window.pageYOffset);
console.log(
'height/width viewport',
document.documentElement.clientHeight,
document.documentElement.clientWidth
);
//scrolling
window.scrollTo(
s1coords.left + window.pageXOffset,
s1coords.top + window.pageYOffset
);
window.scrollTo({
left: s1coords.left + window.pageXOffset,
top: s1coords.top + window.pageYOffset,
behavior: 'smooth',
});
// modern way
section1.scrollIntoView({ behavior: 'smooth' });
});
Types of Events and Event HandlersaddEvenetListener, removeEventListener
const h1 = document.querySelector('h1');
const alertH1 = e => {
alert('addEventListener : Great! You are reading the heading :D');
h1.removeEventListener('mouseenter', alertH1); //event 가 한번만 실행되고 제거된다.
};
h1.addEventListener('mouseenter', alertH1);
setTimeout(() => h1.removeEventListener('mouseenter', alertH1), 3000);
//old way
h1.onmouseenter = e => {
alert('addEventListener : Great! You are reading the heading :D');
};
Event Propagation : Bubbling and Capturingイベント発生原理
イベントが発生した場合は、要素ではなく一番上のDocumentに渡されます.
rgb(255, 255, 255); ランダムカラー関数の作成
const randomInt = (min, max) =>
Math.floor(Math.random() * (max - min + 1) + min);
const randomColor = () =>
`rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
document.querySelector('.nav__link').addEventListener('click', function (e) {
this.style.backgroundColor = randomColor();
console.log('LINK', e.target, e.currentTarget);
// Stop propogation 사용하지 않는게 좋음
//e.stopPropagation(); //bubbling 일어나지 않음
});
document.querySelector('.nav__links').addEventListener('click', function (e) {
this.style.backgroundColor = randomColor();
console.log('CONTAINER', e.target, e.currentTarget);
});
document.querySelector('.nav').addEventListener(
'click',
function (e) {
this.style.backgroundColor = randomColor();
console.log('NAV', e.target, e.currentTarget);
},
true // event handling이 bubbling을 멈추고 capturing event 시작한다.
// capturing phase : nav -> link -> container 순서로 event 발생 (nav는 capturing, 나머지 둘은 bubbling phase 이므로)
);
「.navlink」イベントを実行するときに親要素として使用します.およびnavlinksnavはすべて実行されます.=> Event propagation
this==e.currentTarget/e.targetとは、実際にイベントが発生した要素です.泡が立つから.navのイベントが発生しても、e.targetは.nav linkを指します!
Event Delegation
Implementing Page Navigation by using Event Delegation
委任イベントの利点
同じイベントを複数の要素で実行する必要がある場合は、=>共通の親要素でイベント(委任)を実行することによって一貫した関数を作成することを省略できます.すなわち、繰り返しのイベントを処理する場合、すなわち、親の子供がイベントを共同で処理する必要がある場合、イベントリスナーを毎日サブノードに追加するよりも、親に登録するほうがよい.
イベント委任ロジック
document.querySelector('.nav__links').addEventListener('click', e => {
e.preventDefault();
// Matching strategy
if (e.target.classList.contains('nav__link')) {
const id = e.target.getAttribute('href');
if (id === '#') {
return;
}
document.querySelector(id).scrollIntoView({ behavior: 'smooth' });
}
});
注)link href='#id'=>は、対応するIDを使用して自動的にスクロールする基本機能を備えています.DOM Traversing
DOM Traversing : walking through the DOM, we can select an element based on another element
Going downwards : child
querySelector
const h1 = document.querySelector('h1');
console.log(h1.querySelectorAll('.highlight'));
console.log(h1.childNodes);
//NodeList(9) [text, comment, text, span.highlight, text, br, text, span.highlight, text]
// Nodes can be anything!
console.log(h1.children); //HTMLCollection(3) [span.highlight, br, span.highlight]
h1.firstElementChild.style.color = 'white';
h1.lastElementChild.style.color = 'orangered';
Going upwards : parentsclosest
console.log(h1.parentNode); //<div class="header__title">...</div>
console.log(h1.parentElement); //<div class="header__title">...</div>
//closest(selectors) 지정한 선택자와 가장 가깝게 조건에 만족한 부모요소가 반환된다.
h1.closest('.header').style.background = 'var(--gradient-secondary)';
// header에 가장 가까운 h1의 부모요소에 효과 적용된다.
h1.closest('h1').style.background = 'var(--gradient-primary)';
// h1 그 자체
最も近いのはquerySelectorとは全く逆の概念と考えられる.どちらもセレクタが受信されますが、querySelectorはchild elementを選択し、最近のparent elementを選択します.Going side ways : siblings
console.log(h1.previousElementSibling); //바로 전 sibling elememnt
console.log(h1.nextElementSibling); // 바로 다음 sibling element
console.log(h1.previousSibling); //바로 전 sibling node
console.log(h1.nextSibling); //바로 다음 sibling node
console.log(h1.parentElement.children); // h1을 포함한 모든 siblings 출력.
[...h1.parentElement.children].forEach(function (el) {
if (el !== h1) el.style.transform = 'scale(0.5)';
});
Tabbed componenttabsContainer.addEventListener('click', e => {
const clicked = e.target.closest('.operations__tab'); //span 부분을 눌러도 button 선택된다!
//Guard clause -modern way (빠른 return)
if (!clicked) return;
// Remove active classes
tabs.forEach(t => t.classList.remove('operations__tab--active'));
// 흔한 logic! 하나의 element에만 classList를 추가하고 싶다면 추가 전에 모든 요소의 classList clear 해주기!
tabsContent.forEach(c => c.classList.remove('operations__content--active'));
//Active tab
clicked.classList.add('operations__tab--active');
//Active content area
document
.querySelector(`.operations__content--${clicked.dataset.tab}`)
.classList.add('operations__content--active');
});
Reference
この問題について([JS]scrollIntoView event handlers, bubbling & capturing, event delegation, DOM traversing), 我々は、より多くの情報をここで見つけました https://velog.io/@hoje15v/scrollIntoView-types-of-events-event-handlers-bubbling-capturing-event-delegationテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol