前言: 我们继续使用上一次写的图书案例,在基础上面进行改进!
事件绑定
在我们浏览网页的时候,获取数据并不是一下只就全部获取到的,为了创建一个更好的用户体验,就来模拟一个加载(Spinner)
的图片来告诉用户正在获取数据中!
当用户在浏览详细视图(books/:BookName)
,只需要调用加载数据的方法。然后,因为设置了正确的监听器,当接受到新的数据的时候,视图就会自动更新。数据更新的时候,Backbone
支持多事件和自定义事件。
改变路由程序里面的代码:
// 渲染Books页面
loadBook: function (bookName){
this.bookView.loadBook(bookName);
}
除了bookView
类,其他都不会改变。添加构造函数或者initialize
方法,initialize
方法是Backbone
里面的一个特殊的字符属性。每个实例初始化的时候都会调用这个属性对应的方法。
然后使用两个事件——change
和spinner
的自定义事件。我们将使用on()
(别名bind
)函数。
initialize: function (){
this.model = new (Backbone.Model.extend({}));
this.model.bind('change', this.render, this);
this.bind('spinner', this.showSpinner, this);
}
上面的代码做了两件简单的事情:
- 当模型改变时候调用
render()
函数 - 当事件
spinner
触发时调用showSpinner()
函数
然后spinner
怎么办呢?,那就用一个简单的gif图片把!在bookView
里创建一个新的属性:
templateSpinner: '<img src="img/loding.gif">'
spinner
图片(上网找一大堆):
接着回到一开始那个loadBook
函数里面,继续写代码:
loadBook: function (bookName){
this.trigger('spinner');
// 出现加载图片
var me = this;
// 需要在闭包访问this
setTimeout(function (){
// 模拟从服务器获取数据要的时间
me.model.set(me.collection.where({
name: bookName
})[0].attributes);
}, 1000);
}
里面触发了spinner
事件,还有为了解决作用域的问题,需要在闭包里面访问this
。
setTimerout
是为了模拟从服务器获取响应的时间。在它内部里面,使用model.set()
和model.attributes
(返回模型属性)把选中的模型赋值给当前视图的模型。
最后把render
函数里面多余的代码去掉,实现showSpinner
函数:
render: function (bookName){
var bookHtml = this.template(this.model);
$('body').html(bookHtml);
},
showSpinner: function (){
$('body').html(this.templateSpinner);
}
让后打开浏览器访问index.html#books/book1
,如果可以看到加载的图片的话,就证明成功啦!
最后附上完整的代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>backbone日常练习</title>
</head>
<body>
<p><a href="#books/book1">bg</a></p>
<script src="js/jquery.min.js"></script>
<script src="js/Underscore.min.js"></script>
<script src="js/backbone-min.js"></script>
<script>
var app;
// 图书数据库
var booksData = [
{
name: 'book1',
url: 'img/1.jpg'
},
{
name: 'book2',
url: 'img/2.jpg'
}
];
var router = Backbone.Router.extend({
routes: {
'': 'home',
'books/:bookName': 'loadBook'
},
initialize: function (){
// 一些在对象初始化的时候执行的代码
var books = new Books();
books.reset(booksData);
this.homeView = new homeView({collection: books});
this.bookView = new bookView({collection: books});
},
home: function (){
this.homeView.render();
},
// 渲染Books页面
loadBook: function (bookName){
this.bookView.loadBook(bookName);
}
});
var homeView = Backbone.View.extend({
el: 'body',
template: _.template('books data: <%= data %>'),
render: function (){
this.$el.append(this.template({
data: JSON.stringify(this.collection.models)
}));
}
// TODO 子视图
});
var Books = Backbone.Collection.extend({});
// books 视图
var bookView = Backbone.View.extend({
initialize: function (){
this.model = new (Backbone.Model.extend({}));
this.model.bind('change', this.render, this);
this.bind('spinner', this.showSpinner, this);
},
template: _.template(
'<h2><%= attributes.name %></h2><img src="<%= attributes.url %>">'
),
templateSpinner: '<img src="img/loding.gif">',
loadBook: function (bookName){
this.trigger('spinner');
// 出现加载图片
var me = this;
// 需要在闭包访问this
setTimeout(function (){
// 模拟从服务器获取数据要的时间
me.model.set(me.collection.where({
name: bookName
})[0].attributes);
}, 1000);
},
// TODO 用加载图书过程和事件绑定来重写
render: function (bookName){
var bookHtml = this.template(this.model);
$('body').html(bookHtml);
},
showSpinner: function (){
$('body').html(this.templateSpinner);
}
});
$(function (){
app = new router;
Backbone.history.start();
});
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。