注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易邮箱前端技术中心

汇聚最新最劲爆的前端技术

 
 
 

日志

 
 
 
 

浅谈Backbone  

2013-09-17 23:33:55|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
最近参与邮箱文件中心改版,因为不考虑引用邮箱的框架和前端库,对比参考一下其他框架,决定使用轻量级的Backbone。

Backbone是一个轻量级库(1.0.0版的源码 + 注释 ≈ 1500行,推荐阅读),方便开发单页面的Web应用。必须依赖Underscore.js,可选依赖jQuery。(源码:Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;)

Backbone主要提供了Model(模型)、Collection(集合)、View(视图)、Router(路由)等模块,各自负责的功能为:
Model:用于绑定数据(一个model实例类似于一个数据表中的一行数据);带有丰富的接口和强大的事件绑定;可以绑定View,因此可以通过自身状态改变触发对应DOM节点做出指定变
Collection:Model的集合,类似数组
View:生成html(建议使用模板,由一般render方法负责);管理视图所对应的Dom元素的事件绑定及子元素的事件代理;可监听对应model的状态改变,做出相应处理
Router:管理浏览器的location;实现历史记录(前进后退)功能

这些是使用Backbone开发中最常使用的。

个人觉得Backbone最重要的一个模块是Backbone.Events。任何对象(*any object*) mixed这个模块之后,就拥有可以触发自定义事件的能力(1.0.0源码约78 ~ 229行)。
上面列举的模块(包括没提到的History模块),都在定义的时候,都通过_.extend(模块.prototype, Backbone.Events, {...})引用了Events对象的方法。
由此可见,其实本质就是事件驱动(通过改变状态触发自定义事件)。

说了挺多,通过文件中心开发过程中的分页按钮控制的小例子,分享使用Backbone的开发经验。
 
顶部分页按钮:
浅谈Backbone - 网易邮箱前端技术中心 - 网易邮箱前端技术中心
底部分页按钮:
浅谈Backbone - 网易邮箱前端技术中心 - 网易邮箱前端技术中心 
这次的列表部分总共有两个工具栏(顶部和底部各一个),顶部分页还带有一个分页下拉选项,如上图所示
使用Backbone的话,可以这么处理:
整体划分为3部分,ListModel、ToolbarTopModel,对应ToolbarTopView和ToolBottomModel,对应ToolBottomView
ListModel存在两个属性,curPage和totalPage,ToolbarTopModelToolBottomModel分别监听这两个属性的变化:

// ToolbarTopModel(或者ToolBottomModel):

function fInitialize() {

this.listenTo(oListModel, 'change:curPage', fChangeCurPage);  

this.listenTo(oListModel, 'change:curTotalPage', fChangeTotalPage);

}


function fChangeCurPage() {

// 可以trigger一个changeXXX事件,然后由对应的View做处理

this.trigger('changeCurPage');

}


// ToolbarTopView(或者ToolBottomView):

function fInitialize() {

this.listenTo(this.model, 'changeCurPage', fChangeCurPage);  

}


function fChangeCurPage() {

// 各种DOM操作

}

View模块中的fChangeCurPage和fChangeTotalPage负责处理页数变化后相应的业务逻辑,比如disable掉上一页按钮(最后一个同理),只有一页时隐藏底部的分页工具栏等等。
此外,处理分页按钮以及下拉分页菜单的点击事件时,只要在事件的回调函数中改变ListModel的两个页码属性即可。
如果想人为改变分页状态的话,比如上传或者删除了N个文件导致页数变动,只需在ListModel中开放一个fSetPage(nCurPage, nTotalPage)接口,负责改变页码属性即可(改变后会触发change事件,最终会通知到view做出相应DOM操作)

作为对比,如果不使用Backbone该怎么处理呢?写到这里,本人想到的大致方法是,ListModel定义一个fSetPage(nCurPage, nTotalPage)方法,基本实现如下:

function fSetPage(nCurPage, nTotalPage) {

// 不一定存在view


// 改变顶部分页,由对应页面模块进行DOM操作

oToolbarTopModel.setPage(nCurPage, nTotalPage);


// 改变底部分页,由对应页面模块进行DOM操作

oToolbarBottomModel.setPage(nCurPage, nTotalPage);


// 保存值

this.curPage = nCurPage;

this.totalPage = nTotalPage;

}

个人觉得两种方法没有好坏之分,只要能实现需求的都是好代码…
不过,一个比较明显区别的是,假设现在想删除(或者修改或者增加一个新的)顶部的分页:
第一个种方法直接删除ToolbarTopModel及对应的View即可(新增也是类似)
第二种方法除了修改对应的Model,还得修改ListModel中的fSetPage方法(解耦得不是很彻底…)

这次开发,个人觉得Backbone也存在不足(或者是本人认识有限,不清楚Backbone已存在的解决方案):
1、强制sync,不是每个CRUD都是REST…
2、作为一个框架,模块之间的管理稍弱。
3、collection中如果add的源数据中id相同,model会被覆盖(通过多id唯一标识一个对象,多对多这种情况在网盘中还是挺常见的)
4、collection不支持多种model,比如这次文件列表开发就遇到一个列表存在多种文件,图片、文本以及文件夹等等(约10多种)…这次的解决办法是通过model的一个type属性进行区分 ⊙﹏⊙b
5、listenTo可能会造成调试不便

一些开发建议:
1、model中不要保存view实例的引用,而是应该通过让view去监听model的状态,做出对应处理。简单说就是view单向依赖model。
2、对于同时增加多个model,最好不要监听add事件,然后循环append构造列表(同理,清除一个列表时,建议不要监听collection中单个model的destroy事件,然后remove掉这个view)。本人的处理方法是加载完成之后,trigger一个事件,由view监听,然后一起渲染(销毁)。

传送门:
  评论这张
 
阅读(1983)| 评论(3)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017