Backbone.js MVC架构理解 #
一、MVC模式概述 #
1.1 什么是MVC #
MVC(Model-View-Controller)是一种软件架构模式,将应用程序分为三个核心组件:
text
┌─────────────────────────────────────────────────────────┐
│ MVC模式 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌───────────┐ │
│ │ Model │◄───────►│ View │ │
│ │ (模型) │ │ (视图) │ │
│ └────┬────┘ └─────┬─────┘ │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Controller │ │
│ │ (控制器) │ │
│ └─────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
1.2 MVC各组件职责 #
| 组件 | 职责 | Backbone对应 |
|---|---|---|
| Model | 管理数据、业务逻辑 | Backbone.Model |
| View | 展示数据、用户界面 | Backbone.View |
| Controller | 处理用户输入、协调Model和View | Router + View |
1.3 Backbone的MVC变体 #
Backbone.js 实际上采用的是 MVP(Model-View-Presenter)或 MVVM 的变体:
text
Backbone架构
├── Model:数据层
├── Collection:数据集合层
├── View:视图层 + 控制器逻辑
└── Router:路由控制层
二、Backbone组件关系 #
2.1 组件交互图 #
text
┌─────────────────────────────────────┐
│ Router │
│ (路由控制) │
└──────────────┬──────────────────────┘
│
│ 导航
▼
┌──────────────┐ ┌─────────────────────────┐
│ Model │◄───────►│ View │
│ (数据) │ │ (视图 + 控制器逻辑) │
└──────────────┘ └───────────┬─────────────┘
▲ │
│ │
│ 数据 │ DOM事件
│ │
│ ┌───────────────────┴───────────────────┐
│ │ │
│ ▼ ▼
│ ┌─────────────┐ ┌─────────────────┐
│ │ Collection │ │ DOM Events │
│ │ (数据集合) │ │ (用户交互) │
│ └─────────────┘ └─────────────────┘
│ │
│ │
└─────────┘
2.2 数据流向 #
text
用户操作 → View捕获事件 → 更新Model → Model触发事件 → View更新UI
三、Model(模型) #
3.1 Model的职责 #
javascript
var User = Backbone.Model.extend({
defaults: {
name: '',
email: '',
age: 0
},
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
if (attrs.age < 0) {
return '年龄不能为负数';
}
},
initialize: function() {
console.log('User模型已创建');
}
});
Model核心职责:
| 职责 | 方法 | 说明 |
|---|---|---|
| 数据存储 | get/set | 存取属性值 |
| 数据验证 | validate | 验证数据有效性 |
| 数据持久化 | save/fetch/destroy | 与服务器同步 |
| 事件通知 | trigger | 通知数据变化 |
3.2 Model的生命周期 #
text
创建 → 初始化 → 设置属性 → 验证 → 保存 → 更新 → 销毁
│ │ │ │ │ │ │
└────────┴─────────┴────────┴───────┴───────┴───────┘
触发事件
3.3 Model事件流 #
javascript
var user = new User();
user.on('change', function() {
console.log('属性已变化');
});
user.on('change:name', function(model, value) {
console.log('姓名已变更为:', value);
});
user.set('name', '张三');
四、Collection(集合) #
4.1 Collection的职责 #
javascript
var Users = Backbone.Collection.extend({
model: User,
url: '/api/users',
comparator: 'name',
initialize: function() {
console.log('Users集合已创建');
}
});
var users = new Users([
{ name: '张三', age: 25 },
{ name: '李四', age: 30 }
]);
Collection核心职责:
| 职责 | 方法 | 说明 |
|---|---|---|
| 模型管理 | add/remove/reset | 添加、移除、重置模型 |
| 查询过滤 | find/filter/where | 查找和过滤模型 |
| 排序 | sort/comparator | 排序模型 |
| 批量操作 | fetch/create | 批量获取和创建 |
4.2 Collection与Model的关系 #
text
Collection (Users)
│
├── Model (User) { name: '张三', age: 25 }
│
├── Model (User) { name: '李四', age: 30 }
│
└── Model (User) { name: '王五', age: 28 }
4.3 Collection事件代理 #
javascript
var users = new Users();
users.on('add', function(model) {
console.log('添加了用户:', model.get('name'));
});
users.on('remove', function(model) {
console.log('移除了用户:', model.get('name'));
});
users.add({ name: '张三' });
users.remove(users.at(0));
五、View(视图) #
5.1 View的职责 #
javascript
var UserView = Backbone.View.extend({
tagName: 'div',
className: 'user-item',
template: _.template(
'<span class="name"><%= name %></span>' +
'<span class="age"><%= age %>岁</span>' +
'<button class="edit">编辑</button>' +
'<button class="delete">删除</button>'
),
events: {
'click .edit': 'editUser',
'click .delete': 'deleteUser'
},
initialize: function() {
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.remove);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
editUser: function() {
console.log('编辑用户:', this.model.get('name'));
},
deleteUser: function() {
this.model.destroy();
}
});
View核心职责:
| 职责 | 方法/属性 | 说明 |
|---|---|---|
| DOM渲染 | render | 生成DOM元素 |
| 事件处理 | events | 绑定DOM事件 |
| 模型监听 | listenTo | 监听模型变化 |
| 模板渲染 | template | 渲染HTML模板 |
5.2 View的双重角色 #
Backbone的View同时承担了视图和控制器的职责:
text
View = View(视图) + Controller(控制器)
视图职责:
├── 渲染HTML
├── 更新UI
└── 显示数据
控制器职责:
├── 处理用户输入
├── 更新模型
└── 协调视图和模型
5.3 View的事件绑定 #
javascript
var UserView = Backbone.View.extend({
events: {
'click .btn': 'onClick',
'mouseenter .item': 'onMouseEnter',
'mouseleave .item': 'onMouseLeave',
'keypress input': 'onKeyPress'
},
onClick: function(e) {
e.preventDefault();
},
onMouseEnter: function(e) {
$(e.currentTarget).addClass('hover');
},
onMouseLeave: function(e) {
$(e.currentTarget).removeClass('hover');
},
onKeyPress: function(e) {
if (e.which === 13) {
this.submit();
}
}
});
六、Router(路由器) #
6.1 Router的职责 #
javascript
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'users': 'listUsers',
'users/:id': 'showUser',
'users/:id/edit': 'editUser',
'*notFound': 'notFound'
},
home: function() {
console.log('首页');
},
listUsers: function() {
console.log('用户列表');
},
showUser: function(id) {
console.log('显示用户:', id);
},
editUser: function(id) {
console.log('编辑用户:', id);
},
notFound: function() {
console.log('页面未找到');
}
});
Router核心职责:
| 职责 | 方法 | 说明 |
|---|---|---|
| 路由定义 | routes | 定义URL与函数的映射 |
| 导航控制 | navigate | 编程式导航 |
| 历史管理 | history | 管理浏览器历史 |
6.2 Router在MVC中的角色 #
text
Router作为入口控制器:
┌─────────────────────────────────────────────────────┐
│ │
│ URL变化 → Router匹配 → 创建/更新View → 渲染页面 │
│ │
└─────────────────────────────────────────────────────┘
七、Events(事件系统) #
7.1 Events的作用 #
Events是Backbone的核心,所有组件都继承了Events:
javascript
// Model、Collection、View、Router都继承自Events
Backbone.Model.prototype.on === Backbone.Events.on
Backbone.Collection.prototype.on === Backbone.Events.on
Backbone.View.prototype.on === Backbone.Events.on
Backbone.Router.prototype.on === Backbone.Events.on
7.2 事件驱动架构 #
text
┌─────────────────────────────────────────────────────┐
│ 事件驱动架构 │
├─────────────────────────────────────────────────────┤
│ │
│ Model ──触发事件──► View ──监听事件──► 更新UI │
│ │
│ View ──捕获事件──► Model ──更新数据──► 触发事件 │
│ │
│ Collection ──代理事件──► View ──监听──► 更新列表 │
│ │
└─────────────────────────────────────────────────────┘
7.3 事件绑定方式 #
javascript
// 方式1:直接绑定
model.on('change', callback);
// 方式2:监听其他对象
view.listenTo(model, 'change', callback);
// 方式3:绑定多个事件
model.on({
'change:name': this.onNameChange,
'change:age': this.onAgeChange,
'destroy': this.onDestroy
});
八、数据流详解 #
8.1 单向数据流 #
text
用户操作
│
▼
View处理事件
│
▼
更新Model
│
▼
Model触发事件
│
▼
View监听事件
│
▼
更新UI
8.2 完整数据流示例 #
javascript
var Todo = Backbone.Model.extend({
defaults: {
title: '',
completed: false
}
});
var TodoView = Backbone.View.extend({
events: {
'click .toggle': 'toggleCompleted'
},
initialize: function() {
this.listenTo(this.model, 'change:completed', this.updateUI);
},
toggleCompleted: function() {
var completed = this.model.get('completed');
this.model.set('completed', !completed);
},
updateUI: function(model, completed) {
this.$el.toggleClass('completed', completed);
}
});
8.3 数据流图解 #
text
┌─────────────────────────────────────────────────────────────┐
│ 数据流图解 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户点击 ──► toggleCompleted() ──► model.set() │
│ │ │
│ ▼ │
│ Model触发change:completed │
│ │ │
│ ▼ │
│ View监听到事件 │
│ │ │
│ ▼ │
│ updateUI()更新DOM │
│ │
└─────────────────────────────────────────────────────────────┘
九、最佳实践 #
9.1 职责分离原则 #
javascript
// 好的做法:Model只处理数据逻辑
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.email.match(/@/)) {
return '邮箱格式不正确';
}
},
getFullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}
});
// 好的做法:View只处理UI逻辑
var UserView = Backbone.View.extend({
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
events: {
'click .save': 'saveUser'
},
saveUser: function() {
var data = this.$('form').serializeJSON();
this.model.save(data);
}
});
9.2 避免在View中直接操作Model数据 #
javascript
// 不好的做法
var BadView = Backbone.View.extend({
onClick: function() {
this.model.attributes.name = '新名字';
this.render();
}
});
// 好的做法
var GoodView = Backbone.View.extend({
onClick: function() {
this.model.set('name', '新名字');
},
initialize: function() {
this.listenTo(this.model, 'change', this.render);
}
});
9.3 使用Collection管理多个Model #
javascript
// 不好的做法:在View中维护数组
var BadView = Backbone.View.extend({
initialize: function() {
this.users = [];
},
addUser: function(user) {
this.users.push(user);
this.render();
}
});
// 好的做法:使用Collection
var GoodView = Backbone.View.extend({
initialize: function() {
this.listenTo(this.collection, 'add', this.addOne);
this.listenTo(this.collection, 'remove', this.removeOne);
},
addOne: function(user) {
var view = new UserView({ model: user });
this.$el.append(view.render().el);
}
});
十、总结 #
10.1 Backbone MVC特点 #
| 特点 | 说明 |
|---|---|
| 轻量级 | 组件简单,职责清晰 |
| 灵活性 | 不强制特定模式 |
| 事件驱动 | 组件间松耦合 |
| 单向数据流 | 数据流向清晰 |
10.2 核心理解 #
- Model:数据管理和业务逻辑
- Collection:模型集合管理
- View:视图渲染 + 控制器逻辑
- Router:路由导航控制
- Events:组件通信桥梁
10.3 设计原则 #
- 保持Model纯净,只处理数据
- View负责UI渲染和用户交互
- 使用事件实现组件间通信
- Collection管理多个Model实例
- Router控制应用导航
最后更新:2026-03-28