Backbone前端框架核心及源码解析
Backbone是一款前端框架,它的核心是提供了MVC架构中Model(模型)和Collection(集合),以及View(视图)和Router(路由)的基础实现。Backbone的源码易读易懂,阅读源码可以对JavaScript编程有更深刻的理解。
1. Model和Collection
Model
Model表示前端程序中的业务模型。Model对象提供了数据的接口;保存数据,处理数据,触发对View(视图)的更新。在Backbone中,通过继承Backbone.Model
来定义一个Model类,通过以下代码实现:
var Book = Backbone.Model.extend({});
在定义了Model类之后,还要定义Model的实例,创建Model实例时可以通过定义默认的数据值:
var Book = Backbone.Model.extend({
defaults: {
title: 'unknown',
author: 'unknown'
}
});
var book1 = new Book({ title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' });
console.log(book1.get('title')); // "The Lord of the Rings"
console.log(book1.get('author')); // "J.R.R. Tolkien"
Collection
Collection表示一组Model对象。Collection把Model视为一个整体,可以进行Model的批量操作。在Backbone中,通过继承Backbone.Collection
来定义一个Collection类,通过以下代码实现:
var Books = Backbone.Collection.extend({
model: Book
});
在定义了Collection类之后,还要定义Collection的实例,可以通过add()和remove()方法操作Collection对象:
var books = new Books();
var book1 = new Book({ title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' });
var book2 = new Book({ title: 'The Hobbit', author: 'J.R.R. Tolkien' });
var book3 = new Book({ title: 'Harry Potter and the Philosopher\'s Stone', author: 'J.K. Rowling' });
books.add(book1);
books.add(book2);
books.add(book3);
console.log(books.length); // 3
books.remove(book2);
console.log(books.length); // 2
2. View和Router
View
View表示前端程序中的用户界面。View对象接收Model数据,通过模板引擎将数据渲染成html,然后更新到指定的DOM元素上。在Backbone中,通过继承Backbone.View
来定义一个View类,通过以下代码实现:
var BookView = Backbone.View.extend({
tagName: 'div',
className: 'book-item',
template: _.template('<h2><%= title %></h2><p><%= author %></p>'),
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
在定义了View类之后,还要定义View的实例,通过指定el属性来指定渲染后的html插入到哪个DOM元素内部:
var book1 = new Book({ title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' });
var bookView = new BookView({ model: book1 });
$('#app').append(bookView.el);
Router
Router负责页面的路由控制和处理。Router对象监听URL变化(hashchange事件),响应URL变化,收集路由参数,调用对应的Controller方法。在Backbone中,通过继承Backbone.Router
来定义一个Router类,通过以下代码实现:
var AppRouter = Backbone.Router.extend({
routes: {
'books/:id': 'showBook'
},
showBook: function (id) {
var book = books.get(id);
var bookView = new BookView({ model: book });
$('#app').html(bookView.el);
}
});
在定义了Router类之后,还要定义Router的实例,启动Backbone的history:
var router = new AppRouter();
Backbone.history.start();
使用hash值#books/123
访问页面,Router会捕捉到books/:id
的URL,调用对应的showBook方法。showBook方法获取该book的模型数据,使用BookView进行渲染,最后更新到指定的DOM元素上。
3. 示例
示例1:一个简单的待办事项列表
var Todo = Backbone.Model.extend({
defaults: function () {
return {
title: '',
completed: false
};
},
toggle: function () {
this.save({
completed: !this.get('completed')
});
}
});
var TodoList = Backbone.Collection.extend({
model: Todo,
localStorage: new Backbone.LocalStorage('todos-backbone'),
completed: function () {
return this.where({ completed: true });
},
remaining: function () {
return this.where({ completed: false });
}
});
var Todos = new TodoList();
var TodoView = Backbone.View.extend({
tagName: 'li',
template: _.template('<span class="title"><%= title %></span>'),
events: {
'click .title': 'toggleCompleted'
},
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
render: function () {
this.$el.toggleClass('completed', this.model.get('completed'));
this.$el.html(this.template(this.model.toJSON()));
return this;
},
toggleCompleted: function () {
this.model.toggle();
}
});
var AppView = Backbone.View.extend({
el: '#app',
statsTemplate: _.template('<span><%= remaining %> items left</span><span><%= completed %> items completed</span>'),
events: {
'keypress input': 'addTodo'
},
initialize: function () {
this.$input = this.$('input');
this.$list = this.$('#todo-list');
this.listenTo(Todos, 'add', this.addTodoView);
this.listenTo(Todos, 'reset', this.addAll);
this.listenTo(Todos, 'change:completed', this.filterOne);
this.listenTo(Todos, 'filter', this.filterAll);
Todos.fetch({ reset: true });
},
render: function () {
this.$list.empty();
Todos.each(function (todo) {
var view = new TodoView({ model: todo });
this.$list.append(view.render().el);
}, this);
this.renderStats();
},
renderStats: function () {
var completed = Todos.completed().length;
var remaining = Todos.remaining().length;
this.$('#todo-stats').html(this.statsTemplate({ completed: completed, remaining: remaining }));
},
addTodo: function (e) {
if (e.keyCode != 13) return;
if (!this.$input.val().trim()) return;
Todos.create({ title: this.$input.val().trim() });
this.$input.val('');
},
addTodoView: function (todo) {
var view = new TodoView({ model: todo });
this.$list.append(view.render().el);
},
addAll: function () {
Todos.each(this.addTodoView, this);
},
filterOne: function (todo) {
TodoView.hide(todo.get('completed'));
},
filterAll: function () {
Todos.each(this.filterOne, this);
}
});
var App = new AppView();
在HTML中添加必要的DOM元素:
<body>
<div id="app">
<input type="text" placeholder="What need to be done?">
<span id="todo-stats"></span>
<ul id="todo-list"></ul>
</div>
</body>
示例2:简单路由控制
var HomePageView = Backbone.View.extend({
el: '#app',
template: _.template('<h1>Backbone Home Page</h1>'),
render: function () {
this.$el.html(this.template());
return this;
}
});
var AboutPageView = Backbone.View.extend({
el: '#app',
template: _.template('<h1>About Us</h1><p>This is the about us page</p>'),
render: function () {
this.$el.html(this.template());
return this;
}
});
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'about': 'about'
},
home: function () {
var homePageView = new HomePageView();
homePageView.render();
},
about: function () {
var aboutPageView = new AboutPageView();
aboutPageView.render();
}
});
var router = new AppRouter();
Backbone.history.start();
在HTML中添加必要的DOM元素:
<body>
<div id="app"></div>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#about">About Us</a></li>
</ul>
</body>
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Backbone前端框架核心及源码解析 - Python技术站