骨气。模型
今天我们来说说主干网中的M . js MVC . model是主干网的核心部分,它包含了页面显示内容的数据,以及围绕数据操作的各种操作,如转换、验证、计算、权限控制、服务器端交互等。您可以通过主干网生成模型。Model.extend(),当然生成的模型也可以作为基类向下扩展更多的模型。
var People=主干。model . extend({ });var Man=people . extend({ });骨气。模型Api
骨气。模型提供了大量的方法来实现模型的基本操作,当然最基本的是基于主干的事件机制。事件当模型的属性改变时,将触发相应的change:attr事件。这是提供的API:
其中,有服务器端对数据进行操作的方法:
Sync :包装主干,sync fetch :是xhr的基类,用于从服务器获取数据。保存:将数据保存到服务器。销毁:从服务器中删除数据模型中的数据操作。
Get:从属性集中获取数据:在属性中设置data escape :对数据进行编码。使用_中是否有对应的数据未设置:escape有3360个下划线属性、从属性中删除数据、清除:清除属性数据、更改:和最后状态(设置为已执行、未设置)。与更改后的值进行比较toJSON:将属性序列化为对象解析:当set item parse为true时,将解析目标数据,并在初始化/设置/取消设置/提取等数据操作中返回解析的对象。这个方法是空的。需要重写hasChanged :与前一状态(set executed,unset)相比是否有变化,changeAttributes :与前一状态(set executed,unset)相比是否有变化,以及与前一状态(set executed,unset)相比发生的所有值。该属性的值对应于previousAttributes :以及用于验证所有值模型中的数据是否处于已更改对象的先前状态(已设置、未设置)的方法:
Validate:用于验证模型中的数据,需要重写该数据以覆盖默认方法validationError :返回最后一个无效值时返回的值是有效的:调用_validate方法。下面将解释一些关键的API。
构造器
var模型=主干。Model=function(属性,选项){ var attrs=attributes | | { };选项||(选项={ });this.cid=_。uniqueId(' c ');this . attributes={ };if(options . collection)this . collection=options . collection;if(options . parse)attrs=this . parse(attrs,options)| | { };attrs=_。默认值({},attrs,_。结果(这是“默认值”);this . set(attr,options);this . changed={ };this.initialize.apply(this,参数);};构造函数主要设置初始化数据和选项,然后生成唯一的cid来标记模型。如果在选项中解析为真,将通过解析方法解析初始值,并调用set方法。所有初始值将存储在属性中,并将调用initialize方法。模型被初始化。
设置
模型。set (attributes,[options]) set方法会将值设置到属性中。将slip设置为true时,会触发相应的change:attr事件,最终统一触发change事件。set方法的部分代码如下:
set:函数(键、值、选项){ //.//键值可以是键值对,也可以是一个字符串,将赋值传入attrs属性中if(key的类型==' object '){ attrs=key;options=val } else {(attrs={ })[key]=val;} //.//对设置的值进行校验if(!这个验证(属性,选项))返回options.unset//未设置为真实的时会删除设置的值,未设置方法就是通过set(key,val,{unset:true})去实现的//当对象正在被被设置的时候,不给先前属性赋值if(!改变){这个_previousAttributes=_ .克隆(这个。属性);这个。已更改={ };} current=this.attributes,prev=this ._ previousAttributes//如果对身份进行了设置,则对对象的编号属性也进行改变if(attr中的这个。IDattribute)这个。id=attrs[this。IDattribute];//进行设置或者是删除操作for(attr中的attr){ val=attr[attr];if(!_.isEqual(当前[attr],val))更改。push(attr);if(!_.isEqual(prev[attr],val)){ this。已更改[attr]=val;//为模型的改变的进行设置} else {删除此内容。已更改[attr];}取消设置?删除当前[attr] :当前[attr]=val;//如果复原被设置成真实的了,则进行删除操作} //在沉默的不为错误的的情况下,进行变更:属性事件发送if(!无声){ if (changes.length)这个_待定=选项;for (var i=0,l=changes.lengthI li ) { this.trigger('change: '更改[i],此,当前[更改[i]],选项);} } //触发变化事件如果(改变)返回这个;if(!沉默){ while(这个_pending) { options=this ._待定;这个. pending=false this . trigger(' change ',this,options);} }这个_ pending=false这个_ changing=false归还这个;}集的整个流程就是对传入的数值进行处理,变成一个键值对,然后对数值进行校验,检查正确性,然后开始进行设置操作,设置时检查数值时候是发生改变的,如果有则加入一个改变了的对象中,然后检查复原的值,进行相应的添加更新删除操作。然后依次触发变更:属性和变化事件。
救援
模特。保存([属性]、[选项])保存方法用于向客户端持久化数据,会根据数据的不同和配置的不同选择使用创建、更新或者是补丁,并且触发同步事件,以下为部分代码:
save:函数(键、值、选项){ //.//当设置了等待属性真实的的时候,保存方法先不执行设置方法(不触发变化事件),只执行验证if(attr!options.wait) { if(!这个。设置(属性,选项))返回false} else { if(!这个验证(属性,选项))返回false} //如果等待为没错,设置这个。属性if(attrs选项。等等){这个。属性=_ .extend({},attributes,attrs);} //.定义变量模型=这个;var success=options . success options。成功=功能(resp){//确保在同步保存过程中恢复属性模型.属性=属性;var serverAttrs=模型。解析(resp,options);//如果等待为没错,那么会在请求返回之后才进行设置操作if (options.wait) serverAttrs=_ .extend(attrs || {},serverAttrs);if (_ .isObject(服务器属性)!model.set(serverAttrs,options)){ return false;}如果(成功)成功(模型分别是,选项);//触发同步事件model.trigger('sync ',model,resp,options);};//生成XHR奥内尔回调函数wrapError(这个,选项);//选择方法method=this.isNew()?create' : (options.patch?补丁' : '更新');if(method===' patch ')选项。attrs=attrsxhr=this.sync(方法、这个、选项);//恢复属性if(attrs选项。等等)这个。属性=属性;//返回xhr对象返回xhr}保存中最需要注意的就是等待的设置,当等待为真的时候,保存返回会在xhr返回之后再执行设置操作,而不是在xhr之前就进行设置操作,因此变化事件的触发时机也就不同了。
之前说过整个毅力都是通过事件串联起来的,所以对于事件触发时机的了解和把握是非常重要的,不然会在开发过程中导致一些奇怪的问题出现。
骨气。视角前面已经对毅力中的事件、模型、集合代码进行了分析,现在我们来看下手动音量调节中的V部分,也就是骨气。视图,视图在毅力中主要用于沟通页面中的数字正射影像图和骨气。模型/集合,页面的逻辑操作唐事件的绑定等,视图部分的代码非常简答,加上注释只有110左右视图部分有一下API:
方法不多,下面对部分应用程序接口进行介绍:
构造方法
var viewOptions=['model ',' collection ',' el ',' id ',' attributes ',' className ',' tagName ',' events '];var视图=主干视图=功能(选项){ this.cid=_ .uniqueId(' view ');选项||(选项={ });_.扩展(这个,_。pick(选项,视图选项));这个. EnsureElement();this.initialize.apply(这个,参数);这个。delegate events();};构造方法中为视角生成了一个唯一的cid,以视图开头,然后进行对目标属性视图选项进行合并,接着调用_ensureElement判断埃尔的情况,接着调用delegateEvents进行方法绑定,初始化完成。
delegateEvents
view.setElement(元素)setElement:函数(元素,委托){如果(这个).$ El)这个。underegateevents();//如果已经存在这个$el,进行事件解绑//对$el进行赋值,本质是一个jquery或者是洛达什和泽普托对象这个$el=主干的元素实例。$ ?元素:主干。$(元素);//把数字正射影像图元素赋值给el this.el=这个$ El[0];//如果没有显式传值,则进行事件绑定如果(委托!==false)这个。delegate events();归还这个;}setElement方法用于设置视角对应的元素,这个方法在新的的时候会被调用,如果想要在使用过程中改变视角的数字正射影像图元素指向,可调用这个方法进行重新设置
_ensureElement
_ ensureelement : function(){//如果已经设置了el,直接调用setElement方法if(!This.el) {//如果没有设置,生成一个element对象,然后调用setElement方法varattrs=_。extend ({},_。结果(这是“属性”);if (this.id) attrs.id=_。结果(这个,‘id’);if(this . class name)attrs[' class ']=_。结果(这个,‘class name’);var $el=主干。$('' _.结果(这是“标记名”)。attr(attr);this.setElement($el,false);} else { this.setElement(_)。结果(这个,‘El’),假的);} }_ensureelement是一个内部方法,在构造函数中用来判断页面中是否存在指定的El。如果它存在,它将为$el赋值,如果它不存在,它将生成一个$el,但是应该注意的是,这个对象还没有在dom树中着陆。
delegateEvents
delegateEvents([events]) //*{ '事件选择器' : '回调' }* ////{ //'mousedown。标题' : '编辑',//'点击。按钮' : '保存',//'点击。open' :函数(e){ 0.}///}委托事件:函数(事件){//如果事件不存在,直接返回if(!(事件||(事件=_)。result(this,' events ')))返回this;//首先解除所有事件的绑定this . underegateevents();//为(事件中的var key){ var method=events[key]处理每个事件;//解析回调函数if(!_.isFunction(method))方法=this[events[key]];if(!方法)继续;//分析选择器varmatch=key . match(delegateevent splitter);var eventName=match[1],选择器=match[2];方法=_。bind(方法,this);//绑定的事件名称由“event name”组成。delegateEvents的cid。//通过这样做,可以在取消删除事件时选择该视图中的所有事件。eventname='。delegateevents ' this.cidif(选择器==='') { this。$el.on(eventName,method);} else { this。$el.on(eventName,选择器,方法);} }返回此;}在视图中,您可以使用key:value值集来指定相应的事件。在初始化期间,构造函数将调用delegateEvents进行绑定。需要注意的是,key中指定的所有元素的父元素必须是$el,这意味着元素必须是$el的子元素,否则绑定会失败。
视图和其他主干模块的一个区别是,它没有自己的内置自定义事件。当然,它还结合了Events模块,但是所有的事件都需要自己构建。视图主要是一个MVC模型的承载,其实真正的功能并不多。其实从模型层面来说,V在前端开发中最接近业务逻辑,所以View中的大部分逻辑都是开发人员自己扩展的。