코딩/Javascript

[JS-중급편-이벤트] 5. 많은 요소에 대한 이벤트 처리

드리프트 2021. 3. 13. 22:12
728x170

 

 

가장 기본적인 경우 이벤트 리스너는 단일 요소에서 시작된 이벤트를 처리합니다.

 

 

 

이런 말을 처음 들었다면 잠시 시간 내어 JavaScript의 이벤트 튜토리얼을 먼저 읽으십시오.

 

cpro95.tistory.com/154?category=912319

 

[JS-중급편-이벤트] 1. 자바스크립트 이벤트

눈치채지는 못했겠지만, 대부분의 애플리케이션과 웹사이트는 가만히 있으면 그냥 그 자체로 지루합니다. 애플리케이션과 웹사트가 엄청난 팡파르와 돌풍을 일으키며 시작했지만, 우리가 그

cpro95.tistory.com

 

더 복잡한 것을 빌드할 때 "하나의 요소에 대해 하나의 이벤트 핸들러" 맵핑이 한계를 나타내기 시작합니다.

 

가장 일반적인 이유는 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 개의 요소로 이루어진 좋은 고정 수는 아닐 수 있습니다.

 

 

 

 

좋은 솔루션

 

이에 대한 좋은 솔루션은 이전에 이벤트 리스너가 하나뿐인 다이어그램을 모방한 것입니다. 

 

이것이 어떻게 작동하는지 설명함으로써 먼저 당신을 혼란스럽게 할 것입니다. 

 

그런 다음 코드를 보여주고 정확히 무슨 일이 일어나고 있는지 자세히 설명하여 혼동을 없애겠습니다. 

 

이에 대한 간단하고 혼란스러운 해결책은 다음과 같습니다.

 

  1. 부모 theDude 요소에 단일 이벤트 리스너를 만듭니다.

  2. 1 개, 2 개, 3 개, 4 개 또는 5 개 요소 중 하나를 클릭하면 이벤트가 소유하는 전파 동작에 의존하고 부모 theDude 요소에 도달할 때 이를 가로챕니다.

  3. 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 요소로 작업을 시작하면 여기서 본 모든 것을 한 번 이상 사용해야합니다.

 

그리드형