Backbone中的视图提供了一组处理DOM事件、和渲染模型(或集合)数据方法(在使用视图之前,你必须先导入jQuery或Zepto)
视图类提供的方法非常简单,我们一般在backbone.View的基础上进行扩展。但即使是特别复杂的视图类,它也应该仅仅是做界面事件、和渲染逻辑相关的操作,数据管理应该交由Model和Collection来完成,而业务逻辑应该由其它的类完成。
上述文字来自http://blog.csdn.net/eagle_110119/article/details/8842026
backbone框架图:http://www.cnblogs.com/nuysoft/archive/2012/03/19/2404274.html
1.1 定义和创建视图
先看例子1.1-1:
<div title="列表" style="color:red" id="list" class="listview"></div> <script type="text/javascript"> var ListView = Backbone.View.extend({ el : '#list' }); var listview = new ListView(); </script>
extend部分就不看,跟collection和model一样。
var ListView = Backbone.View.extend({ el : '#list' });
将el绑定到ListView的原型上,通过ListView实例化的对象可以直接使用。
下一段代码:
var listview = new ListView();
看一下View的构造器:
var View = Backbone.View = function(options) { this.cid = _.uniqueId('view');//生成关于视图的cid options || (options = {}); _.extend(this, _.pick(options, viewOptions));//将自定义属性值绑定到实例上 this._ensureElement();//调用_ensureElement方法 this.initialize.apply(this, arguments);//调用init方法 this.delegateEvents();//调用delegateEvents方法 }
先看一下underscore的pick方法
_.pick = function(obj) { var copy = {}; var keys = concat.apply(ArrayProto, slice.call(arguments, 1));//转成数组 each(keys, function(key) { if (key in obj) copy[key] = obj[key];//为copy绑定自定义的属性值,前提是属性名是viewOptions中的 }); return copy; }
将自定义的信息绑定到this实例。
这里例子略显简单,导致源码很多部分不能覆盖执行,我们给例子添加点东西,再进入_ensureElement方法,看例子1.1-2
<script type="text/javascript"> var ListView = Backbone.View.extend({ tagName : 'div', className : 'listview', id : 'list', attributes : { title : '列表', style : 'color:red' }, render : function() { this.el.innerHTML = 'Hello World!'; document.body.appendChild(this.el); } }); var listview = new ListView(); listview.render(); </script>
其中
{ tagName : 'div', className : 'listview', id : 'list', attributes : { title : '列表', style : 'color:red' }
将会被加到View的实例中。看一下_ensureElement方法
_ensureElement: function() { if (!this.el) {//没有关联页面的标签,一般是创建在页面显示 var attrs = _.extend({}, _.result(this, 'attributes'));//将attributes的信息绑定到attrs上 if (this.id) attrs.id = _.result(this, 'id');//将id传给attrs。 if (this.className) attrs['class'] = _.result(this, 'className');//将className传给attrs //至此attrs获取基本的创建标签的属性 var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);//调用第三方选择器生成标签,并注入我们自定义的属性信息,但这里还没有将该对象插入HTML页面 this.setElement($el, false); } else {//声明的时候我们定义了el this.setElement(_.result(this, 'el'), false);//调用进入setElement方法 } }
backbone在View这块,依赖一些第三方插件,比如jQuery,Zepto等。所以使用的时候,先将它们加载进来。进入setElement方法。
setElement: function(element, delegate) { if (this.$el) this.undelegateEvents();//初始化时,不执行 this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); //这里给定义,调用第三方的选择器生成dom对象(并非原生dom对象,这里我们引用的是jQuery, // 就姑且认为是jQuery对象),将我们之前生成jQuery对象传给实例的$el属性 this.el = this.$el[0];//获得原生对象 if (delegate !== false) this.delegateEvents(); return this; }
这个例子中,我们没有绑定任何事件。接着我们执行构造器中的最后一个方法delegateEvents
if (!(events || (events = _.result(this, 'events')))) return this;//没有代理事件,返回
因为没有绑定事件,这里就直接返回了。
例子中使用listview.render(),看一下render()
render: function() { //这个方法默认返回实例,使用时,可以将其重载 return this; }
声明View类时,我们已经自定义了render,这将会重载系统中原有的render,那我们来看一下自定义的render
render : function() { this.el.innerHTML = 'Hello World!'; document.body.appendChild(this.el); }
this.el是生成jQuery对象转成的原生对象。在其中添加"Hello World",最后再将它插入页面,最后显示在页面上
这里我们总结下各个属性的作用,很简单
tagName标识新标签的名称(如果没有设置,则默认是div)
className对应标签的class样式
id对应标签的id属性
1.2 处理DOM事件
可以想一下,以往我们是怎么用jQuery绑定事件的
<p> <input type="button" value="Create" id="create" /> <input type="button" value="Read" id="read" /> <input type="button" value="Update" id="update" /> <input type="button" value="Delete" id="delete" /> </p> <script type="text/javascript"> function createData() { // todo } function readData() { // todo } function updateData() { // todo } function deleteData() { // todo } $('#create').on('click', createData); $('#read').on('click', readData); $('#update').on('click', updateData); $('#delete').on('click', deleteData); </script>
那我们看一下backbone的view是如何处理dom事件的,先上个例子1.2-1
<p id="view"> <input type="button" value="Create" id="create" /> <input type="button" value="Read" id="read" /> <input type="button" value="Update" id="update" /> <input type="button" value="Delete" id="delete" /> </p> <script type="text/javascript"> var MyView = Backbone.View.extend({ el : '#view', events : { 'click #create' : 'createData', 'click #read' : 'readData', 'click #update' : 'updateData', 'click #delete' : 'deleteData' }, createData : function() { console.log('create'); }, readData : function() { console.log('read'); }, updateData : function() { console.log('update'); }, deleteData : function() { console.log('delete'); } }); var view = new MyView(); </script>
看一下View类的声明,将createDate,readData,updateData,deleteData加到了MyView的原型上。这里我们主要看一下构造器上的delegateEvents方法
delegateEvents: function(events) { if (!(events || (events = _.result(this, 'events')))) return this;//没有代理事件,返回 this.undelegateEvents();//进入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);//将类似click #create分离获取 var eventName = match[1], selector = match[2];//获取触发事件动作名,获取选择器 method = _.bind(method, this);//绑定事件,将事件绑定到View的实例上 eventName += '.delegateEvents' + this.cid; if (selector === '') {//监听事件 this.$el.on(eventName, method);//jQuery的原生on事件,低版本的jQuery注意 } else { this.$el.on(eventName, selector, method); } } return this; }
看一下undelegateEvents方法
undelegateEvents: function() { this.$el.off('.delegateEvents' + this.cid);//删除绑定事件 return this; }
创建事件之前,先将以前可能存在的事件都删除掉。这里最后绑定事件的方法其实是jQuery的on方法,所以大家在引用第三方插件的时候,注意插件的版本。
另外就是这里的绑定事件都是绑定的都是p标签,所以使用事件委任,这写button在remove掉之后,再添加进来,依旧有事件。满足动态删减dom的情况。
内容不多,时间刚好,以上是我的一点读码体会,如有错误,请指出,大家共通学习。