删除“包装”事件处理程序以在pub / sub消息传递中使用

时间:2014-10-12 11:11:41

标签: javascript jquery javascript-events publish-subscribe

我使用jQuery事件完成了一些发布/订阅。

基本功能有效:

var publish = function(name) {                        // --- works
  var args = Array.prototype.slice.call(arguments);   // convert to array
  args = args.slice(1);                               // remove arg1 (name)
  $("html").trigger(name, args);
}

var subscribe = function(name, callback) {            // --- works
  $("html").on(name, callback);
}

var unsubscribe = function(name, callback) {          // --- works
  $("html").off(name, callback);
}

// usage:                                             // --- works
var myhandler = function () { /* ... */ };
subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"});
unsubscribe("foo", myhandler);

但订阅我想要的方式,不会:

var subscribe = function(name, callback) {            // --- can't unsub this
  $("html").on(name, function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  });
}

我想要第二个subscribe函数,因为匿名回调剥离了第一个参数(Event对象),我不想在" clean"客户代码。我想在回调中收到的只是事件数据,我不想要Event对象本身。

但这意味着我无法成功调用unsubscribe,因为我没有将off()传递给传递给on()的相同回调 - 这不是实际的回调,而是包裹匿名函数。

有解决方法吗?

3 个答案:

答案 0 :(得分:2)

通常的方法是使用jQuery的"namespaced" events

$("html").on(name + ".my-pub-sub", function () {
    // ...
});

然后取消订阅:

$("html").off(name + ".my-pub-sub");

告诉jQuery删除具有给定事件名称和特定命名空间的所有处理程序。

这是一个简化的例子:

// Add two click handlers:
$("button").on("click", function() {
  $("<p>Non-namespaced click</p>").appendTo(document.body);
});
$("button").on("click.namespace", function() {
  $("<p>Namespaced click</p>").appendTo(document.body);
});

// Show they both trigger
$("<p>Clicking...</p>").appendTo(document.body);
$("button").click();

// Remove the namespaced one without a function ref
$("button").off("click.namespace");

// Now just the non-namespaced one runs
$("<p>Clicking again...</p>").appendTo(document.body);
$("button").click();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>The button</button>

答案 1 :(得分:1)

您可以返回新创建的事件处理程序,如下所示:

var subscribe = function(name, callback) {
  var handler = function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  };
  $("html").on(name, handler);
  return handler;
};

现在您可以像这样使用它:

var myhandler = function () { console.log(arguments); };
var eventHandler = subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"}); // logs to console
unsubscribe("foo", eventHandler);
publish("foo", 1, false, "bob", {a:1, b:"2"}); // don't log anymore

以下是 demo

答案 2 :(得分:0)

我所做的是基于@TJCrowder提出的名称空间构思。但我已经将他的答案标记为谢谢。

var subscribe = function(name, callback) {

  // create a unique "key" for this specific event handler
  // - use this format: ORIGINALNAME.MILLISECONDS.RANDOMNUMBER
  // - include time in random string, as could be lots of subs happening at once
  // - then include a random number, just to be safe
  var key = name + "." + (new Date().getTime()) + (Math.random()*1000);

  $("html").on(key, function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  });

  return key;
}

var unsubscribe = function (key) {
  $("html").off(key);
};

// usage:
var myhandler = function () { /* ... */ };
var key = subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"});
unsubscribe(key);

由于此密钥是唯一的(好吧,它应该是?!),它只会删除这个特定的处理程序。所以我可以有很多订阅者,只能取消其中一个订阅者。