前言
在前一篇读源码主要是把逻辑清楚部分了,但是MVC之间数据数据的处理和相关细节,还是存在一定的隔膜,这篇就来试试各个多个实例,看看数据在MVC之间怎样进行流动和操作。
step 1 View的简单使用
第一步还是从View开始,由于前端的特性,MVC模式在前端的应用归根结底不管中间如何玩花样,到了最后还是要把数据渲染到浏览器来,这是最最根本的事情。而数据渲染这个环节,无论如何该有一个目标渲染的数据,这里model和collection都是可以。先试试最简单的用model配合view输出一个helloworld。
纯View
我们先来看看View来渲染一个写死的数据(没有model和collection配合)是怎样的:
在这个例子中,整个数据仅仅是直接传参进去人后通过render进行dom渲染。
最后出来的dom是这样的
1 | <div data-index="1" data-test="test" id="view" class="viewClass">Hello World</div> |
这里需要说的是三个参数:id,className和attributes,这三个函数在没有指定el的情况下会自动生成DOM,然后将id,className作为id和class给其设置好(事实上还有一个tagName属性也可以设置),然后attributes遍历也设置好。
这是其中一种用法,自动生成dom然后按逻辑渲染,但是除此以外我们还可以直接对已经有的DOM进行重绘:
JS Bin on jsbin.com
View&Model
这里先随便标记一下。回头再来看这个细节。我们先找个model配合view来渲染下页面:
JS Bin on jsbin.com
这个例子和之前变化不大,只是实例化了一个model,然后使用get的方法取出了值进行渲染
View&Collection
Collection往往是诸多数据的集合,常用的场景往往就是遍历输出。配合遍历输出的往往有复杂模板,但是这里仅仅输出纯文本好了。像下面的:
JS Bin on jsbin.com
分析
至此预想的step1实验到此就完毕了。我们来分析一下这些情况是如何产生的逻辑:
- 设置el和不设置el时候View生成的dom
- Model和Collection数据如何被View使用的。
el相关:
先看View的构造函数:
1 | var View = Backbone.View = function(options) { |
关于el不同的处理方式就在 _ensureElement
方法中:
1 | _ensureElement: function() { |
这段代码很容易,似乎无需说什么了,只有两个很简单的分支,顺便把用到的方法也贴出来。存在el还是不存在el情况下目标元素的设置和选定。
唯一需要说明下的_.result可以点击下进去查看细节,这里不详解。
Model和Collection数据如何被View使用
构造函数已经被贴过了,关于model和collection的设置其实还在el被设置之前。这里只贴关键代码行,整体看前面。
1 | _.extend(this, _.pick(options, viewOptions)); |
很简单的玩意儿,哈哈,但是不看用法时候还真不知道用来为何这样写。
这里顺便贴下_.pick的用法,我认为相当于一个过滤方法。
不过还是简单说一句吧。这段代码的意思,从options中取出数组中指定的属性,使用extend加到this上。而这个this一般使用时候指向new出来的实例。
View初始化
View还是存在一个初始化的接口的,这是因为很多代码需要一实例化立即进行渲染之类的操作,上面我们使用自己的设置的render来处理这个,这里我们换个方式来做:
JS Bin on jsbin.com
只是非常简单的换了下上面demo的写法,加了一个initialize属性,调用render方法初始化,这样后面就无需手动view.render()了。
1 | this.initialize.apply(this, arguments); |
这是这段代码的功劳了。但是需要注意的是initialize比自定义的render时机要早,很多情况下可能使用它来初始化this.template这个属性,也就是设置模板。
View的事件绑定(非View&Event)
现代WEB应用,几乎没有那个应用没有进行事件绑定了。这是一个刚需的功能性需求。
我们来看看如何在View中进行事件绑定。
先看个demo:
JS Bin on jsbin.com
这个demo上绑定了两个很简单的事件 click和mouseover
事件的绑定,写在了setElement方法中,这个方法在View的构造函数里面有调用。看看这个方法的细节:
1 | // Set callbacks, where `this.events` is a hash of |
事件绑定关键的代码在line22-23,我们聚焦这一块。
- 它首先将events属性名切割成事件名称和选择器两个,作为属性传入delegate,随之传入的还有method,这里使用_bind将method事件方法的上下文绑定到当前视图对象, 因此在事件被触发后, 事件方法中的this始终指向视图对象本身.
- 然后看delegate:看完有些sb的感觉了。。。它使用jQuery等库的on函数来处理的事件绑定,并没有自己实现一下,jQuery的on可以去看看语法。唯一的问题是
eventName + '.delegateEvents' + this.cid
运算的结果类似这样:keypress.delegateEventsview1,多了后面一截命名空间,何故呢?看看undelegateEvents内部通过’.delegateEvents’ + this.cid参数进行off解绑就明白了!
小结
Backbone.View的分析就此告落了。最后一段事件的分析,让我们可以联想到之前对事件机制的猜想,之前读源码时候还以为全部是Pub/Sub模式感到不解,现在可以得出最终结论了:Backbone确实是使用Pub/Sub模式,但是在View上它巧妙运用了第三方库来实现事件处理。实质上是混合了二者。
step2 Model
Model基本属于数据表里面代表一行的数据,这个类型的数据基本没有太多可以多说的数据流问题。
在Model的实例中,实例的数据存放在attributes这个对象中,诸多方法,也都是依托CURD这个对象来实现。这个事情也只能这样做。因为数据最终需要有个地方存放,即使不叫attributes,那么也可能叫做attrs或者data之流。
这里仅仅简要说明一下Model里面常用到的一些功能。并没有太多新意。
1 | # get获取数据 |
step3 Collection
如果说Model是一个row,那么collection就是一个table。Collection的方法应该是偏向集化操作的。
Collection是Model的Collection,明确这一点非常重要。这是数据集合的统一性质要求,是Sql数据表的存储要求,也是ORM这一原则的要求。
我们来看看如何设置一个简单的Collecion:
大致就是专业的一个东西,这里简单的使用了一下Collection上的API,从思路上来说,一切都是对实例上models属性的操作。这个操作,非常大程度上参考了Array的api,有pop,push,shift,unshift,slice等等操作,细节上可能会有不同,但是都是对models属性的操作。
细节就不表了,感觉数组用了这么久,不需要。
不是总结的总结
本来以为要浪费N多少时间在Modle和Colletion上,后来发现其实真的不需要,反而是View占用了大多数篇幅。
有朋友说Backbone写起来很随意,看了这么多,发现真的是很随意。除了改了N年的细节和兼容,Backbone是一个你理解架构就可以自己去山寨的一个不算库的库,虽然不会比它好。
MVC是backbone的核心,到现在基本是理清了。虽然很多细节没有提及,但是感觉不需要了。
Model就像是对闭包内数据的读写操作,而Collecion则相当于对闭包内数组的读写。
而View算是Backbone整体架构的最新展现者,但是它功能和API也真的是太简单,差不多一个巴掌可以数过来的API,也就涵盖了DOM生成选定,模板渲染和数据绑定三个环节的东西,没有一丝累赘。
有一句实话是,backbone虽然设计精巧,但是看下来确实有些失望。因为此番收获的确实不太多。或许没有精熟各个细节是大原因。下一篇有空打算把Sync和Router整理一番。做个收尾。
最后贴个链接在这里,算是自己的读源码历程的一个反思: 程序员阅读源码是一种什么心态?源码对编程意义何在?如何才能更好阅读代码?
深以为:debug能力是程序员生涯中最重要的能力之一,源码不是小说没有情节,也记不住细节,读源码的意义,除了在文档缺乏情况下可以找到使用方法,也是熟悉各种编程思想的最佳位置之一。