用Backbone.js创建一个联系人管理系统(二)
欢迎大家回来继续这一教程,第一部分我们学习了model,collection和view在Backbone中的
基本用法,还有怎么样用主视图去绑定collection去渲染出每个Contact.
这部分我们学习怎么通过用户输入过滤视图中的数据还要怎么给我们的应用程序加入路由的功能.
响应用户输入
从第一部分你可以发现每个model都有一个属性type,这个属性可以把model分成朋友,家人,同事等等.
让我们给主视图加入一个select控件来对models进行按type类型选择的操作.
我们当然可以将select的option写死,那样显然可维护性很差.虽然我们现在还没有添加或者删除Contacts的
功能,但是肯定将来要添加的.提前透露第三部分教程我们将完成这个功能. 废话还是太多了,肯定是要从现有记录
的type里读取了. 但是之前要先在Contacts的容器里加上装载select的容器.
<header> <div id="filter"><label>Show me:</label></div> </header>
我们用个header元素包裹的指定id的div元素做容器,
下面是在主视图DirectoryView中创建select的代码.
getTypes: function () { return _.uniq(this.collection.pluck("type"), false, function (type) { return type.toLowerCase(); }); }, createSelect: function () { var filter = this.el.find("#filter"), select = $("<select/>", { html: "<option>All</option>" }); _.each(this.getTypes(), function (item) { var option = $("<option/>", { value: item.toLowerCase(), text: item.toLowerCase() }).appendTo(select); }); return select; }
collection.pluck():是Backbone.js的中方法,作用是从Collection中取出所有models的指定属性(这里是type)值得数组.
_.uniq:是Underscore.js中的方法. 去除指定数组中重复的数据. 第一个参数是数组,第二个参数是否重新排序可选true或false.
在这里是去掉pluck后得到数组里的重复元素.第三个参数为function,可以指定对每个数组元素要做的操作.
_.each:是Underscore的方法. 第一个参数是要处理的数组,第二个参数是funtion对每个数组元素的操作.这里把去掉重复数据后
的types数组的每个元分别赋给一个option的value和text属性后添加到select元素里.
最后在初始化结束后initialize()方法里把生成的select的html放入id为filter的div.
this.$el.find("#filter").append(this.createSelect());
$el为Backbone.js视图对象中缓存当前视图的JQuery对象.
过滤视图
现在我们有了select按钮,为了让按钮可以响应过滤models,我们先在主视图中添加一个events属性.
events: { "change #filter select": "setFilter" },
这样"change #filter select"(id为filter的tagName为select的子元素值变化)时候执行setFilter方法,我们在补充setFilter方法:
setFilter: function (e) { this.filterType = e.currentTarget.value; this.trigger("change:filterType"); },
在这个方法里先把select的选择结果(e.currentTarget.value)存储到局部变量filterType里,然后触发change:filterType事件.
定义当type改变时候的具体操作方法.
filterByType: function () { if (this.filterType === "all") { this.collection.reset(contacts); //重置collection } else { this.collection.reset(contacts, { silent: true }); //重置collection但不刷新页面 var filterType = this.filterType, filtered = _.filter(this.collection.models, function (item) { return item.get("type").toLowerCase() === filterType; }); this.collection.reset(filtered); } }
_.filter是Underscore.js中的方法. 过滤出指定的type的contacts.
对Collection加载监听器
最后挂载事件监听,第一个其实不是针对collection的而是自定义局部变量filterType变量监听.
this.on("change:filterType", this.filterByType, this);
每次对collection执行reset后. view并不会自动刷新前端. 所以还要为reset事件加载监听.
this.collection.on("reset", this.render, this);
这样每当view的collection执行reset. 都会重新render显示的内容.
路由
现在我们可以通过select控件来过滤Contacts,但是如果通过URL来过滤会不会更好呢. Backbone.js的router
就能实现这个功能. 很简单也是使用Backbone.router的extend();
var ContactsRouter = Backbone.Router.extend({ routes: { "filter/:type": "urlFilter" }, urlFilter: function (type) { directory.filterType = type; directory.trigger("change:filterType"); } });
用过其他MVC的router对象的一看就明白: routes属性里定义一种路由格式( "filter/:type"). 如果需要也可以扩展更多.
"urlFilter"为路由执行的方法. 下面的urlFilter是方法的实现.
最后在初始化DirectioryView后面初始化一个router.
var contactsRouter = new ContactsRouter();
然后为了解决浏览器后退问题要再上一句
Backbone.history.start();
为了在type值变化时对应浏览器url的跳转更新filterByType方法. 增加contactsRouter.navigate到指定的url
filterByType: function () { if (this.filterType === "all") { this.collection.reset(contacts); <b>contactsRouter.navigate("filter/all");</b> } else { this.collection.reset(contacts, { silent: true }); var filterType = this.filterType, filtered = _.filter(this.collection.models, function (item) { return item.get("type") === filterType; }); this.collection.reset(filtered); <b>contactsRouter.navigate("filter/" + filterType);</b> } }
最后测试一下结果
总结
这部分主要学习了Backbone.js的路由对象.和一些Underscore.js的方法. 例如_.uniq() _.filter()
下一部分教程我们会回到model,学习如何在collection中添加和删除model.
这节课代码:
http://cdn.tutsplus.com/net/uploads/legacy/1143_bb2/demo.zip