1

내가 재사용 가능한 사용자 지정 드롭 다운 메뉴를 가지고JS - 문서에 청취자가 너무 많습니까?

설치, 거친 프레임 워크는 무엇인가 같다 :

var List = (function() { 

    // Custom list prototype stuffs... 

    function ListObj(el, options) {  
     this._init(el); 
    } 

    ListObj.prototype._init = function(el) { 
     var self = this; 
     self.menu = el; 
    } 

    // Expose an init function 
    return { 
     init : function(el, options) { 
      new ListObj(el, options); 
     } 
    }; 

})(); 

그리고 각 메뉴는 같은으로 초기화됩니다 :

var ddlist = document.querySelector('.ddlist'); 
DDList.init(ddlist, options); 

이 모두 예상대로 작동합니다. 나는 각 메뉴가 가지고 싶습니다

한 동작을 원하는 것은

는 클릭이 그 메뉴 자체 내에 있지 발생하면 자동으로을 최소화 이다. 내가 대신 각 메뉴를 추가하고 확인하는 데 다음 문서에 대한 한 번의 클릭 리스너를 가진, 그리고

한 적이 무엇

클릭, 나는 문서를 클릭 리스너를 추가하기로 결정했습니다 된 곳 위의 _init 메소드 내 :

ListObj.prototype._init = function(el) { 
    var self = this; 
    self.menu = el; 

    document.addEventListener('click', function(e) { 
     var el = e.target; 

     if(self.menu === el || self.menu.contains(el)) { 
      // Click was inside menu 
      // Perform whatever tasks 
     }else { 
      // Click was outside of (this) menu, so minimize 
      self.menu.minimize(); 
     } 
    }); 

} 

이러한 방식으로, 각각의 메뉴가 자동으로 문서 클릭을 모니터링하고 중 하나를 클릭하여 메뉴에없는 경우 최소화, 또는 필요 어떤 작업을 수행 할 수있는 행동으로 초기화됩니다.

완벽하게 작동합니다. 나에게 특히 흥미로운 점은 문서 클릭 리스너에 추가 할 필요없이 새로운 드롭 다운 메뉴를 동적으로 만들 수 있으며 event.stopPropagation(); (나는 발을 자르지 않고)과 싸울 필요가 없다는 것입니다.

하지만 컴퓨터가 폭발할까요?

이것은 모두 단일 페이지 웹 응용 프로그램입니다. 즉, 수십 또는 수백 개의 메뉴를 만들거나 제거 할 수 있습니다. 내 모든 우려는 이러한 문서의 클릭 수신기가 겹쳐서 성능 문제를 일으킬 것이라는 점입니다.

내가 할 경우 뭔가처럼 ...

document.getElementById('someMenu').remove(); 

은 JS의 가비지 컬렉션이 멀리 하나의 문서를 클릭 리스너를 할 수 있음을 알 수 있습니까? 아니면 듣는 사람이 끝날 때까지 지속될 것입니까? 후자의 경우 메뉴 제거시 해당 특정 수신기를 제거 할 수있는 방법이 있습니까?

중요한 것은 메뉴가 절대 제거되지 않지만 부모가 제거된다는 것입니다. 따라서 .remove()은 메뉴에서 직접 작동하지 않습니다.

감사합니다.

그냥 테스트

은 ...

나는 두 가지 메뉴를 생성하고 그 중 하나 (.remove()를) 삭제. 하나의 메뉴가 제거되었지만 그 안에있는 문서 클릭 수신기는 모든 클릭에 대해 계속 실행됩니다.이것은 가비지 콜렉션이 이 아니고이 처리되지 않는다고 제안하는 것으로 보이며, 나는 수많은 리스너로 끝날 것입니다.

그럼 이제 어떻게해야합니까?

+0

문서에 이벤트 수신기를 추가하면 해당 수신기는 수신기를 만든 개체 (콜백 포함)가 제거 된 경우에도 기존 수신기를 유지합니다. 가장 깨끗한 해결책은'document.removeEventListener'를 사용하여 메뉴를 제거하기 전에 리스너를 제거하는 것입니다. 또한 리스너를 메뉴의 dom 요소에 바인딩 할 수 있습니다. 그런 다음 메뉴를 제거하면 청취자도 제거됩니다. 마지막 옵션으로 문서에 하나의 청취자 만있을 수 있으며, 문서를 클릭하면 모든 메뉴를 반복하여 닫도록 지시합니다. – Kokodoko

+0

* 속보 *! 컴퓨터가 심하게 프로그래밍 된 웹 페이지로 인해 폭발하며 자세한 내용을 확인하십시오. – epascarello

답변

1

함수에 이름을 지정하면 이벤트 수신기를 제거 할 수 있습니다.

ListObj.prototype._init = function(el) { 
    var self = this; 
    self.menu = el; 
    self.click_handler = function(e) { 
     var el = e.target; 
     if (!document.contains(self.menu)) { // This element has been removed from DOM 
      document.removeEventListener("click", self.click_handler); 
      return; 
     } 
     if(self.menu === el || self.menu.contains(el)) { 
      // Click was inside menu 
      // Perform whatever tasks 
     }else { 
      // Click was outside of (this) menu, so minimize 
      self.menu.minimize(); 
     } 
    }; 
    document.addEventListener("click", self.click_handler); 

} 
+0

완벽! 이것은 정확히 내가 찾고 있었지만 리스너의 특정 인스턴스를 참조하는 방법을 알 수 없었습니다. – Birrel