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


97

질문 : 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);
}

이벤트를 어떻게 첨부합니까?
Felix Kling

2
제목은 개체 의 요소 에 대해 묻는 반면 실제 질문은 이벤트 에 대해 묻습니다 . 하위 요소 또는 이벤트를 제거 하시겠습니까?
Pär Wieslander 2010

오 D * 미네소타, 나는이에 대한 배려 해요 것을 ... 쓸 때 내가 다른 뭔가 생각해 봤는데 원인이었다 그 이벤트
플로리안 뮐러을

정확한 경우를 모르지만 경우에 따라 해결 방법으로 항상 단일 리스너에서 작동하고 div.onclick=null. 물론 addEventListener이 경우에는 .NET의 리스너와 다른 별도의 리스너를 추가하므로 함께 사용해서는 안됩니다 onclick.
venimus

답변:


107

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

모든 이벤트 핸들러 제거

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

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경우 제거 할 때 포함 된 요소를 제거해야 합니다.


@Florian : 확실히 코드는 개선 될 수 있지만 아이디어를 제공해야합니다 ... 즐거운 코딩!
Felix Kling

2
둘 이상의 div 요소로 이것을 시도 했습니까? 노드 var는 실제로 문자열로 변환됩니다. 예를 들어 '[object HTMLDivElement]'는 모든 것을 동일한 노드에 추가한다는 의미입니다.
cstruter

@cstruter : 맞아요 ... 이건 자바 스크립트 초창기 였는데 ... 시간이 더 있으면 코드를 수정하겠습니다. 알려 줘서 고마워.
Felix Kling 2012

나는 오타가있는 것 같아요,의 addListener는 addEvent해야한다
AGamePlayer

참고 element.parentNode널 (null)이 될 수 있습니다. 위의 코드 주변에 if 체크를 넣어야합니다.
thecoolmacdude apr

43

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

element.outerHTML = element.outerHTML;

2
좋은 대답입니다. 리프 노드의 경우 이것이 가장 좋은 아이디어 인 것 같습니다.
user3055938

3
document.querySelector('body').outerHTML = document.querySelector('body').outerHTML나를 위해 일했습니다.
라이언

3
대신 @Ryan document.querySelector('body').outerHTML당신은 입력 할 수 있습니다document.body.outerHTML
제이 Dadhania

29

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

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

2
이것이 정답이 아닌 이유가 확실하지 않습니다. 질문은 SO에서 여러 번 나타나며 복제 방법을 사용하여 문제를 해결할 수 있습니다.
jimasun 2016

42
getEventListenersWebKit 개발 도구와 FireBug에서만 사용할 수있는 것 같습니다 . 코드에서 호출 할 수있는 것은 아닙니다.
corwin.amber

1
이 작업을 수행하는 데 문제가있는 경우 개체를에 인수로 전달합니다 getEventListeners(). 예 : getEventListeners(document)또는getEventListeners(document.querySelector('.someclass'))
Luke

10
이것은 크롬 콘솔 에서만 작동하는 것 같습니다 . 페이지의 스크립트에서도 작동하지 않습니다.
Reuel Ribeiro

4
getEventListeners(document).click.forEach((e)=>{e.remove()})이 오류를 생성합니다.VM214:1 Uncaught TypeError: e.remove is not a function
Ryan

11

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) }
  ) 
}

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

즐겨!


이는 모든 리스너를 제거하지 않고 문서 노드에서 특정 리스너를 제거하는 경우와 같이 리스너 제거를 대상으로하는 경우에 가장 적합한 답변입니다.
Trevor

이것은 잘 작동하고 최선의 대답입니다. @Jmakuc 감사합니다.
Thavamani Kasi

5
Firefox가 getEventListeners정의되지 않았다고 알려줍니다 .
rovyko

현재 getEventListeners는 Chrome에서만 지원되기 때문에 이는 좋지 않은 솔루션입니다.
Michael Paccione

1

에 대한 모든 호출을 가로채는 후크 함수를 추가 할 수 있습니다 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를 사용하고 =>를 기능 및 기타 여러 가지로 변경하십시오.


0

답변을 완성하기 위해 다음은 웹 사이트를 방문하고 생성 된 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로 작성된 앱을 완전히 중단하지 않고 모든 양식 유효성 검사 및 제한 이벤트를 제거 할 수있는 방법이 있는지 모르겠습니다.


0

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;
        }
    };

....


어디 EVENT_NAME_SYMBOL_REGX에서 오는 거죠?
Elias Zamaria

0

예를 들어 이벤트 리스너를 지우는 도우미 함수를 추가 할 수 있습니다.

function clearEventListener(element) {
 const clonedElement = element.cloneNode(true);
element.replaceWith(clonedElement);
return clonedElement;
}

요소를 함수에 전달하기 만하면됩니다.


-1
var div = getElementsByTagName('div')[0]; /* first div found; you can use getElementById for more specific element */
div.onclick = null; // OR:
div.onclick = function(){};

//편집하다

이벤트 첨부에 어떤 방법을 사용하고 있는지 몰랐습니다. 들어 addEventListener당신이 사용할 수 있습니다 :

div.removeEventListener('click',functionName,false); // functionName is the name of your callback function

자세한 내용


1
내가 그것을 좋아하는 설정하면 div.onClick = something다음 내가 이전에 가지고 예를 들어, 널 (null) 하나 그래서 ... 다른 이벤트 onclick을하지만, 이전의 숙박을 설정
플로리안 뮐러

1
를 통해 핸들러를 추가하면 작동하지 않습니다 addEventListener().
Felix Kling

@Florian : 사실이 아닙니다. 이벤트 핸들러를 추가하는이 방법을 사용하는 경우 이벤트에 대해 하나의 핸들러 만 가질 수 있습니다 . 하지만 사용하면 차이가납니다 addEventListener()...
Felix Kling 2010-12-08

하지만 이렇게 봤기 때문에 이전 함수를 다시 추가하면 두 번 호출됩니다. Felix King이 말했듯이 이것은 addEventListener에서 작동하지 않습니다 ...
Florian Müller

-1

다음과 같은 작업을 수행하면 브라우저가 자동으로 수행 할 수 있습니다.

div및 해당 속성을 복사하고 이전 속성 앞에 삽입 한 다음 콘텐츠를 이전 항목에서 새 항목으로 이동하고 이전 항목을 삭제 하시겠습니까?


이제 그것은 실제로 좋은 생각이지만 완전히 성능이 떨어집니다. 만약 1'000에서 1'000'000 사이의 엄청난 양의 div를 위해 이것을해야한다면 ... 예, 그것은 큰 프로젝트입니다;)
Florian Müller

6
한 페이지에 1M div? 이 문제 전에 다른 문제가 발생합니다.) 이벤트 위임을 사용할 수 있습니다 ...
Mic

-1

의 모든 이벤트 제거document :

짧막 한 농담:

for (key in getEventListeners(document)) { getEventListeners(document)[key].forEach(function(c) { c.remove() }) }

예쁜 버전 :

for (key in getEventListeners(document)) {
  getEventListeners(document)[key].forEach(function(c) {
    c.remove()
  })   
}

-1

Chrome 만

Protractor 테스트 내에서 EventListener를 제거하려고하는데 테스트에서 Listener에 대한 액세스 권한이 없으므로 다음은 단일 유형의 모든 이벤트 리스너를 제거하기 위해 작동합니다.

function(eventType){
    getEventListeners(window).[eventType].forEach(
        function(e){
            window.removeEventListener(eventType, e.listener)
        }
    );
}

나는 이것이 이전 답변이 더 이상 작동하지 않는 "제거"방법을 사용했기 때문에 누군가에게 도움이되기를 바랍니다.


-1

한 가지 방법은 e.stopImmediatePropagation ()을 호출하는 새 이벤트 리스너를 추가하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.