最近项目不是太忙,所以有点时间可以自学,刚好学一下 MVC 元老:Backbone。

目录速览

背景

为了深刻理解前端的MVC软件架构模式,从0开始学习下Backbone.js
首先要区分好:业务数据逻辑页面路由逻辑

Backbone简介

请Google

依赖库Underscore

下载后的Backbone.js文件仅是一个框架式的JS结构类库,它还必须依赖于Underscore库才能完整运行。

Backbone事件管理

Backbone.Events 模块API结构

Backbone.Events的时间管理是通过Backbone提供的Events API来实现的:

  • Backbone 1.0之前
    • on
    • off
    • trigger
    • once
  • Backbone 1.0以后(新增)
    • listenTo   指定本对象去监听别的对象将要发生的事件,并绑定处理函数
    • listenToOnce
    • stopListening

      事件与Model、Collection和View的关系

  • Model模型中,可以使用on或listenTo的方法绑定对象中的系统事件或自定义 事件
  • Collection模块类是Model与View模块类的中间层,也可以自定义事件,但使用较少
  • View模块类中,为了更好地维护DOM元素与事件的关系,View模块实例化的对象提供了一套完整的事件自动绑定机制,运用这套机制,可通过View对象的属性添加DOM元素的事件

Backbone数据模型

构建数据模型类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Student = Backbone.Model.extend({
initialize: function(attributes, options){ /* 实例化时会运行的初始化方法 */
//所有初始化时要做的事情都可以在此
this.on('change:grade', function(){ /* 监听单个属性 */
console.log('Attribute:"grade" changed!');
});
this.on('change', function(){ /* 监听整个对象 */
console.log('Object changed!');
});
},
defaults: {
code: '',
name: '',
grade: ''
},
selfDefinedMethod: function(){ /* 自定义模型中的方法 */
}
});

实例化数据模型类

1
2
3
4
5
6
7
8
9
10
11
12
13
var batman = new Student();
// 设置数据
batman.set({code: 101, name: 'batman'}); /* 统一设置 */
batman.set('grade', 100); /* 单属性设置 */
// 获取数据
batman.get('grade');
batman.escape('grade');
batman.previousAttributes();
batman.previous('grade');
batman.attributes;
// 删除数据
batman.unset('grade');
batman.clear(); /* 清空属性数据 */

Backbone模型集合

依附于基类的另外一个数据集合类,功能:管理和存储由模型(Model)衍生的数据集合;
实例化后的Model对象好像表中的一条记录,而实例化后的Collection对象则是一张数据集合表,可以在表中进行一系列的增加、删除、修改、查询的操作。

创建集合对象

  • 方法一:先自定义集合类,再实例化集合对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    var Student = Backbone.Model.extend({
    defaults: {
    code: '',
    name: '',
    grade: ''
    }
    });
    var StudentList = Backbone.Collection.extend({
    model: Student,
    selfDefineMethod: function(){ /*自定义集合方法*/
    },
    });
    var datalist = [
    {code:101, name:'batman', grade:100},
    {code:102, name:'ironman', grade:100},
    {code:103, name:'hulk', grade:100},
    ];
    var studlist = new StudentList(datalist);
    for(var i=0;i<studlist.models.length;i++){
    console.log(studlist.models[i].toJSON());
    }
  • 方法二:直接实例化集合对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var Student = Backbone.Model.extend({
    defaults: {
    code: '',
    name: '',
    grade: ''
    }
    });
    var datalist = [
    {code:101, name:'batman', grade:100},
    {code:102, name:'ironman', grade:100},
    {code:103, name:'hulk', grade:100},
    ];
    var studlist = new Backbone.Collection(datalist, {model: Student});
    for(var i=0;i<studlist.models.length;i++){
    console.log(studlist.models[i].toJSON());
    }

操作集合中模型对象

可以通过集合类提供的方法对其下的模型对象进行:

  • 增加 -> 触发add事件
    • obj.add(models, options)
    • obj.push(options)
    • obj.unshift(options)
  • 移除 -> 触发remove事件
    • obj.remove(models, options)
    • obj.pop(options)
    • obj.shift(options)
  • 查询
    • obj.get(id)
      若在构建模型对象类时没有该属性,也可以通过idAttribute属性值指定其他数字类型的属性为id标志;
    • obj.at(index)
    • obj.findWhere(attrs)
    • obj.where(attrs, first)
  • 排序
    • obj.sort(options)

Backbone视图

模型(Model)和集合(Collection)都属于底层的数据处理,真正与页面交互的是视图(View)
可以设置el属性关联DOM元素
可以指定与视图相关的模型或集合类名,实现各个类之间对象的数据互访

核心功能:

  1. 处理数据业务逻辑
  2. 绑定DOM元素事件
  3. 渲染模型或集合数据

主要功能:

  • 将数据渲染至页面中

定义视图对象

定义视图对象有两种形式:

  1. 定义一个尚未存在的视图类,在实例化时会生成新的DOM
  2. 定义一个查找DOM的视图类
    ps: 共同点为每个视图都会有一个el属性,用来获取DOM对象

定义一个尚未存在的视图类,在实例化时会生成新的DOM

1
2
3
4
5
6
7
8
9
10
var View = Backbone.View.extend({
// 构建视图类的逻辑结构
id: 'newElem',
className: 'new_elem_class',
style: 'border:1px solid #e4393c',
render: function(){ // do sth
}
});
var view = new View();
view.render();

定义一个查找DOM的视图类

1
2
3
4
5
6
7
8
9
10
var View = Backbone.View.extend({
// 构建视图类的逻辑结构
el: '.ele_class',
initialize: function(){ //do sth
},
render: function(){ // do sth
}
});
var view = new View();
view.render();

视图对象访问模型对象

严格来说,视图对象通常是接收集合对象返回的数据集,并将数据在页面中进行渲染,并不直接访问模型对象
但也能直接访问模型对象,实现方式:在实例化视图对象时,通过设置model属性值与需要访问的模型对象进行关联,关联之后,在视图类的内部能以this.model的方式进行访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var Student = Backbone.Model.extend({
defaults: {
code: '',
name: ''.
grade: 0,
}
});
var stu = new Student({
code: 1001,
name: '咸蛋超人',
grade: 100
});
var StuView = Backbone.View.extend({
el: '.elem_class',
render: function(){
console.log(JSON.stringify(this.model));
},
});
var stuview = new StuView({model: stu});
stuview.render();

视图对象访问集合对象

与访问模型对象类似,也可以通过视图对象直接访问集合对象
实现方法:在实例化视图对象时,将collection属性值设置为关联的集合对象名;
在构建视图类时,可以this.collection的方式获取被关联的集合对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var stulist = [
{code:1001, name:'ironman', grade:100},
{code:1002, name:'hulk', grade:100},
{code:1003, name:'cap', grade:100},
];
var stuCollection = new Backbone.Collection(stulist);
var View = Backbone.View.extend({
el: '.elem_class',
render: function(){
var models = this.collection.models;
for(var i in models){
console.log(JSON.stringify(models[i]));
}
}
});
var viewer = new View({ collection: stuCollection });
viewer.render();

视图中的模板

通过underscore库来引入视图模板的功能

1
2
3
4
5
6
<!-- html -->
<div class="elem_class">
</div>
<script type="text/template" id="viewTpl">
<div><%= '编号':code '姓名':name '成绩':grade%></div>
</script>

1
2
3
4
5
6
7
8
9
10
11
12
// js
var View = Backbone.View.extend({
el: '.elem_class',
initialize: function(){ // do sth
this.template = _.template($('#viewTpl').html());
},
render: function(opt){ // do sth
this.$el.html(this.template(opt));
},
});
var viewer = new View();
viewer.render({code: 1005, name: 'antman', grade: '100'});

视图中的元素事件

视图对象与页面的交互最为密切,视图类中提供了许多侧重于页面交互的属性或方法
在构建视图类时,可以添加一个events属性,该属性的功能是将DOM元素与触发事件和执行事件函数相绑定

绑定方式有两种:

  1. 静态绑定
  2. 动态绑定

静态绑定元素事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// js
var View = Backbone.View.extend({
el: '.elem_class',
initialize: function(){ // do sth
this.template = _.template($('#viewTpl').html());
},
render: function(opt){ // do sth
this.$el.html(this.template(opt));
},
events: { /*静态绑定方式*/
'click .elem_class': 'showInfo'
},
showInfo: function(){
console.log('showing infos.');
}
});
var viewer = new View();
viewer.render({code: 1005, name: 'antman', grade: '100'});

动态绑定/取消绑定元素事件

  • delegateEvents([events])
    功能:重新绑定events属性值已声明的全部元素事件
    参数:可选参数events为视图对象的events属性值,也可以不添加,默认就为视图对象资深的events属性值
  • undelegateEvents()
    功能:取消所有已绑定元素的事件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // js
    var View = Backbone.View.extend({
    el: '.elem_class',
    initialize: function(){ // do sth
    this.template = _.template($('#viewTpl').html());
    },
    render: function(opt){ // do sth
    this.$el.html(this.template(opt));
    },
    events: { /*静态绑定方式*/
    'click .elem_class': 'showInfo'
    },
    showInfo: function(){
    console.log('showing infos.');
    },
    rebind: function(){ /*动态绑定方式*/
    this.delegateEvents(this);
    }
    });
    var viewer = new View();
    viewer.render({code: 1005, name: 'antman', grade: '100'});

Backbone导航控制器

浏览器导航功能基础知识

  1. window.history
    功能:保存浏览器的历史浏览记录
    说明:HTML4 标准 的history对象的常用方法和属性
    方法:
    • window.history.go(n)
    • window.history.back()
    • window.history.forward()
      属性:
    • window.history.length
  2. H5的history API
    说明:H5的history对象基于原有对象,新增了两个API方法
    方法:

    • window.history.pushState(data, title [, url]);
      功能:向历史记录堆栈的顶部添加一条记录,常用于实现页面的无刷新跳转
    • window.history.replaceState(data, title [, url]);
      功能:修改当前的历史记录值
    • 参数说明:
      data: 表示在添加记录时,传递的数据对象,常为JSON格式的字符串
      title: 页面显示的标题
      url: 可选,页面跳转地址,默认为当前页地址

    属性:

    • window.history.state
  3. window.location
    功能:管理浏览器的地址
    方法:

    • window.location.reload()
    • window.location.replace()
    • window.location.assign()

    属性:

    • window.location.href
    • window.location.origin
    • window.location.host
    • window.location.hostname
    • window.location.protocol
    • window.location.port
    • window.location.pathname
    • window.location.search
    • window.location.hash

绑定导航地址

在Backbone框架中,大量地封装了locationhistory这两个对象的属性和方法,将页面特定的url和hash属性与定义好的action或event相绑定
router对象的导航功能实际上是由Backbone.js中的router和history两个类共同的完成,前者用于定义和解析hash属性的匹配规则,并将规则中的url映射到对应的动作(action)函数;后者则是监听url的变化,并执行对应的动作函数

  1. action 方式绑定URL地址
    定义Router类时进行绑定
  2. event 方式绑定URL地址
    实例化router对象后进行绑定

router类中的方法

  1. route 方法的使用
    为相应的hash值绑定相应函数;可动态地修改url中hash属性的匹配规则和动作(action)函数,调用方法如下:
    objrouter.route(route, name, callback);
  2. navigate 方法的使用
    手动跳转到hash地址,并决定是否触发相应的函数
    objrouter.navigate(fragment, options);
    示例:
    1
    router.navigate('search/list', { trigger:true });

Backbone.history 对象的方法

  1. Backbone.history.start()
    开始监听URL地址变化并准备触发绑定的相应函数
  2. Backbone.history.stop()
    停止监听