2016-03-28 102 views
0

好吧,我一直在做這個小黑客來實現我需要在不同時間向一個特定函數添加多個事件。如何在沒有DOM對象的情況下將事件綁定到函數

$("#handler").bind("click",function(){ alert(1); }); 
$("#handler").bind("click",function(){ alert(2); }); 
$("#handler").bind("click",function(){ alert(3); }); 

當我簡單地打電話給$("#handler").click()它會觸發所有這些事件。

問題是,我可以做到這一點,而不使一些任意的HTML對象綁定到?

與標準的javascript函數做同樣的事情是什麼?

function handler(){ alert(1); } 
function handler(){ alert(2); } 
function handler(){ alert(3); } 
handler(); 

^這只是觸發的最後一個,而且不是所有3.我怎樣才能多個事件綁定到一個函數,而不是一個DOM元素?

+0

僅綁定事件一次。 – Tushar

+0

@Tushar當然,當然,我不需要問這個問題吧?問題在於,綁定發生在運行時的不同部分。但是,感謝您的輸入 – RealWorldCoder

+0

你有沒有考慮使用循環?它會觸發最後一個,因爲最後一個讀取功能與第一個和第二個讀取功能相同。 –

回答

1

如果您真的只是在尋找一種方法將各個功能組合到一個更大的「功能集」中,然後您可以一次觸發所有功能,則可以通過javascript中的Set對象實現。例如:

// define the Set object that you want to store the functions inside: 
var handlerFunctionCollection = new Set(); 


// add individual functions to the Set: 
handlerFunctionCollection.add(function(){ console.log(1); }); 
handlerFunctionCollection.add(function(){ console.log(2); }); 
handlerFunctionCollection.add(function(){ console.log(3); }); 

// trigger all functions in set using forEach on Set 
// and call() method on stored Function object: 
handlerFunctionCollection.forEach(function(handlerFunction) { 
    if(handlerFunction instanceof Function) { 
     handlerFunction.call(); 
    } 
}); 

請注意,我立足根據你說這句話的解釋你的問題:

當我只需撥打$("#handler").click()它觸發所有這些事件。

這表明你實際上並沒有尋找到直接綁定功能,以事件的方式,而是一種方式來觸發在一個地方多種功能,否則你就不能手動觸發click事件。

使用Set在一個Array對象或類似的集合的一個好處是,Set的成員是唯一的,所以,如果你嘗試在同一功能的多次(意外或其他方式)添加,添加Function對象將只在Set中出現一次,因此它只會在觸發forEach時觸發一次,因爲它只會在Set中存在一次,而不是每次添加時都會存在一次。

1

在JavaScript中,每個函數實際上都是一個函數對象

在Javascript中,如果您定義了多個具有相同名稱的函數,那麼最後一個函數將實際運行。 JavaScript functions不是polymorphic類似許多其他語言的函數,在其他語言中,可能有funcA(parm1)funcA(parm1, parm2)作爲兩個單獨的函數,根據傳遞的參數數量運行該函數。

在你的情況下,你需要聲明一個函數來處理函數範圍內的不同情況。

0

您正在尋找ObserverPublisher/Subscriber ("PubSub")的概念。

這些都很容易創建自己的。
下面是運行以下演示代碼的僅適用於應用程序的代碼(可能運行於DOM就緒或其他)的稍微清理版本。

const trigger = $("#Trigger"); 
const system = Publisher(); 

// add my listeners 
system 
.on("trigger", triggerContentUpdate) 
.on("update", updateView) 
.on("update", logUpdate); // note how I have two things bound to the same event 

// something that kicks off the "trigger" event 
// could be a timer, or an AJAX call, or anything else 
trigger.onclick =() => system.fire("trigger"); 

假設你有一個Publisher庫,並在你的應用程序有上述監聽功能,這是幾乎所有的JS,你不得不寫盡以下工作演示。

我編寫的練習庫和演示的實現如下。

/*** LIBRARY CODE ***/ 
 

 
// Channel.js 
 
const Channel =() => { 
 
    const listeners = new Set(); 
 

 
    const channel = { 
 

 
    listen(listener) { 
 
     listeners.add(listener); 
 
     return channel; 
 
    }, 
 

 
    ignore(listener) { 
 
     listeners.delete(listener); 
 
     return channel; 
 
    }, 
 

 
    notify(data) { 
 
     listeners.forEach(react => react(data)); 
 
     return channel; 
 
    } 
 
    }; 
 

 
    return channel; 
 
}; 
 

 
// Publisher.js 
 
const Publisher =() => { 
 
    const channels = {}; 
 

 
    function getChannel(name) { 
 
    const channel = channels[name] || Channel(); 
 
    channels[name] = channel; 
 
    return channel; 
 
    } 
 

 
    const publisher = { 
 

 
    on(name, subscriber) { 
 
     getChannel(name).listen(subscriber); 
 
     return publisher; 
 
    }, 
 

 
    off(name, subscriber) { 
 
     getChannel(name).ignore(subscriber); 
 
     return publisher; 
 
    }, 
 

 
    fire(name, data) { 
 
     getChannel(name).notify(data); 
 
     return publisher; 
 
    } 
 

 
    }; 
 

 
    return publisher; 
 
} 
 

 
/*** END OF LIBRARY CODE ***/ 
 

 

 

 
/*** APPLICATION CODE ***/ 
 

 
// const Publisher = require("publisher"); or import Publisher from "publisher"; 
 

 
const $ = selector => document.querySelector(selector); 
 

 
const trigger = $("#Trigger"); 
 
const input = $("#Content"); 
 
const output = $("#Result"); 
 
const log = $("#Log"); 
 

 
const system = Publisher(); 
 

 
system 
 
    .on("trigger",() => { 
 
    const content = input.value; 
 
    system.fire("update", content); 
 
    }) 
 
    .on("update", content => output.value = content) 
 
    // normally, I never use innerHTML, and my logic and view are never attached, but this is dirt-simple now 
 
    .on("update", content => log.innerHTML += `<li>[${ (new Date()).toISOString() }]: ${content}</li>`); 
 

 
trigger.onclick =() => system.fire("trigger"); 
 

 
/*** END OF APPLICATION CODE ***/
<h3>Input</h3> 
 
<div> 
 
    <input id="Content" type="text"> 
 
    <button id="Trigger">Update</button> 
 
</div> 
 
<h3>Output</h3> 
 
<output id="Result"></output> 
 

 
<h3>Log</h3> 
 
<ul id="Log"></ul>

當然,我使用的是比較現代的語法,但沒有什麼不能在舊的兼容代碼重寫,或者transpiled並給予填充工具,向下走一路到IE7/8的支持。

如果我想讓一些任意的對象成爲發佈者,我也可以很快地做到這一點。

+0

這是javascript嗎? – RealWorldCoder

+1

@RealWorldCoder它是100%的JavaScript。原生的,正常的,每天的JavaScript。你可以用老式的函數替換所有的箭頭函數,你可以用'[]替換'Set',並添加額外的檢查以避免插入重複的監聽器(一組函數適合你)。你可以用'var'替換所有'const'。你又回到了老式的JS。但是,如果你注意到,如果你使用Chrome或FireFox,或者任何自我尊重的瀏覽器,這個例子應該可以正常工作。 – Norguard

+0

連同填充工具用於相同的'Set'和'Map' – Norguard

相關問題