说道Backbone的事件机制。自己也是逗逼了。敲了一遍Backbone的源码。。居然是还不知道他的机制。。
先上Events On对象的源码
/**
* Created by More on 2015/11/28.
*/
var Events = Backbone.Events ={
/**
* params:
* events : 事件们
* callback : 回调函数
* context : 上下文,俗称的this
*
* **/
on: function(events,callback,context){
var calls,//回调函数数字
event,//切割的事件名称
node,//节点对象
tail,//节点的结尾,用于判断所有回调是否执行完毕
list;//保存当前对象中的事件对象
if(!callback){
return this;
}
//事件切割数组
events = events.split(eventSplitter);
//回调对象
calls = this._callbacks || (this._callbacks = {});
while(event = events.shift()){
list = calls[event];
node = list ? list.tail : {};
node.next = tail = {};
node.context = context;
calls[event] ={
tail : tail,
next : list ? list.next : node
}
}
return this;
}
}
一开始,我都不知道原理是啥,只知道他丢进去了一个_CallBacks对象在Backbone里边,里边的键值对是有序的,包括回调函数都是有序的保存在该对象中,但是不知道是怎么触发的。。
老老实实又去看了下collection的原型,再上源码
add : function(models, options) {
// 局部变量定义
var i, index, length, model, cid, id, cids = {}, ids = {}, dups = [];
options || ( options = {});
// models必须是一个数组, 如果只传入了一个模型, 则将其转换为数组
models = _.isArray(models) ? models.slice() : [models];
// 遍历需要添加的模型列表, 遍历过程中, 将执行以下操作:
// - 将数据对象转化模型对象
// - 建立模型与集合之间的引用
// - 记录无效和重复的模型, 并在后面进行过滤
for( i = 0, length = models.length; i < length; i++) {
// 将数据对象转换为模型对象, 简历模型与集合的引用, 并存储到model(同时models中对应的模型已经被替换为模型对象)
if(!( model = models[i] = this._prepareModel(models[i], options))) {
throw new Error("Can‘t add an invalid model to a collection");
}
// 当前模型的cid和id
cid = model.cid;
id = model.id;
// dups数组中记录了无效或重复的模型索引(models数组中的索引), 并在下一步进行过滤删除
// 如果cids, ids变量中已经存在了该模型的索引, 则认为是同一个模型在传入的models数组中声明了多次
// 如果_byCid, _byId对象中已经存在了该模型的索引, 则认为同一个模型在当前集合中已经存在
// 对于上述两种情况, 将模型的索引记录到dups进行过滤删除
if(cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) {
dups.push(i);
continue;
}
// 将models中已经遍历过的模型记录下来, 用于在下一次循环时进行重复检查
cids[cid] = ids[id] = model;
}
// 从models中删除无效或重复的模型, 保留目前集合中真正需要添加的模型列表
i = dups.length;
while(i--) {
models.splice(dups[i], 1);
}
// 遍历需要添加的模型, 监听模型事件并记录_byCid, _byId列表, 用于在调用get和getByCid方法时作为索引
for( i = 0, length = models.length; i < length; i++) {
// 监听模型中的所有事件, 并执行_onModelEvent方法
// _onModelEvent方法中会对模型抛出的add, remove, destroy和change事件进行处理, 以便模型与集合中的状态保持同步
( model = models[i]).on(‘all‘, this._onModelEvent, this);
// 将模型根据cid记录到_byCid对象, 便于根据cid进行查找
this._byCid[model.cid] = model;
// 将模型根据id记录到_byId对象, 便于根据id进行查找
if(model.id != null)
this._byId[model.id] = model;
}
// 改变集合的length属性, length属性记录了当前集合中模型的数量
this.length += length;
// 设置新模型列表插入到集合中的位置, 如果在options中设置了at参数, 则在集合的at位置插入
// 默认将插入到集合的末尾
// 如果设置了comparator自定义排序方法, 则设置at后还将按照comparator中的方法进行排序, 因此最终的顺序可能并非在at指定的位置
index = options.at != null ? options.at : this.models.length;
splice.apply(this.models, [index, 0].concat(models));
// 如果设置了comparator方法, 则将数据按照comparator中的算法进行排序
// 自动排序使用silent属性阻止触发reset事件
if(this.comparator)
this.sort({
silent : true
});
// 依次对每个模型对象触发"add"事件, 如果设置了silent属性, 则阻止事件触发
if(options.silent)
return this;
// 遍历新增加的模型列表
for( i = 0, length = this.models.length; i < length; i++) {
if(!cids[( model = this.models[i]).cid])
continue;
options.index = i;
// 触发模型的"add"事件, 因为集合监听了模型的"all"事件, 因此在_onModelEvent方法中, 集合也将触发"add"事件
// 详细信息可参考Collection.prototype._onModelEvent方法
model.trigger(‘add‘, model, this, options);
}
return this;
},
原来在这里的最后几行代码中,手动触发了这个事件,导致自定义的事件可以被触发。。差点就被自己给坑进去了。。还以为自己发现了什么心技能。。可以隐式的定义方法在对象的_callBacks对象中。。
呀呀呀。。继续干。。
原文:http://www.cnblogs.com/nonmingbobo/p/5003404.html