가장 기본적인 경우 이벤트 리스너는 단일 요소에서 시작된 이벤트를 처리합니다.
이런 말을 처음 들었다면 잠시 시간 내어 JavaScript의 이벤트 튜토리얼을 먼저 읽으십시오.
cpro95.tistory.com/154?category=912319
더 복잡한 것을 빌드할 때 "하나의 요소에 대해 하나의 이벤트 핸들러" 맵핑이 한계를 나타내기 시작합니다.
가장 일반적인 이유는 JavaScript를 사용하여 동적으로 요소를 만드는 데 있습니다.
생성중인 이러한 요소는 수신하고 반응할 수 있는 이벤트를 발생시킬 수 있으며, 이벤트 지원이 필요한 소수의 요소부터 이벤트를 처리해야 하는 많은 요소에 이르기까지 어디에서나 가질 수 있습니다.
우리가 원하지 않는 것은 다음과 같습니다.
각 요소에 대해 이벤트 리스너를 생성하고 싶지 않습니다.
그 이유는 그것이 비효율적이기 때문입니다.
이러한 요소는 많은 콘텐츠가 있을 때 실제로 메모리 사용량을 합산 할 수 있는 이벤트 리스너 및 해당 속성에 대한 데이터를 전달합니다.
대신, 당신이 원하는 것은 최소한의 중복과 불필요한 것들로 여러 요소에서 이벤트를 처리하는 깨끗하고 빠른 방법입니다.
당신이 원하는 것은 다음과 같이 보일 것입니다.
이 모든 것이 약간 이상하게 들릴 수 있습니다.
이 튜토리얼에서는 JavaScript를 사용하여 이것을 구현하는 방법에 대해 모든 것을 배울 것입니다.
이상적이지 않은 솔루션
여기에 우리가 원하지 않는 것이 있습니다.
다음 버튼 각각에 대해 5 개의 이벤트 리스너를 원하지 않습니다.
var oneElement = document.querySelector("#one");
var twoElement = document.querySelector("#two");
var threeElement = document.querySelector("#three");
var fourElement = document.querySelector("#four");
var fiveElement = document.querySelector("#five");
oneElement.addEventListener("click", doSomething, false);
twoElement.addEventListener("click", doSomething, false);
threeElement.addEventListener("click", doSomething, false);
fourElement.addEventListener("click", doSomething, false);
fiveElement.addEventListener("click", doSomething, false);
function doSomething(e) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
소개에서 언급 한 내용을 반영하기 위해 명백한 이유는 코드를 복제하고 싶지 않기 때문입니다.
또 다른 이유는 이러한 각 요소에 이제 addEventListener 속성이 설정되어 있기 때문입니다.
이것은 다섯 가지 요소에 대해 큰 문제가 아닙니다.
적은 양의 메모리를 차지하는 수십 또는 수백 개의 요소가 있으면 큰 문제가 되기 시작합니다.
또 다른 이유는 UI가 실제로 얼마나 적응 적이거나 동적인지에 따라 요소 수가 달라질 수 있다는 것입니다.
이 인위적인 예에서와 같이 5 개의 요소로 이루어진 좋은 고정 수는 아닐 수 있습니다.
좋은 솔루션
이에 대한 좋은 솔루션은 이전에 이벤트 리스너가 하나뿐인 다이어그램을 모방한 것입니다.
이것이 어떻게 작동하는지 설명함으로써 먼저 당신을 혼란스럽게 할 것입니다.
그런 다음 코드를 보여주고 정확히 무슨 일이 일어나고 있는지 자세히 설명하여 혼동을 없애겠습니다.
이에 대한 간단하고 혼란스러운 해결책은 다음과 같습니다.
-
부모 theDude 요소에 단일 이벤트 리스너를 만듭니다.
-
1 개, 2 개, 3 개, 4 개 또는 5 개 요소 중 하나를 클릭하면 이벤트가 소유하는 전파 동작에 의존하고 부모 theDude 요소에 도달할 때 이를 가로챕니다.
-
DOM 트리를 위아래로 모호하게 실행되는 이벤트를 처리할 필요가 없도록 부모 요소에서 이벤트 전파를 중지합니다.
세 단계를 읽은 후 확실히 혼란스럽습니다!
이러한 단계를 더 시각적으로 설명하는 다이어그램으로 혼동하지 않도록 하겠습니다.
이해를 막는 마지막 단계는 다이어그램과 위의 세 단계가 무엇을 뜻하는지 이해하는 겁니다.
var theParent = document.querySelector("#theDude");
theParent.addEventListener("click", doSomething, false);
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}
잠시 시간을 내어 여기에 표시된 코드를 읽고 이해하십시오.
초기 목표와 다이어그램을 본 후에는 꽤 자명해야 합니다.
부모 theDude 요소에서 이벤트를 수신합니다.
var theParent = document.querySelector("#theDude");
theParent.addEventListener("click", doSomething, false);
이벤트 리스너는 하나뿐이며 여기서 눈여겨볼 거는 doSomething입니다.
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}
이 이벤트 리스너는 클릭되는 모든 하위 요소와 함께 theDude 요소를 클릭할 때마다 호출됩니다.
우리는 하위 요소와 관련된 클릭 이벤트에만 관심이 있으며, 이 상위 요소에 대한 클릭을 무시하는 적절한 방법은 클릭이 발생한 요소 (일명 이벤트 대상)가 이벤트 리스너 대상과 동일한 경우 코드 실행을 피하는 것입니다. (일명 theDude 요소) :
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}
이벤트의 대상은 e.target으로 표시되고 이벤트 리스너가 연결된 대상 요소는 e.currentTarget으로 표시됩니다.
이러한 값이 같지 않은지 확인하기 만하면 이벤트 처리기가 관심 없는 부모 요소에서 발생한 이벤트에 반응하지 않는지 확인할 수 있습니다.
이벤트 전파를 중지하려면 stopPropagation 메서드를 호출하기 만하면 됩니다.
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}
이 코드는 실제로 내 if 문 외부에 있습니다.
이는 이벤트가 일단 우연히 들리면 모든 상황에서 DOM 순회를 중지하기를 원하기 때문입니다.
함께 모아서
이 모든 코드 실행의 최종 결과는 theDude의 자식을 클릭하고 이벤트가 전파되는 동안 수신할 수 있다는 것입니다.
모든 이벤트 인수가 여전히 이벤트의 소스에 연결되어 있으므로 상위에서 addEventListener를 호출하더라도 이벤트 핸들러에서 클릭된 요소를 대상으로 지정할 수 있습니다.
이 솔루션에 대해 언급해야 할 주요 사항은 우리가 피하려고 설정 한 문제를 충족한다는 것입니다.
이벤트 리스너를 하나만 만들었습니다.
theDude가 얼마나 많은 자녀를 낳는지는 중요하지 않습니다.
이 접근 방식은 코드를 추가로 수정하지 않고도 모두를 수용할 수 있을 만큼 일반적입니다.
또 다른 끔찍한 해결책
한동안 저는 실제로 비효율적이지만 여러 줄의 코드를 복제할 필요가 없는 다중 요소 이벤트 수수께끼에 대한 솔루션을 제안했습니다.
많은 사람들이 그것의 비 효율성을 지적하기 전에 나는 그것이 유효한 해결책이라고 생각했습니다.
이 솔루션이 작동하는 방식은 for 루프를 사용하여 이벤트 리스너를 부모 (또는 HTML 요소를 포함하는 배열)의 모든 자식에 연결하는 것입니다.
코드는 다음과 같습니다.
var theParent = document.querySelector("#theDude");
for (var i = 0; i < theParent.children.length; i++) {
var childElement = theParent.children[i];
childElement.addEventListener('click', doSomething, false);
}
function doSomething(e) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
최종 결과는 이 접근 방식을 통해 자식에서 직접 클릭 이벤트를 수신할 수 있게 되었습니다.
내가 수동으로 작성한 유일한 코드는 루프에서 코드가 있는 위치를 기반으로 적절한 자식 요소에 매개 변수화 된 단일 이벤트 리스너 호출입니다.
childElement.addEventListener('click', doSomething, false);
이 접근 방식이 좋지 않은 이유는 각 하위 요소에 이벤트 리스너가 연결되어 있기 때문입니다.
이것은 이 접근법이 불필요하게 메모리를 낭비하는 효율성 주장으로 돌아갑니다.
이제 요소가 근처에 공통 부모 없이 DOM 전체에 분산되는 상황이 있는 경우 HTML 요소 배열에 이 접근 방식을 사용하는 것이 MEEC 문제를 해결하는 나쁜 방법이 아닙니다.
결론
게임, 데이터 시각화 앱 및 기타 HTMLElement가 풍부한 항목을 위한 많은 양의 UI 요소로 작업을 시작하면 여기서 본 모든 것을 한 번 이상 사용해야합니다.
'코딩 > Javascript' 카테고리의 다른 글
[JS-중급편-이벤트] 7. 커스텀 이벤트 (0) | 2021.04.14 |
---|---|
[JS-중급편-이벤트] 6. 키보드 이벤트 (0) | 2021.03.22 |
[JS-중급편-이벤트] 4. 코드 실행의 최적시간 (0) | 2021.03.06 |
[JS-중급편-이벤트] 3. 마우스 이벤트 (0) | 2021.02.07 |
[JS-중급편-이벤트] 2. 이벤트 캡쳐링, 버블링 (0) | 2021.02.01 |