ホームページ >ウェブフロントエンド >jsチュートリアル >Backbone.jsのModelモデルとViewのソースコードをざっと理解する_基礎知識
バックボーン.モデル
今日はまず Backbone.js MVC の M について説明します。モデルはバックボーンの中核部分であり、ページ表示コンテンツのデータと、データ操作に関連するさまざまな変換、検証、計算、権限制御が含まれます。 、サーバー側の操作やその他の操作を行うと、Backbone.Model.extend() を通じてモデルを生成できます。もちろん、生成されたモデルを基本クラスとして使用して、さらに多くのモデルを拡張することもできます
。var People = Backbone.Model.extend({ }); var Man = People.extend({ });
バックボーン.モデル API
Backbone.Model は、モデルの基本的な操作を実装するための多数のメソッドを提供します。もちろん、最も基本的なのは、Model の属性が変更されると、それに対応する変更が行われるイベント メカニズムです。 attr イベントはトリガーになります。提供される API は次のとおりです:
データに対してサーバー側の操作を実行するためのメソッドがあります:
モデル内のデータ操作のメソッド:
コンストラクター
var Model = Backbone.Model = function(attributes, options) { var attrs = attributes || {}; options || (options = {}); this.cid = _.uniqueId('c'); this.attributes = {}; if (options.collection) this.collection = options.collection; if (options.parse) attrs = this.parse(attrs, options) || {}; attrs = _.defaults({}, attrs, _.result(this, 'defaults')); this.set(attrs, options); this.changed = {}; this.initialize.apply(this, arguments); };
セット
model.set(attributes, [options])
set: function(key, val, options) { //...... // key值可以是键值对,也可以是一个字符串,将赋值传入attrs属性中 if (typeof key === 'object') { attrs = key; options = val; } else { (attrs = {})[key] = val; } // .... //对设置的值进行校验 if (!this._validate(attrs, options)) return false; unset = options.unset; // unset为true时会删除设置的值,unset方法就是通过 set(key,val,{unset:true})去实现的 //当对象正在被被设置的时候,不给 previousAttributes 赋值 if (!changing) { this._previousAttributes = _.clone(this.attributes); this.changed = {}; } current = this.attributes, prev = this._previousAttributes; //如果对Id进行了设置,则对对象的id属性也进行改变 if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; //进行 设置或者是删除操作 for (attr in attrs) { val = attrs[attr]; if (!_.isEqual(current[attr], val)) changes.push(attr); if (!_.isEqual(prev[attr], val)) { this.changed[attr] = val;//为model的changed进行设置 } else { delete this.changed[attr]; } unset ? delete current[attr] : current[attr] = val;//如果unset被设置成true了,则进行删除操作 } //在silent不为false 的情况下,进行change:attr事件发送 if (!silent) { if (changes.length) this._pending = options; for (var i = 0, l = changes.length; i < l; i++) { this.trigger('change:' + changes[i], this, current[changes[i]], options); } } //触发change事件 if (changing) return this; if (!silent) { while (this._pending) { options = this._pending; this._pending = false; this.trigger('change', this, options); } } this._pending = false; this._changing = false; return this; }
保存
model.save([attributes], [options])
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); } }
_ensureElement这个方法是内部方法,在构造函数中使用,用于判断指定的el在页面中存不存在,如果存在则对$el进行赋值,如果不存在,则生成一个$el,但是要注意这个对象是没有落地到dom树中的 。
delegateEvents
delegateEvents([events]) // *{"event selector": "callback"}* // // { // 'mousedown .title': 'edit', // 'click .button': 'save', // 'click .open': function(e) { ... } // } delegateEvents: function(events) { //如果不存在events,则直接返回 if (!(events || (events = _.result(this, 'events')))) return this; //先解除所有的事件绑定 this.undelegateEvents(); //处理每个事件 for (var key in events) { var method = events[key]; //解析回调函数 if (!_.isFunction(method)) method = this[events[key]]; if (!method) continue; //对选择器进行分析 var match = key.match(delegateEventSplitter); var eventName = match[1], selector = match[2]; method = _.bind(method, this); //绑定的事件名都是以 eventName + '.delegateEvents' + cid 组成, //这么做能够在undelegateEvents的时候选择到这个View的所有事件 eventName += '.delegateEvents' + this.cid; if (selector === '') { this.$el.on(eventName, method); } else { this.$el.on(eventName, selector, method); } } return this; }
在View中你可以使用一个 key:value 集合指定对应的事件,在初始化的时候构造函数会调用delegateEvents进行绑定,需要注意的是所有在key中指定的元素的父元素都必须是$el,也就是说元素必须是$el的子节点,否则绑定失败。
View和其他backbone模块一个区别就是没有自己的内建自定义事件,当然他也组合了Events模块,但是所有的事件都需要自己进行建立。View主要是一个MVC模型的承载,其实真正的功能不多,其实从模型层面上看V在前端开发中是最接近业务逻辑的,所以在View中大部分的逻辑都是开发者自己去扩展的。