簡體   English   中英

將'this'和參數傳遞給addEventListener函數而不使用bind

[英]Passing 'this' and argument to addEventListener function without using bind

當addon禁用時,bootstrapped插件中的removeEventListener不能正常工作 ,我正在探索其他可能性。

除了使用bind()和緩存綁定函數之外,有沒有辦法使用'this'並傳遞參數?

// works fine but can't pass argeement
contextMenu.addEventListener('popupshowing', 
     this.contextPopupShowing, false);

// passes the argument but 'this' is no longer available
contextMenu.addEventListener('popupshowing', 
    function(){this.contextPopupShowing(window);}, false);

我一直在使用bind()的一些事件監聽器,我正在尋找替代方法而不使用bind()

我甚至嘗試使用<menupopup id="contentAreaContextMenu" ...>的遞歸函數來抓取window

更新: bind()干擾removeEventListener

因為我們正在討論無重啟的附加組件......許多無重啟的附加組件使用unloadunloadWindow輔助函數,以便更容易正確實現shutdown ,並且還有助於addEventListener這樣的東西,所以請耐心等待一下。

幫助者 - unload

首先, unload是一個輔助函數,您將另一個函數傳遞給它,它將在shutdown運行(或者可以手動調用)。 大多數實現與此非常相似:

var unloaders = []; // Keeps track of unloader functions.

function unload(fn) {
  if (typeof(fn) != "function") {
    throw new Error("unloader is not a function");
  }
  unloaders.push(fn);
  return function() {
    try {
      fn();
    }
    catch (ex) {
      Cu.reportError("unloader threw " + fn.toSource());
      Cu.reportError(ex);
    }
    unloaders = unloaders.filter(function(c) { return c != fn; });
  };
}

然后你會掛斷shutdown來做正確的事情:

function shutdown() {
  ...
  for (let i = unloaders.length - 1; i >= 0; --i) {
    try {
      unloaders[i]();
    }
    catch (ex) {
      Cu.reportError("unloader threw on shutdown " + fn.toSource());
      Cu.reportError(ex);
    }
  }
  unloaders.length = 0;
}

使用unload

現在你可以做以下事情:

function startup() {
  setupSomething();
  unload(removeSomething);

  setupSomethingElse();
  var manualRemove = unload(removeSomethingElse);
  ...
  if (condition) {
    manualRemove();
  }
}

助手 - unloadWindow

你通常想要創建第二個函數unloadWindow以便在你的插件關閉或窗口關閉時卸載東西,無論先發生什么。 在窗口關閉時不刪除東西可能非常棘手,並且非常容易創建bootstrap.js和/或代碼模塊的Zombie隔離專區 (這來自經驗編寫和審閱無重新啟動的附加組件)。

function unloadWindow(window, fn) {
  let handler = unload(function() {
    window.removeEventListener('unload', handler, false);
    try {
      fn();
    }
    catch (ex) {
      Cu.reportError("window unloader threw " + fn.toSource());
      Cu.reportError(ex);
    }
  });
  window.addEventListener('unload', handler, false);
};

(有些人可能想要“優化”這個,因為只有一個"unload"處理程序,但通常你只有這樣的unloadWindow調用它並不重要。)

把它們放在一起

現在你可以.bind東西並做任何事情,讓卸載器關閉跟蹤它。 此外,您可以使用此代碼將關閉代碼保留在初始化代碼旁邊,這可能會提高可讀性。

function setupWindow(window, document) {
  var bound = this.contextPopupShowing.bind(this);
  contextMenu.addEventListener('popupshowing', bound, false);
  unloadWindow(window, function() {
    contextMenu.removeEventListener('popupshowing', bound, false);
  });

  // Or stuff like
  var element = document.createElement(...);
  contextMenu.appendChild(element);
  unloadWindow(window, function() {
    contextMenu.removeChild(element);
  });

  // Or just combine the above into a single unloader
  unloadWindow(window, function() {
    contextMenu.removeEventListener('popupshowing', bound, false);
    contextMenu.removeChild(element);
  });
}

在支持bind()之前,您必須在函數外部保存this的引用。 然后傳入一個可以按你想要的方式轉發調用的函數。

var self = this;
contextMenu.addEventListener('popupshowing', function() {
     self.contextPopupShowing.apply(self, arguments);
}, false);

在這種情況下,我們使用apply於上下文設置為self ,我們保存的版本this ,並把它的任何arguments通過魔法傳遞給匿名函數arguments包含的調用時的函數傳遞參數列表中的關鍵字。

您不必為addEventListener使用bind 您可以使用handleEvent 在那個主題中,我也把你聯系起來:

刪除使用bind添加的事件偵聽器

MDN :: EventTarget.addEventListener - 處理程序中“this”的值

handleEvent實際上是firefox代碼庫中javascript代碼的常用方式。

直接從MDN復制:

var Something = function(element) {
  this.name = 'Something Good';
  this.handleEvent = function(event) {
    console.log(this.name); // 'Something Good', as this is the Something object
    switch(event.type) {
      case 'click':
        // some code here...
        break;
      case 'dblclick':
        // some code here...
        break;
    }
  };

  // Note that the listeners in this case are this, not this.handleEvent
  element.addEventListener('click', this, false);
  element.addEventListener('dblclick', this, false);

  // You can properly remove the listners
  element.removeEventListener('click', this, false);
  element.removeEventListener('dblclick', this, false);
}

我主要使用bind是在執行for循環時,我在數組中使用arr[i]創建匿名函數。 如果我不綁定它,那么它總是只占用數組的最后一個元素,我不知道為什么,我討厭它,所以然后我去使用[].forEach.call(arr, function(arrI)

http://2ality.com/2013/06/auto-binding.html

var listener = myWidget.handleClick.bind(myWidget);
domElement.addEventListener('click', listener);
...
domElement.removeEventListener(listener);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM