$(function(){
由 Jérôme Gravel-Niquet 贡献的 Backbone 示例应用程序。此演示使用简单的 LocalStorage 适配器 在浏览器中持久化 Backbone 模型。
DOM 准备就绪后加载应用程序,使用 jQuery.ready
$(function(){
我们的基本 Todo 模型具有 title
、order
和 done
属性。
var Todo = Backbone.Model.extend({
Todo 项目的默认属性。
defaults: function() {
return {
title: "empty todo...",
order: Todos.nextOrder(),
done: false
};
},
切换此 Todo 项目的 done
状态。
toggle: function() {
this.save({done: !this.get("done")});
}
});
Todo 集合由 localStorage 支持,而不是远程服务器。
var TodoList = Backbone.Collection.extend({
对该集合模型的引用。
model: Todo,
将所有 Todo 项目保存在 "todos-backbone"
命名空间下。
localStorage: new Backbone.LocalStorage("todos-backbone"),
筛选所有已完成的 Todo 项目列表。
done: function() {
return this.where({done: true});
},
筛选列表,仅显示尚未完成的 Todo 项目。
remaining: function() {
return this.where({done: false});
},
我们按顺序保存 Todo,尽管它们在数据库中按无序 GUID 保存。这会为新项目生成下一个顺序号。
nextOrder: function() {
if (!this.length) return 1;
return this.last().get('order') + 1;
},
Todo 按其原始插入顺序排序。
comparator: 'order'
});
创建我们的全局 Todos 集合。
var Todos = new TodoList;
Todo 项目的 DOM 元素…
var TodoView = Backbone.View.extend({
… 是一个列表标签。
tagName: "li",
缓存单个项目的模板函数。
template: _.template($('#item-template').html()),
特定于项目的 DOM 事件。
events: {
"click .toggle" : "toggleDone",
"dblclick .view" : "edit",
"click a.destroy" : "clear",
"keypress .edit" : "updateOnEnter",
"blur .edit" : "close"
},
TodoView 监听其模型的变化,重新渲染。由于此应用程序中 Todo 和 TodoView 之间存在一对一对应关系,因此为了方便起见,我们在模型上设置了直接引用。
initialize: function() {
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.remove);
},
重新渲染 Todo 项目的标题。
render: function() {
this.$el.html(this.template(this.model.toJSON()));
this.$el.toggleClass('done', this.model.get('done'));
this.input = this.$('.edit');
return this;
},
切换模型的 "done"
状态。
toggleDone: function() {
this.model.toggle();
},
将此视图切换到 "editing"
模式,显示输入字段。
edit: function() {
this.$el.addClass("editing");
this.input.focus();
},
关闭 "editing"
模式,保存对 Todo 的更改。
close: function() {
var value = this.input.val();
if (!value) {
this.clear();
} else {
this.model.save({title: value});
this.$el.removeClass("editing");
}
},
如果按 enter
键,则表示已完成编辑项目。
updateOnEnter: function(e) {
if (e.keyCode == 13) this.close();
},
删除项目,销毁模型。
clear: function() {
this.model.destroy();
}
});
我们的整体 AppView 是 UI 的顶层部分。
var AppView = Backbone.View.extend({
不生成新元素,而是绑定到 HTML 中已存在的应用程序骨架。
el: $("#todoapp"),
应用程序底部统计行模板。
statsTemplate: _.template($('#stats-template').html()),
用于创建新项目和清除已完成项目的委托事件。
events: {
"keypress #new-todo": "createOnEnter",
"click #clear-completed": "clearCompleted",
"click #toggle-all": "toggleAllComplete"
},
在初始化时,我们绑定到 Todos
集合上的相关事件,当项目添加或更改时。通过加载可能保存在 localStorage 中的任何预先存在的 Todo 来启动操作。
initialize: function() {
this.input = this.$("#new-todo");
this.allCheckbox = this.$("#toggle-all")[0];
this.listenTo(Todos, 'add', this.addOne);
this.listenTo(Todos, 'reset', this.addAll);
this.listenTo(Todos, 'all', this.render);
this.footer = this.$('footer');
this.main = $('#main');
Todos.fetch();
},
重新渲染应用程序仅意味着刷新统计信息 - 应用程序的其余部分不会改变。
render: function() {
var done = Todos.done().length;
var remaining = Todos.remaining().length;
if (Todos.length) {
this.main.show();
this.footer.show();
this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
} else {
this.main.hide();
this.footer.hide();
}
this.allCheckbox.checked = !remaining;
},
通过为其创建视图并将元素附加到 <ul>
中,将单个 Todo 项目添加到列表中。
addOne: function(todo) {
var view = new TodoView({model: todo});
this.$("#todo-list").append(view.render().el);
},
一次性添加 Todos 集合中的所有项目。
addAll: function() {
Todos.each(this.addOne, this);
},
如果在主输入字段中按回车键,则创建新的 Todo 模型,并将其持久化到 localStorage。
createOnEnter: function(e) {
if (e.keyCode != 13) return;
if (!this.input.val()) return;
Todos.create({title: this.input.val()});
this.input.val('');
},
清除所有已完成的 Todo 项目,销毁其模型。
clearCompleted: function() {
_.invoke(Todos.done(), 'destroy');
return false;
},
toggleAllComplete: function () {
var done = this.allCheckbox.checked;
Todos.each(function (todo) { todo.save({'done': done}); });
}
});
最后,我们通过创建 App 来启动操作。
var App = new AppView;
});