[javascript] Javascript / DOM : DOM 개체의 모든 이벤트를 제거하는 방법은 무엇입니까?

질문 : div와 같은 객체의 모든 이벤트를 완전히 제거 할 수있는 방법이 있습니까?

편집 : div.addEventListener('click',eventReturner(),false);이벤트 별로 추가 하고 있습니다.

function eventReturner() {
    return function() {
        dosomething();
    };
}

EDIT2 : 작동하지만 내 경우에 사용할 수없는 방법을 찾았습니다.

var returnedFunction;
function addit() {
    var div = document.getElementById('div');
    returnedFunction = eventReturner();
    div.addEventListener('click',returnedFunction,false); //You HAVE to take here a var and not the direct call to eventReturner(), because the function address must be the same, and it would change, if the function was called again.
}
function removeit() {
    var div = document.getElementById('div');
    div.removeEventListener('click',returnedFunction,false);
}



답변

모든 이벤트 제거가 무슨 뜻인지 잘 모르겠습니다 . 특정 유형의 이벤트에 대한 모든 처리기를 제거하거나 한 유형에 대한 모든 이벤트 처리기를 제거 하시겠습니까?

모든 이벤트 핸들러 제거

모든 이벤트 핸들러 (모든 유형)를 제거 하려면 요소를 복제 하고 복제로 바꿀 수 있습니다.

var clone = element.cloneNode(true);

참고 : 이렇게하면 속성과 자식이 유지되지만 DOM 속성에 대한 변경 사항은 유지되지 않습니다.


특정 유형의 “익명”이벤트 핸들러 제거

다른 방법은 사용하는 removeEventListener()것이지만 이미 시도했지만 작동하지 않은 것 같습니다. 여기에 캐치가 있습니다 .

addEventListener익명 함수를 호출 하면 매번 새 리스너가 생성됩니다. removeEventListener익명 함수를 호출해도 효과가 없습니다 . 익명 함수는 호출 될 때마다 고유 한 객체를 생성하지만 기존 객체에 대한 참조는 아니지만 호출 할 수 있습니다. 이러한 방식으로 이벤트 리스너를 추가 할 때는 한 번만 추가해야합니다. 추가 된 객체가 제거 될 때까지 영구적 (제거 할 수 없음)입니다.

기본적으로 익명 함수를 addEventListener로 전달하여 함수를 eventReturner반환합니다.

이 문제를 해결할 수있는 두 가지 가능성이 있습니다.

  1. 함수를 반환하는 함수를 사용하지 마십시오. 함수를 직접 사용하십시오.

    function handler() {
        dosomething();
    }
    
    div.addEventListener('click',handler,false);
    
  2. addEventListener반환 된 함수에 대한 참조를 저장 하는 래퍼를 만들고 이상한 removeAllEvents함수를 만듭니다 .

    var _eventHandlers = {}; // somewhere global
    
    const addListener = (node, event, handler, capture = false) => {
      if (!(event in _eventHandlers)) {
        _eventHandlers[event] = []
      }
      // here we track the events and their nodes (note that we cannot
      // use node as Object keys, as they'd get coerced into a string
      _eventHandlers[event].push({ node: node, handler: handler, capture: capture })
      node.addEventListener(event, handler, capture)
    }
    
    const removeAllListeners = (targetNode, event) => {
      // remove listeners from the matching nodes
      _eventHandlers[event]
        .filter(({ node }) => node === targetNode)
        .forEach(({ node, handler, capture }) => node.removeEventListener(event, handler, capture))
    
      // update _eventHandlers global
      _eventHandlers[event] = _eventHandlers[event].filter(
        ({ node }) => node !== targetNode,
      )
    }
    

    그리고 다음과 함께 사용할 수 있습니다.

    addListener(div, 'click', eventReturner(), false)
    // and later
    removeAllListeners(div, 'click')
    

데모

참고 : 코드가 오랫동안 실행되고 많은 요소를 만들고 제거하는 _eventHandlers경우 제거 할 때 포함 된 요소를 제거해야 합니다.


답변

이렇게하면 자식에서 모든 리스너가 제거되지만 큰 페이지의 경우 속도가 느려집니다. 작성하기 매우 간단합니다.

element.outerHTML = element.outerHTML;


답변

이벤트 리스너의 자체 기능을 사용합니다 remove(). 예를 들면 :

getEventListeners().click.forEach((e)=>{e.remove()})


답변

corwin.amber가 말했듯이 Webkit과 다른 웹킷 사이에는 차이점이 있습니다.

Chrome에서 :

getEventListeners(document);

기존의 모든 이벤트 리스너가있는 객체를 제공합니다.

Object
 click: Array[1]
 closePopups: Array[1]
 keyup: Array[1]
 mouseout: Array[1]
 mouseover: Array[1]
 ...

여기에서 제거하려는 리스너에 도달 할 수 있습니다.

getEventListeners(document).copy[0].remove();

따라서 모든 이벤트 리스너 :

for(var eventType in getEventListeners(document)) {
   getEventListeners(document)[eventType].forEach(
      function(o) { o.remove(); }
   )
}

Firefox에서

제거 기능이없는 리스너 래퍼를 사용하기 때문에 약간 다릅니다. 제거하려는 리스너를 가져와야합니다.

document.removeEventListener("copy", getEventListeners(document).copy[0].listener)

모든 이벤트 리스너 :

for(var eventType in getEventListeners(document)) {
  getEventListeners(document)[eventType].forEach(
    function(o) { document.removeEventListener(eventType, o.listener) }
  )
}

나는 뉴스 웹 사이트의 성가신 복사 방지를 비활성화하려는이 게시물을 우연히 발견했습니다.

즐겨!


답변

에 대한 모든 호출을 가로채는 후크 함수를 추가 할 수 있습니다 addEventHandler. 후크는 정리에 사용할 수있는 목록으로 핸들러를 푸시합니다. 예를 들면

if (EventTarget.prototype.original_addEventListener == null) {
    EventTarget.prototype.original_addEventListener = EventTarget.prototype.addEventListener;

    function addEventListener_hook(typ, fn, opt) {
        console.log('--- add event listener',this.nodeName,typ);
        this.all_handlers = this.all_handlers || [];
        this.all_handlers.push({typ,fn,opt});
        this.original_addEventListener(typ, fn, opt);
    }

    EventTarget.prototype.addEventListener = addEventListener_hook;
}

이 코드를 기본 웹 페이지 상단 근처에 삽입해야합니다 (예 🙂 index.html. 정리하는 동안 all_handler를 통해 루프를 수행하고 각각에 대해 removeEventHandler를 호출 할 수 있습니다. 동일한 함수로 removeEventHandler를 여러 번 호출하는 것에 대해 걱정하지 마십시오. 무해합니다.

예를 들면

function cleanup(elem) {
    for (let t in elem) if (t.startsWith('on') && elem[t] != null) {
        elem[t] = null;
        console.log('cleanup removed listener from '+elem.nodeName,t);
    }
    for (let t of elem.all_handlers || []) {
        elem.removeEventListener(t.typ, t.fn, t.opt);
        console.log('cleanup removed listener from '+elem.nodeName,t.typ);
    }
}

참고 : IE의 경우 EventTarget 대신 Element를 사용하고 =>를 기능 및 기타 여러 가지로 변경하십시오.


답변

답변을 완성하기 위해 다음은 웹 사이트를 방문하고 생성 된 HTML 및 JavaScript 코드를 제어 할 수 없을 때 이벤트를 제거하는 실제 사례입니다.

일부 성가신 웹 사이트는 로그인 양식에 사용자 이름을 복사하여 붙여 넣는 것을 방해하며, onpaste이벤트가 onpaste="return false"HTML 속성 으로 추가 된 경우 쉽게 우회 할 수 있습니다 . 이 경우 입력 필드를 마우스 오른쪽 버튼으로 클릭하고 Firefox와 같은 브라우저에서 “요소 검사”를 선택하고 HTML 속성을 제거하면됩니다.

그러나 이벤트가 다음과 같이 JavaScript를 통해 추가 된 경우 :

document.getElementById("lyca_login_mobile_no").onpaste = function(){return false};

JavaScript를 통해서도 이벤트를 제거해야합니다.

document.getElementById("lyca_login_mobile_no").onpaste = null;

내 예에서는 방문한 웹 사이트에서 사용하는 텍스트 입력 ID이므로 ID “lyca_login_mobile_no”를 사용했습니다.

이벤트를 제거하는 또 다른 방법 (모든 이벤트도 제거됨)은으로 제거 addEventListener할 수없는 익명 함수를 사용하여 이벤트를 추가하는 데 사용 된 경우 수행해야하는 것처럼 노드를 제거하고 새 노드를 만드는 것 입니다 removeEventListener. 요소를 검사하고, HTML 코드를 복사하고, HTML 코드를 제거한 다음 동일한 위치에 HTML 코드를 붙여 넣어 브라우저 콘솔을 통해이 작업을 수행 할 수도 있습니다.

또한 JavaScript를 통해 더 빠르고 자동화 될 수 있습니다.

var oldNode = document.getElementById("lyca_login_mobile_no");
var newNode = oldNode.cloneNode(true);
oldNode.parentNode.insertBefore(newNode, oldNode);
oldNode.parentNode.removeChild(oldNode);

업데이트 : Angular와 같은 JavaScript 프레임 워크를 사용하여 웹 앱을 만든 경우 이전 솔루션이 작동하지 않거나 앱이 중단되는 것으로 보입니다. 붙여 넣기를 허용하는 또 다른 해결 방법은 JavaScript를 통해 값을 설정하는 것입니다.

document.getElementById("lyca_login_mobile_no").value = "username";

현재로서는 Angular와 같이 JavaScript로 작성된 앱을 완전히 중단하지 않고 모든 양식 유효성 검사 및 제한 이벤트를 제거 할 수있는 방법이 있는지 모르겠습니다.


답변

angular에는이 문제에 대한 polyfill이 있습니다. 나는 많이 이해하지 못했지만 도움이 될 수 있습니다.

const REMOVE_ALL_LISTENERS_EVENT_LISTENER = ‘모든 리스너 제거’;

    proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () {
        const target = this || _global;
        const eventName = arguments[0];
        if (!eventName) {
            const keys = Object.keys(target);
            for (let i = 0; i < keys.length; i++) {
                const prop = keys[i];
                const match = EVENT_NAME_SYMBOL_REGX.exec(prop);
                let evtName = match && match[1];
                // in nodejs EventEmitter, removeListener event is
                // used for monitoring the removeListener call,
                // so just keep removeListener eventListener until
                // all other eventListeners are removed
                if (evtName && evtName !== 'removeListener') {
                    this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);
                }
            }
            // remove removeListener listener finally
            this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
        }
        else {
            const symbolEventNames = zoneSymbolEventNames$1[eventName];
            if (symbolEventNames) {
                const symbolEventName = symbolEventNames[FALSE_STR];
                const symbolCaptureEventName = symbolEventNames[TRUE_STR];
                const tasks = target[symbolEventName];
                const captureTasks = target[symbolCaptureEventName];
                if (tasks) {
                    const removeTasks = tasks.slice();
                    for (let i = 0; i < removeTasks.length; i++) {
                        const task = removeTasks[i];
                        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
                        this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
                    }
                }
                if (captureTasks) {
                    const removeTasks = captureTasks.slice();
                    for (let i = 0; i < removeTasks.length; i++) {
                        const task = removeTasks[i];
                        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
                        this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
                    }
                }
            }
        }
        if (returnTarget) {
            return this;
        }
    };

….