set的整个流程就是 对传入的数值进行处理,变成一个键值对,然后对数值进行校验,检查正确性,然后开始进行设置操作,设置时检查数值时候是发生改变的,如果有则加入一个 changeed的对象中,然后检查unset的值,进行相应的添加更新删除操作。然后依次触发change:attr和change事件。
save
model.save([attributes], [options])
save方法用于向客户端持久化数据,会根据数据的不同和配置的不同选择使用create,update或者是patch,并且触发 sync 事件,以下为部分代码:
save: function(key, val, options) { // ...... //当设置了wait属性true的时候 , save方法先不执行set方法(不触发change事件),只执行validate if (attrs && !options.wait) { if (!this.set(attrs, options)) return false; } else { if (!this._validate(attrs, options)) return false; } //如果wait为true,设置this.attributes if (attrs && options.wait) { this.attributes = _.extend({}, attributes, attrs); } // ..... var model = this; var success = options.success; options.success = function(resp) { // Ensure attributes are restored during synchronous saves. model.attributes = attributes; var serverAttrs = model.parse(resp, options); //如果wait为true , 那么会在请求返回之后才进行set操作 if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { return false; } if (success) success(model, resp, options); //触发 sync 事件 model.trigger('sync', model, resp, options); }; //生成XHR onerror 回调函数 wrapError(this, options); //选择方法 method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); if (method === 'patch') options.attrs = attrs; xhr = this.sync(method, this, options); // Restore attributes. if (attrs && options.wait) this.attributes = attributes; //返回xhr对象 return xhr; }
save 中最需要注意的就是 wait 的设置,当wait为真的时候,save返回会在xhr返回之后再执行set操作,而不是在xhr之前就进行set操作,因此change事件的触发时机也就不同了。
之前说过整个Backbone都是通过事件串联起来的,所以对于事件触发时机的了解和把握是非常重要的,不然会在开发过程中导致一些奇怪的问题出现。
Backbone.View
前面已经对backbone中的Event、Model、Collection代码进行了分析,现在我们来看下MVC中的V部分,也就是Backbone.View,View在Backbone中主要用于沟通页面中的DOM和Backbone.Model/Collection,页面的逻辑操作,DOM事件的绑定等,View部分的代码非常简答,加上注释只有110左右。 View部分有一下API:
方法不多,下面对部分API进行介绍:
构造方法
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; var View = Backbone.View = function(options) { this.cid = _.uniqueId('view'); options || (options = {}); _.extend(this, _.pick(options, viewOptions)); this._ensureElement(); this.initialize.apply(this, arguments); this.delegateEvents(); };
构造方法中为View生成了一个唯一的cid,以'view'开头,然后进行对目标属性viewOptions进行合并,接着调用_ensureElement判断el的情况,接着调用delegateEvents进行方法绑定,初始化完成 。
delegateEvents
view.setElement(element) setElement: function(element, delegate) { if (this.$el) this.undelegateEvents();//如果已经存在this.$el,进行事件解绑 //对$el进行赋值,本质是一个jquery或者是 Lo-Dash and Zepto 对象 this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); //把dom element 赋值给el this.el = this.$el[0]; //如果没有显式传值,则进行事件绑定 if (delegate !== false) this.delegateEvents(); return this; }
setElement方法用于设置View对应的element , 这个方法在new的时候会被调用, 如果想要在使用过程中改变View的dom元素指向,可调用这个方法进行重新设置
_ensureElement
_ensureElement: function() { //如果已经对el进行设置,直接调用setElement方法 if (!this.el) {//如果没有设置,生成一个元素对象,再调用setElement方法 var attrs = _.extend({}, _.result(this, 'attributes')); if (this.id) attrs.id = _.result(this, 'id'); if (this.className) attrs['class'] = _.result(this, 'className'); var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); this.setElement($el, false); } else { this.setElement(_.result(this, 'el'), false); } }