Backbone源码学习 — Backbone.Collection

发表于 Backbone 分类,标签:

今天我们继续来说说Backbone MVC中的 M,如果说前面介绍的Backbone.Model像是数据库中的一条记录的抽象的话,那么今天要聊的Backbone.Collection 就像是由若干条Backbone.Model组成的一个数据库表,其api和使用方法和Backbone.Model相似,主要是对models集合进行操作,以下为Backbone.Collection提供的API:

我们可以看到很多api和Backbone.Model 的方法是相同的,主要是用于操作数据,进行数据定位等等,方法有:

  • set:作为所有数据操作的基类方法,通过options确定具体的操作,主要是对models 集合进行add,remove,merge等操作,默认操作是将传入的models替换原有的models,不进行合并

  • add:封装了set方法,传入的配置默认是remove:false,将存入的models添加到原有的models中去

  • remove:删除传入的models,如果传入的model不存在,则为空操作,删除之后触发 remove 事件

  • reset : 删除原来的models集合 ,将传入的models进行设置,不触发add/remove事件,在完成之后触发reset事件

  • get : 通过传入的参数返回特定的model(参数可以是obj/id/cid);

下面我们来看看几个主要的API:

set

collection.set(models, [options])

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
   //set/add操作中传入set 的默认option  var setOptions = {add: true, remove: true, merge: true};  var addOptions = {add: true, remove: false};  set:function(models, options){         //各种属性设置            options = _.defaults({}, options, setOptions);        //parse 解析models        if (options.parse) models = this.parse(models, options);        //判断是否是当个model,如果是则返回一个[model]        var singular = !_.isArray(models);        models = singular ? (models ? [models] : []) : _.clone(models);              // 各种options 的判断        var i, l, id, model, attrs, existing, sort;        // 如果传入了at属性,则会在插入的时候插入到at指定的models的位置        var at = options.at;        var targetModel = this.model;        //如果comparator不为空,没有指定at,sort不为false,则这次set操作将进行排序        var sortable = this.comparator && (at == null) && options.sort !== false;        var sortAttr = _.isString(this.comparator) ? this.comparator : null;          //设置各个操作的临时存储集合        var toAdd = [], toRemove = [], modelMap = {};        var add = options.add, merge = options.merge, remove = options.remove;        var order = !sortable && add && remove ? [] : false;          //开始对传入的models进行处理,但是只是对models进行分类,传入到各个临时存储集合中去      for (i = 0, l = models.length; i < l; i++) {        attrs = models[i] || {};      //获取model的id        if (attrs instanceof Model) { //是否为 Backbone.Model (没有设置model)          id = model = attrs;        } else {          id = attrs[targetModel.prototype.idAttribute || 'id'];        }        //判断是否已经存在        if (existing = this.get(id)) {          if (remove) modelMap[existing.cid] = true; //如果 remove 为true,加入modelMap          if (merge) { //merge 为true, 对model中的attribute 进行设置            attrs = attrs === model ? model.attributes : attrs;            if (options.parse) attrs = existing.parse(attrs, options);            existing.set(attrs, options);//调用model中的set方法,进行数据合并            if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;          }          models[i] = existing;        } else if (add) {//若不存在则判断add属性,存入到toAdd 中        //调用_prepareModel生成一个model          model = models[i] = this._prepareModel(attrs, options);          if (!model) continue;          toAdd.push(model); //添加入toAdd          this._addReference(model, options); //建立与collection的关联        }        model = existing || model;        if (order && (model.isNew() || !modelMap[model.id])) order.push(model);        modelMap[model.id] = true;      }          //添加model 处理       if (toAdd.length || (order && order.length)) {        if (sortable) sort = true;        this.length += toAdd.length;//更新length的值        if (at != null) {//如果at值不为空,则插入到对应的索引位置          for (i = 0, l = toAdd.length; i < l; i++) {            this.models.splice(at + i, 0, toAdd[i]);          }        } else {//否则使用push向后插入,如果order不为空,则使用order替换整个models          if (order) this.models.length = 0;          var orderedModels = order || toAdd;          for (i = 0, l = orderedModels.length; i < l; i++) {            this.models.push(orderedModels[i]);          }        }      }      if (sort) this.sort({silent: true}); // 排序      //触发 响应的事件      if (!options.silent) {        for (i = 0, l = toAdd.length; i < l; i++) {          (model = toAdd[i]).trigger('add', model, this, options);        }        if (sort || (order && order.length)) this.trigger('sort', this, options);      }      return singular ? models[0] : models;             }

set方法中通过对options的remove,add,merge进行设置,进行不同的行为操作,如果remove是true的话,其值将被设置入order中,在line:79 进行整个models的替换,如果是remove是false,则将set 的值加入toAdd中。Backbone.Collection中很多方法都是以set为基础方法的,如 add方法:

123
    add: function(models, options) {        return this.set(models, _.extend({merge: false}, options, addOptions));   }

_addReference

_addReference 方法为内部方法,主要用于在model和对应的collection建立关系,在collection的_byId集合中加入对应cidid的model映射,将model的collection属性设置为当前的collection 。

123456
   _addReference: function(model, options) {      this._byId[model.cid] = model;      if (model.id != null) this._byId[model.id] = model;      if (!model.collection) model.collection = this;      model.on('all', this._onModelEvent, this);    }

除了set方法,其他的方法和Backbone.Model中的方法从逻辑,机制都差不多,都是一个 操作 --> 触发事件的过程。只有少数差别,比如fetch方法 ,在options中有个reset配置,可以对获取的数据进行一个覆盖操作。而Backbone.Collection中没有save方法,取而代之的是一个create方法,就是调用了model中的save方法,但是细细推敲,在collection中使用create这个名字确实比较准确

转自(http://qbright.github.io/blog/2014/12/08/backbone.Collectioin/  )

0 篇评论

发表我的评论