Backbone.js Overview

  • 它由Jeremy Ashkenas开发,最初发行于2010-10-13
  • 它是一个轻量的JavaScript类库,只依赖于underscore.js,非强制依赖于jquery,大小只有7.6Kb,作为一个框架级的js文件,它已经非常小了
  • 它提供了Model-View-Presenter(MVP)的框架模式,可以帮助前端开发搭建一个层次清晰的Web应用框架
  • 它提供了models和collections来封装数据结构,提供了views来操作DOM,提供了自定义事件将数据结构和DOM操作绑定在一起

Environment Setup

要完整使用BackboneJS,需要引入以下js

  • Underscore.js(>= 1.8.3)或者lodash.js
  • Jquery.js(>= 1.11.0)
  • Json2.js(如果需要支持IE)

在没有npm的环境下,可以下载压缩包或者使用CDN。

<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.0/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>

Bakbone.js View

负责操作DOM,采用 OO 的思想来操作一个视图。

Backbone.js View API

  • extend 每一个自定义的View都必须由Backbone.View类extend而来,override父类中的属性
  • initialize() View的构造函数,每当new一个实例时,就会调用该方法
  • render() 通常将view的渲染逻辑写在此方法中,并在initialize中调用它
  • template() View渲染时的模板,可以使用underscore的模板,也可以使用其他任意JS模板引擎
  • el View对应的DOM对象,可以使用id选择器,类选择器来定义
  • $el View对应的jQuery对象,方便使用jQuery的方法来操作DOM
  • tagName View对应的DOM节点的标签名称,默认是“div”
  • id View对应的DOM节点的id属性
  • className View对应的DOM节点的class属性
  • events 给View绑定事件
  • remove() 移除一个view,其el将从DOM中移出,绑定的事件也将停止监听

Create a View

只需要扩展视图构造函数 Backbone.View, 传入Dom相关的属性。

示例 假如,需要在DOM中动态添加一个id=“root”的div。

不使用backbone.js,我们通常这样实现。

// app.js
function addRoot() {
var el = document.createElement('div');
el.id = 'root';
el.innerHTML = 'Hello Backbone!!!';
document.body.appendChild(el);
}
addRoot();

使用backbone.js,我们这样实现:

// app.js
var AppView = Backbone.View.extend({
tagName: 'div',
id: 'root',
initialize: function () {
this.render();
},
render: function () {
this.el.innerHTML = 'Hello Backbone!!!';
return this;
}
}); var appView = new AppView();
document.body.appendChild(appView.el);
  • tagName 指定这个element 是一个div
  • id 指定这个div的id属性值
  • 当 调用 new AppView() 时,执行initialize() 函数
  • render() 函数用于渲染这个element

Get Existed Element

假如,在html中已经定义了div#root这个element,想修改它的内容。

使用Backbone.js怎么来操作这个element呢?

// index.html
<body>
<div id="root">loading...</div>
</body>
var AppView = Backbone.View.extend({
el: '#root',
initialize: function () {
this.render();
},
render: function () {
this.el.innerHTML = 'Hello Backbone!!!';
return this;
}
});
var appView = new AppView();

Bind events

格式:

events: {
'event1 selector1': 'function name1',
'event2 selector2': 'function name2',
...
}

示例 有这样一个小应用,在input中输入后,回车,添加一个new goal;点击每一个goal后面的remove,移除此项目。

// index.html
<div id="root" class="color-dark">
<header>
<h2>My Life Goals</h2>
<input id="new-goal" type="text" placeholder="add a new goal">
</header>
<ul id="goal-list">
<li class="goal-item">Goal one <a class="btn-remove">remove</a></li>
<li class="goal-item">Goal two <a class="btn-remove">remove</a></li>
<li class="goal-item">Goal three <a class="btn-remove">remove</a></li>
<li class="goal-item">Goal four <a class="btn-remove">remove</a></li>
</ul>
</div>
  • 给input绑定一个 keypress 事件
  • 给每一个 .btn-remove 绑定一个click事件
// app.js
var AppView = Backbone.View.extend({
el: '#root',
… …
events: {
'keypress #new-goal': 'addGoal',
'click .btn-remove': 'clear',
},
addGoal: function(ev) {
if (ev.keyCode != 13) return;
console.log('addGoal');
// To do
},
clear: function() {
// To do
}
});
var appView = new AppView;

How to change view

在引入Backbone.js的Model之前,我们可以这样来实现 addGoal 方法。

addGoal: function(ev) {
if (ev.keyCode != 13) return;
var newGoal = $('#new-goal').val();
if(newGoal === '') return;
var goalHtml = '<li class="goal-item">'+ newGoal +'<a class="btn-remove">remove</a></li>';
$('#goal-list').append(goalHtml);
$('#new-goal').val('');
}

在Backbone.js 出现之前,当数据发生变化视图需要重新渲染时,我们通常使用js或jQuery来进行DOM操作,改变展示的内容。

这样做data和视图渲染混在一起,显得很乱;而且,如果视图上要显示的属性很多,拼接的代码就很长很长。

所以,使用Backbone.js 的Model和Collection 将data和View 进行分离。

Bakbone.js Model & Collection

Model的作用

  • 封装数据结构
  • 处理业务逻辑
  • 从server 加载、保存数据
  • 当data发生变化时触发事件,比如重新渲染视图

Collection的作用

Collection是Model的有序集合,和Model一样用于数据加载、保存,监听数据变化,还可以使用 Underscore.js 提供的方法来操作Collection。

主要适用于list、table等视图的渲染。在本例中,就需要定义一个Collection来渲染列表,并监听Collection的变化。

定义Model和Collection

// Goal Model
var Goal = Backbone.Model.extend({
defaults: {
title: ''
}
}); // Goal Collection
var GoalCollection = Backbone.Collection.extend({
model: Goal,
});

使用template

下面这段代码,有一些地方是相同的,为了避免重复代码,可以使用模板来渲染。

<ul id="goal-list">
<li class="goal-item">Goal one <a class="btn-remove">remove</a></li>
<li class="goal-item">Goal two <a class="btn-remove">remove</a></li>
<li class="goal-item">Goal three <a class="btn-remove">remove</a></li>
<li class="goal-item">Goal four <a class="btn-remove">remove</a></li>
</ul>

在html中定义模板

把重复的部分抽出来,定义模板时使用<script>标签,但这里的type是text/template,然后给它一个id,用于在View中通过id来获取它。

<body>
<div id="root" class="color-dark">
<header>
<h2>My Life Goals</h2>
<input id="new-goal" type="text" placeholder="add a new goal">
</header>
<ul id="goal-list">
<!-- template -->
</ul>
</div> <script type="text/template" id="item-template">
<li class="goal-item"><%= title %><a class="btn-remove">remove</a></li>
</script>
</body>
  • <%= %>表示插入变量
  • <% %>表示插入任意JS代码段
  • <%- %>表示插值并进行转义

View中定义解析函数template()

在js中定义GoalView,用于生成每一个Goal对应的<li>节点。

BackboneJS中的template实际上调用的是underscore.js的template方法,该方法可以将 JavaScript 模板编译为可以用于页面呈现的函数,它返回的是一个函数

_.template(templateString, [settings])

render时调用template

然后在render中调用template方法,把model对象作为参数传入。

// app.js

// Goal Model
var GoalModel = Backbone.Model.extend({
defaults: {
title: '' // 默认属性值
}
}); // Goal Collection
var GoalCollection = Backbone.Collection.extend({
model: GoalModel,
}); var GoalView = Backbone.View.extend({
tagName: 'li',
initialize: function () {
this.render();
},
template: function () {
return _.template($('#item-template').html()); //根据模板的id来获取模板定义的内容
},
render: function () {
this.$el.html(this.template()(this.model.toJSON()));
},
events: {
'click .btn-remove': 'clear', // 绑定事件
},
clear: function() {
// To do
}
}); var AppView = Backbone.View.extend({
el: '#root',
… …
events: {
'keypress #new-goal': 'addGoal',
},
addGoal: function(ev) {
if (ev.keyCode != 13) return;
console.log('addGoal');
// To do
}, });

测试效果:

var view = new GoalView({ model: {title: 'My first goal'} });
this.$("#goal-list").append(view.$el);

bind Collection to View

在AppView中,修改addGoal的添加模式,将原来的直接操作DOM,修改为通过data的变化来触发DOM的渲染。

  • 在AppView中实例化一个GoalCollection,命名为goalList
  • Keypress事件触发时,修改goalList,这里调用了Backbone.Collection中的push()方法
var AppView = Backbone.View.extend({
el: '#root',
initialize: function () {
this.goalList = new GoalCollection();
this.render();
},
render: function () {
return this;
},
events: {
'keypress #new-goal': 'addGoal'
},
addGoal: function (ev) {
if (ev.keyCode != 13) return;
var inputVal = $('#new-goal').val(); // 获取输入的值
if (inputVal === '') return;
this.goalList.push({ title: inputVal }); // push到Collection
$('#new-goal').val('');
},
});

但是,此时,你会发现虽然goalList发生了变化,但是页面并没有跟着渲染。

因为,View并没有对Collection的变化进行监听。

Model 和 Collection的事件监听

View 监听 Model或Collection的变化

在AppView中,通过listenTo()方法,监听Collection的变化,当Collection发生变化时,触发内部的某个方法。

object.listenTo(other, event, callback)

listenTo 用于一个对象,监听另一个对象的变化

停止监听使用stopListening

object.stopListening([other], [event], [callback])

监听add事件
var AppView = Backbone.View.extend({
el: '#root',
initialize: function () {
this.goalList = new GoalCollection();
this.render();
this.listenTo(this.goalList, 'add', this.addOne);
// or
// this.goalList.on('add', this.addOne, this);
},
render: function () {
return this;
},
events: {
'keypress #new-goal': 'addGoal'
},
addGoal: function (ev) {
if (ev.keyCode != 13) return;
var inputVal = $('#new-goal').val();
if (inputVal === '') return;
this.goalList.push({ title: inputVal });
// or this.goalList.add({ title: inputVal }); $('#new-goal').val('');
},
addOne: function (goal) {
var view = new GoalView({ model: goal });
this.$("#goal-list").append(view.$el);
}
});

这里为什么监听的event是 add,而不是 push?

因为push()方法底层其实调用的是add()方法。

this.goalList.push({ title: inputVal });

修改为

this.goalList.add({ title: inputVal });

效果相同

监听destroy事件

在上一步中,已经给GoalView绑定了Goal这个Model,那么在View中就可以使用Model来控制View的渲染。在GoalView中需要监听GoalModel的变化,goalModel移除时,销毁视图。

var GoalView = Backbone.View.extend({
tagName: 'li',
initialize: function () {
this.render();
this.listenTo(this.model, 'destroy', this.remove);
//or this.model.on('destroy', this.remove, this);
},
template: function () {
return _.template($('#item-template').html());
},
render: function () {
console.log('model', this.model.toJSON());
this.$el.html(this.template()(this.model.toJSON()));
},
events: {
'click .btn-remove': 'clear',
}, clear: function() {
this.model.destroy();
}
});

destroy model后,view 也会从DOM中移除,同时绑定的事件也会停止监听。

this.remove 是View 内置的函数。

remove()方法不仅可以从DOM中移除view对应的节点,同时还能停止节点上绑定的事件监听。

Model或Collection 自我监听变化

在AppView中,还可以通过调用on()方法,让Collection监听自己的变化。

object.on(event, callback, [context])

这种用法是自己监听自己。

如果想停止监听,使用off()方法

object.off([event], [callback], [context])

this.listenTo(this.goalList, 'add', this.addOne);

等效于

this.goalList.on('add', this.addOne, this);

this.listenTo(this.model, 'destroy', this.remove);

等效于

this.model.on('destroy', this.remove, this);

为什么要传入context?

因为调用on()方法的是this.goalList,如果不传入context,那么在addOne()调用时,默认的this指代的是this.goalList,而不是AppView的实例了。

因此,为了保证上下文都是View的实例,需要传入context。

使用 bind() 或 bindAll() 修改context

可以在使用on()时,不传入context,而使用 _.bind() 或 _.bindAll() 来绑定context

在使用bind时,必须使用bind返回的函数

// 使用 bind
initialize: function () {
this.render();
this.remove = _.bind(this.remove, this); // 返回值是一个函数
this.model.on('destroy', this.remove);
},

使用bindAll非常方便,不必考虑返回值

// 使用 bindAll
initialize: function () {
this.render();
_.bindAll(this, 'remove', 'clear'); // 可以同时改变多个函数的context
this.model.on('destroy', this.remove);
},

backbone.js 教程(1) View & Model & Collection的更多相关文章

  1. Backbone.js学习之View

    千呼万唤始出来,终于到最后一个要点View了.照旧,先来一睹官方文档: Backbone views are almost more convention than they are code - t ...

  2. 用Backbone.js教程系列的链接

    整理了一下用Backbone.js系列教程链接. Backbone.js入门教程 用Backbone.js创建一个联系人管理系统(一) 用Backbone.js创建一个联系人管理系统(二) 用Back ...

  3. Backbone.js入门教程

    原文: Getting Started with Backbone.js 不像其它的Web开发语言,过去Javascript很少可用的架构.令人感到高兴的是,最近几年这种情况得到非常大的改善. 今天我 ...

  4. Backbone.js 使用 Collection

    在前面我们的 Backbone.js 用上了 Model, 但绝大数的情况下我们处理的都是一批的 Model 数据列表,所以需要有一个 Collection 来容纳 Model, 就像 Java 里最 ...

  5. [backbone] Getting Started with Backbone.js

    一.简介 Backbone 是一个 JavaScript MVC 框架,它属于轻量级框架,且易于学习掌握.模型.视图.集合和路由器从不同的层面划分了应用程序,并负责处理几种特定事件.处理 Ajax 应 ...

  6. Backbone.js的技巧和模式

    Backbone.js的技巧和模式 Backbone.js的技巧和模式   本文由白牙根据Phillip Whisenhunt的<Backbone.js Tips And Patterns> ...

  7. [Backbone.js]如何处理Model里面嵌入的Collection?

    写了近半个月的backbone.js代码,从一开始的todo到现在做仿微信的网页聊天,其中最大的困惑就在于如何处理比较复杂的Model,其内嵌了一个或者多个Collections. 假设我们有一个Pe ...

  8. Backbone.js学习之Backbone.View(视图)

    Backbone.js为复杂WEB应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和自定义事件:集合附有可枚举函数的丰富API: 视 ...

  9. Backbone.js 中使用 Model

    前面几篇 Backbone.js 的例子中有使用到 template, 及数据的填充,其实这已经很接近 Model 了.现在来学习怎么创建自己的 Model 类,并简单的使用.Backbone.js ...

随机推荐

  1. 使用sql做迁移矩阵

    在数据分析数据差异的时候 经常用到一个图叫做迁移矩阵. 其中里面的值可以是数量也可以是百分比,我们可以从一个时间点明确的看到在另一个时间点或者另一个时间点 子类之间数量迁移. 比如这次我在公司与业务核 ...

  2. Leetcode练习题21. Merge Two Sorted Lists

    题目描述(easy) Merge Two Sorted Lists Merge two sorted linked lists and return it as a new list. The new ...

  3. user-select 用户禁止选中

    我们在页面输入的文本按理来说应该都是可以选中的,但是如何才能让显示出来的文本或是图片不被选中呢,这时候就需要用到 user-select 属性. user-select user-select (CS ...

  4. CSS之咖啡菜单网页设计

    今天记录学习的设计网站首页的咖啡菜单,综合运用所学习的html,css背景,文本,字体,链接,表格,盒子,选择器,定位,以及css3的阴影,圆角边框,2d变换等内容. ㈠咖啡菜单整体样式 运用html ...

  5. CSS的五种基本选择器

    要使用css对HTML页面中的元素实现一对一,一对多或者多对一的控制,这就需要用到CSS选择器. ㈠什么是选择器? 每一条css样式定义由两部分组成,形式如下: [code] 选择器{样式} [/co ...

  6. laravel短信验证

    短信验证按钮倒计时功能: $('.btn').click(function(){ var time = 59; // $('.btn').css('background-color','#ccc'); ...

  7. react 中的路由 Link 和Route和NavLink

    route是配置,link是使用 https://blog.csdn.net/chern1992/article/details/77186118(copy) 嵌套路由一般使用Route,类似于vue ...

  8. oracle条件参数中 IN函数中的值最大只能为1000个

    delete from dep where id in(1,2,3.....) 括号里面字段个数最大只能为1000个

  9. 分布式-信息方式-ActiveMQ静态网络连接的容错

    容错的链接Failover Protocol 前面讲述的都是client配置链接到指定的 broker上.但是,如果 Broker的链接失败怎么办呢?此时, Client有两个选项:要么立刻死掉,要么 ...

  10. IDEA 无法显示项目目录结构解决

    不要去网上看什么乱七八糟的骚教程,一点用都没有.直接按下列步骤操作: 1. 关闭IDEA, 2. 然后删除项目文件夹下的.idea文件夹3. 重新用IDEA工具打开项目