180 lines
5.8 KiB
JavaScript
180 lines
5.8 KiB
JavaScript
|
/**
|
|||
|
* 实现发布-订阅模式下的消息传输机制,支持命名空间与离线事件
|
|||
|
* @param {string} [key] 事件的名称
|
|||
|
* @param {function} [fn] 事件的回调
|
|||
|
* @param {string} [last] 是否只执行最后一次绑定的消息 last ==“last”时只执行最后一次绑定的消息,否则执行之前所有绑定的消息
|
|||
|
*
|
|||
|
* @example
|
|||
|
* 1.常规
|
|||
|
* eventBus.on('click',function(a){
|
|||
|
* console.log(a) // 输出 :1
|
|||
|
* })
|
|||
|
* eventBus.emit('click',1)
|
|||
|
*
|
|||
|
* 2. 先发布后订阅
|
|||
|
* eventBus.emit('click',1)
|
|||
|
* eventBus.on('click',function(a){
|
|||
|
* console.log(a) // 输出 :1
|
|||
|
* })
|
|||
|
*
|
|||
|
* 3.使用命名空间
|
|||
|
* eventBus.create('namespace1').on('click',function(a){
|
|||
|
* console.log(a) // 输出 :1
|
|||
|
* })
|
|||
|
* eventBus.create('namespace1').emit('click',1)
|
|||
|
*
|
|||
|
* auth by guoqiang
|
|||
|
* 注意:支持离线事件可能会带来一些副作用,比如意外的某个页面发布了某个消息,这时如果另一个订阅了这个消息,这个消息的回调会立即执行,而且大多请况下,回调的参数会出问题。在逻辑没理清之前不建议先发布再订阅
|
|||
|
* 注意:支持离线事件可能会带来一些副作用,比如意外的某个页面发布了某个消息,这时如果另一个订阅了这个消息,这个消息的回调会立即执行,而且大多请况下,回调的参数会出问题。在逻辑没理清之前不建议先发布再订阅
|
|||
|
* 注意:支持离线事件可能会带来一些副作用,比如意外的某个页面发布了某个消息,这时如果另一个订阅了这个消息,这个消息的回调会立即执行,而且大多请况下,回调的参数会出问题。在逻辑没理清之前不建议先发布再订阅
|
|||
|
*/
|
|||
|
(function(window, undefined) {
|
|||
|
var _subscribe = null,
|
|||
|
_publish = null,
|
|||
|
_unsubscribe = null,
|
|||
|
_shift = Array.prototype.shift, // 删除数组的第一个 元素,并返回这个元素
|
|||
|
_unshift = Array.prototype.unshift, // 在数组的开头添加一个或者多个元素,并返回数组新的length值
|
|||
|
namespaceCache = {},
|
|||
|
_create = null,
|
|||
|
each = function(ary, fn) {
|
|||
|
var ret = null;
|
|||
|
for (var i = 0, len = ary.length; i < len; i++) {
|
|||
|
var n = ary[i];
|
|||
|
ret = fn.call(n, i, n);
|
|||
|
}
|
|||
|
return ret;
|
|||
|
};
|
|||
|
|
|||
|
// 订阅消息名称为:'+key+'
|
|||
|
_subscribe = function(key, fn, cache) {
|
|||
|
if (!cache[key]) {
|
|||
|
cache[key] = [];
|
|||
|
}
|
|||
|
cache[key].push(fn);
|
|||
|
};
|
|||
|
|
|||
|
// 取消订阅(取消全部或者指定消息)
|
|||
|
_unsubscribe = function(key, cache, fn) {
|
|||
|
if (cache[key]) {
|
|||
|
if (fn) {
|
|||
|
for (var i = cache[key].length; i >= 0; i--) {
|
|||
|
if (cache[key][i] === fn) {
|
|||
|
cache[key].splice(i, 1);
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
cache[key] = [];
|
|||
|
}
|
|||
|
} else if (!key) {
|
|||
|
for (var key in cache) {
|
|||
|
delete cache[key];
|
|||
|
}
|
|||
|
} else {
|
|||
|
console.log("不存在该消息的监听:" + key);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// 发布消息
|
|||
|
_publish = function() {
|
|||
|
var cache = _shift.call(arguments),
|
|||
|
key = _shift.call(arguments),
|
|||
|
args = arguments,
|
|||
|
_self = this,
|
|||
|
ret = null,
|
|||
|
stack = cache[key];
|
|||
|
|
|||
|
if (!stack || !stack.length) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
return each(stack, function() {
|
|||
|
return this.apply(_self, args);
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
// 创建命名空间
|
|||
|
_create = function(namespace) {
|
|||
|
var namespace = namespace || "default";
|
|||
|
var cache = {},
|
|||
|
offlineStack = {}, // 离线事件,用于先发布后订阅,只执行一次
|
|||
|
ret = {
|
|||
|
on: function(key, fn, last) {
|
|||
|
_subscribe(key, fn, cache);
|
|||
|
if (!offlineStack[key]) {
|
|||
|
offlineStack[key] = null;
|
|||
|
return;
|
|||
|
}
|
|||
|
if (last === "last") {
|
|||
|
// 指定执行离线队列的最后一个函数,执行完成之后删除
|
|||
|
offlineStack[key].length && offlineStack[key].pop()(); // [].pop => 删除一个数组中的最后的一个元素,并且返回这个元素
|
|||
|
} else {
|
|||
|
each(offlineStack[key], function() {
|
|||
|
this();
|
|||
|
});
|
|||
|
}
|
|||
|
offlineStack[key] = null;
|
|||
|
},
|
|||
|
one: function(key, fn, last) {
|
|||
|
_unsubscribe(key, cache);
|
|||
|
this.on(key, fn, last);
|
|||
|
},
|
|||
|
off: function(key, fn) {
|
|||
|
_unsubscribe(key, cache, fn);
|
|||
|
},
|
|||
|
emit: function() {
|
|||
|
var fn = null,
|
|||
|
args = null,
|
|||
|
key = _shift.call(arguments),
|
|||
|
_self = this;
|
|||
|
|
|||
|
_unshift.call(arguments, cache, key);
|
|||
|
args = arguments;
|
|||
|
fn = function() {
|
|||
|
return _publish.apply(_self, args);
|
|||
|
};
|
|||
|
|
|||
|
if (offlineStack && offlineStack[key] === undefined) {
|
|||
|
offlineStack[key] = [];
|
|||
|
return offlineStack[key].push(fn);
|
|||
|
}
|
|||
|
return fn();
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
return namespace
|
|||
|
? namespaceCache[namespace]
|
|||
|
? namespaceCache[namespace]
|
|||
|
: (namespaceCache[namespace] = ret)
|
|||
|
: ret;
|
|||
|
};
|
|||
|
|
|||
|
window.eventBus = {
|
|||
|
create: _create, // 创建命名空间
|
|||
|
one: function(key, fn, last) {
|
|||
|
// 订阅消息,只能单一对象订阅
|
|||
|
var namespace = "default";
|
|||
|
var pubsub = this.create(namespace);
|
|||
|
pubsub.one(key, fn, last);
|
|||
|
},
|
|||
|
on: function(key, fn, last) {
|
|||
|
// 订阅消息,可多对象同时订阅
|
|||
|
var namespace = "default";
|
|||
|
var pubsub = this.create(namespace);
|
|||
|
pubsub.on(key, fn, last);
|
|||
|
},
|
|||
|
off: function(key, fn, namespace) {
|
|||
|
// 取消订阅,(取消全部或指定消息)
|
|||
|
namespace = "default";
|
|||
|
var pubsub = this.create(namespace);
|
|||
|
console.trace("");
|
|||
|
pubsub.off(key, fn);
|
|||
|
},
|
|||
|
emit: function(key, fn) {
|
|||
|
// 发布消息
|
|||
|
var namespace = "default";
|
|||
|
var pubsub = this.create(namespace);
|
|||
|
pubsub.emit.apply(this, arguments);
|
|||
|
}
|
|||
|
};
|
|||
|
})(window, undefined);
|