6.1 视图基础
与模型和集合对象相类似,在定义一个视图之前,需要构建一个视图类。在构建类时,可以设置el属性关联DOM中的元素;也可以指定与视图相关的模型和集合类名,实现各个类之间对象的数据互相访问,下面逐一进行详细的介绍。
6.1.1 定义视图对象
定义一个视图对象的方法十分简单,先通过extend方法构建一个视图类,再通过关键字new的方法实例化视图对象,在对象中可以调用视图类中的方法。定义过程如下代码所示。
var testview = Backbone.View.extend({
//构建类的逻辑结构
});
//根据构建的类实例化一个test视图对象
var test = new testview();
在上述代码中,先构建一个名为testview的视图类,然后以实例化的方式定义一个名为test的视图对象,这是定义视图对象最基本的框架。因为视图的主要功能是将数据渲染至页面中,因此,在视图中必须能访问DOM元素,而要实现这一要求,只需要在构建视图类时添加DOM元素属性即可。接下来通过一个简单示例来进行介绍。
示例6-1 通过视图对象添加DOM元素
1.功能描述
通过定义的视图对象添加一个DOM元素,并设置该元素的类别名称。在浏览器中执行该页面时,将在页面中显示“backbone是构建前端MVC的利器”字样。
var testview = Backbone.View.extend({
id:"show",
className:"cls_6",
render:function(content){
this.el.innerHTML = content;
document.body.appendChild(this.el);
}
});
var test = new testview();
test.render("backbone是构建前端MVC的利器");
2.源码分析
在上述页面文件的JavaScript代码中,为了动态创建一个DOM元素,首先定义id和className属性,分别对应元素的ID和样式属性名称。这些属性还包括tagName和attributes,前者为新元素的名称,如果不设置,则为div元素;后者则是一个对象,它可以设置该元素的其他属性值,这些新设置的属性都会在元素添加时一起生效,代码如下。
...省略部分代码
attributes:{
title:"测试",
style:"border:solid 1px #555"
}
...省略部分代码
为了动态设置新添加元素中显示的内容,需要重载视图类提供的render函数。在重载过程中重新渲染视图中的内容,将内容参数content作为新添加元素this.el的innerHTML属性值,即设置元素显示的内容,并调用append方法将新添加元素追加到body元素中。
最后,当实例化一个名为test视图对象,并调用对象的render方法重载对象内容时,将向页面的body元素添加一个设定了内容的div元素,页面效果如上图所示。
上述示例演示的是动态增加一个DOM元素,并将该元素追加至页面中,其实也可以通过在构建视图类时设置el属性访问页面中的元素,再通过render方法设置元素中显示的内容。如果采用这种方法实现示例6-1中的功能,修改代码如下。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
.cls_6{
font-size:12px;
}
</style>
</head>
<body>
<div id="show" class="cls_6"></div>
<script type="text/javascript">
var testview = Backbone.View.extend({
el:"#show",
render:function(content){
this.el.innerHTML = content;
}
});
var test = new testview();
test.render("backbone是构建前端MVC的利器");
</script>
</body>
</html>
上述代码相对于示例6-1首次编写的代码更简洁,它通过设置el属性值指定视图对象在元素中对应的DOM元素。视图中el属性值是一个字符串形式的元素选择器,在实例化过程中,视图内部会通过该选择器获取指定的DOM元素对象,并重新保存至el属性中。因此在视图内部,可以通过thi.el的方式访问这个DOM元素对象。
每个视图都会有一个el属性,用来保存获取的DOM元素对象。通常情况下,视图对象的全部操作都应该在这个元素对象内进行,这样便于页面的整体渲染和子集元素的操作。如果没有设置该属性,框架会自动生成一个空值的div元素,并将该元素对象设置为el属性值。
6.1.2 视图对象访问模型对象
严格来说,视图对象通常是接收集合对象返回的数据集,并将数据在页面中进行渲染,并不直接访问模型对象。但是,也能直接访问模型对象,实现的方式是:在实例化视图对象时,通过设置model属性值与需要访问的模型对象进行关联,关联之后,在视图类的内部能以this.model的方式进行访问。接下来通过一个简单示例进行介绍。
示例6-2 通过视图对象添加DOM元素
1.功能描述
通过定义的视图对象,获取一个实例化模型对象的全部内容值,并将该值以字符的形式显示在页面指定的元素中。
var student = Backbone.Model.extend({
defaults:{
Code:"",
Name:"",
Score:750
}
});
var stus = new student({
Code:"10107",
Name:"皮卡丘",
Score:750
});
var stusview = Backbone.View.extend({
el:"#show",
render:function(){
this.el.innerHTML = JSON.stringify(this.model);;
}
});
var stuv = new stusview({model:stus});
stuv.render();
2.源码分析
在本实例的JavaScript代码中,首先构建一个student模型类,并实例化一个模型对象stus,用于视图对象的调用。然后,构建一个 stuview视图类,在构建视图类中设置el属性,并重载render方法。在重载过程中,通过this.model方式获取关联的模型对象,通过stringify方法将模型对象转换成字符串内容,并将内容显示在页面指定的元素中。
最后,为了关联模型对象,在实例化视图对象时一定要添加model模型属性,并将该属性的值设置为需要关联的模型对象名称,再调用视图对象render方法,将关联后的模型对象内容显示在页面中,最终实现的页面效果如上图所示。
6.1.3 视图对象访问集合对象
与访问模型对象类似,也可以通过视图对象直接访问集合对象。实现的方法是:在实例化视图对象时,将collection属性值设置为关联的集合名称,在构建视图类时,可以采用this.collection的方式获取被关联集合对象。接下来通过一个简单示例来进行介绍。
示例6-3 视图对象访问集合对象
1.功能描述
通过定义的视图对象获取一个实例化集合对象中全部模型数据的内容值,通过遍历的方式将这些值以字符的形式显示在页面指定的元素中。
var stumodels = [{
Code:"10101",
Name:"刘真真",
Score:530
},{
Code:"10102",
Name:"张明基",
Score:460
},{
Code:"10103",
Name:"刘真真",
Score:530
},{
Code:"10104",
Name:"周小敏",
Score:500
},{
Code:"10105",
Name:"陆明明",
Score:300
}];
var stulist = new Backbone.Collection(stumodels);
var stuview = Backbone.View.extend({
el:"#show",
render:function(){
var curlist = this.collection.models;
for(var i=0;i<curlist.length;i++){
this.el.innerHTML += JSON.stringify(curlist[i])+"<br/>";
}
}
});
var stuv = new stuview({collection:stulist});
stuv.render();
2.源码分析
在本示例的JavaScript代码中,首先定义一个用于填充集合对象的数组对象stumodels,再以实例化的形式将stumodels对象作为实参定义一个名为stulist集合对象,此时,新定义的集合对象包含了数组对象stumodels中全部的数据。
构建集合类时,在重载render方法过程中,以this.collection方式获取关联的集合对象,并将该对象的models属性内容保存在curlist中,以遍历的方式获取models属性中每个模型数据的内容,并以字符的形式显示在页面指定的元素中。
在实例化视图对象stuv时添加collection属性,并将该属性值设置为已定义的集合对象stulist,从而实现两个对象的关联。当视图对象stuv调用render进行重载时,以this.collection方式获取的集合对象就是被关联的stulist集合对象。
6.2 视图中的模板
在构建视图类时,虽然可以十分方便地访问DOM元素,但如果DOM元素过多或存在一定的逻辑性,且这些元素不经常变更。要在JavaScript代码中拼接这样的DOM元素是一件非常复杂的事情,为解决这个问题,可以引入视图中的模板。
视图中的模板分为两个部分:
第一部分是在页面中使用<script>元素进行定义。在定义时,只要将<script>元素的type属性设置为“text/template”,表名该元素包含的代码区域都为模板区。在模板区中,采用<%=变量名称%>的形式定义变量,并且可以处理业务逻辑。然后,在JavaScript代码中通过字典的方式给变量传值。
第二部分是在JavaScript代码中,通过.template()函数访问页面中定义的模板内容,当重载模板内容时,可以通过字典的形式向模板中传递变量对应的值。
接下来通过几个完整的示例详细介绍视图中模板的使用方法。
6.2.1
处理逻辑的模板
使用<script>元素定义的页面模板区中,在<%= >区域内,“<% %>”表示区别于其他的HTML元素的特殊符号,“=”表示取值符号,不可缺少。<%= %>区域内的变量会在调用模版时,被以字典方式传入的对应值所取代,如果是字符内容则原样输出。并且<%=
%>区域内还支持简单的JavaScript语句。接下来通过一个简单示例进行介绍。
示例6-4 处理逻辑的模板
1.功能描述
在页面中,使用<script>标记定义一个模板区和一个用于显示模板区内容的<div>元素。当模板区变量score大于600时,<div>元素显示”优秀“,否则显示”及格“。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body{
font-size:13px;
}
div{
width:260px;
padding:5px;
}
</style>
</head>
<body>
<div id="score"></div>
<script type="text/template" id="score-tpl">
<%= score>600?"优秀":"及格"%>
</script>
</body>
<script type="text/javascript">
var stuview = Backbone.View.extend({
el:$("#score"),
initialize:function(){
/*
* 调用_.template函数获取指定ID号的页面模板中的内容,
* 并将该内容赋予视图本身的template属性。
* 这一操作表示页面的模板已与视图类相关联。
*/
this.template = _.template($("#score-tpl").html());
},
render:function(pscore){
this.$el.html(this.template({score:pscore}));
}
});
var stuv = new stuview();
stuv.render(600);
</script>
</html>
2.源码分析
在本示例中,首先在页面中定义一个ID号为“score”的<div>元素,用于显示经过逻辑处理后的模板内容,并使用<script>元素定义一个模板。在模型的<%= %>区域中,根据变量score的值,显示“优秀”或“及格”字样。
在构建视图类时,将el的属性值设置成ID号为“score”的<div>元素,表明本次的视图操作都在该元素中显示。此外,在视图类的构造函数initialize中,调用_.template()函数获取指定ID号的页面模板中的内容,并将该内容赋予视图本身的template属性。这一操作表示页面的模板已与视图类相关联,可以在视图对象的render重载方法中,采用this.template的方式访问页面中的模板。在访问时,还可以以字典的形式替换模板中对应的变量值。
接下来实例化一个名为“stuv”的视图对象,并调用该对象的render方法重载页面中的模板。在重载时,将600作为实参传给模板中对应的变量score,并将该变量值与600进行比较,返回“及格”字样,最后将该返回的内容显示在ID号为“score”的页面元素中。
6.2.2 显示多项内容的模板
上一节中介绍了视图中的模板如何显示有逻辑的变量内容,而在实际的项目开发过程中,视图中的模板常用于显示一些与经常变化、有一定排列格式的多项内容,这些多项内容中的变量命名可以与模型对象的各属性名称相对应,这样的命名方式便于将获取的模型对象转换成JSON格式后直接传递给视图模板中的对应变量,这种方式的代码也更加简洁、安全、高效。接下来通过一个简单示例进行介绍。
示例6-5 显示多项内容的模板
1.功能描述
在页面中,使用<script>标记定义一个包含多项变量内容的模板区和一个用于显示模板区内容的<ul>元素。当实例化一个视图对象并重载对象的render方法时,将获取的模型对象内容直接通过视图中的模板显示在页面的<ul>元素中。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body{
font-size:13px;
}
div{
width:260px;
padding:5px;
}
</style>
</head>
<body>
<ul id="ulshowstus"></ul>
<script type="text/template" id="stus-tpl">
<li>编号:<%=Code%></li>
<li>姓名:<%=Name%></li>
<li>分数:<%=Score%></li>
</script>
</body>
<script type="text/javascript">
var student = Backbone.Model.extend({
defaults:{
Code:"",
Name:"",
Score:0
}
});
var stus = new student({
Code:"10107",
Name:"皮卡丘",
Score:750
});
var stuview = Backbone.View.extend({
el:$("#ulshowstus"),
initialize:function(){
this.template = _.template($("#stus-tpl").html())
},
render:function(){
this.$el.html(this.template(this.model.toJSON()));
}
});
var stuv = new stuview({model:stus});
stuv.render();
</script>
</html>
2.源码分析
在本示例代码中,首先在页面中定义一个用于视图传递数据的视图模板stus-tpl,在该模板中根据显示格式的要求添加<li>元素作为子元素项,并以显示模型对象的各属性名称作为在子元素项中的变量名。这种命名方式便于模型对象在JSON格式化后直接将数据传递给视图模板中的各个对应变量,操作十分方便。此外,在页面中还定义一个名为ulshowstus的<ul>元素,用于显示接收数据之后的视图模板内容。
在构建视图类的过程中,声明el属性所指定的DOM元素对象为ID号为ulshowstus的<ul>元素。在重构函数initialize中,将页面中的模板内容赋予视图本身的template属性。在视图对象的render重载方法中,先将获取的模型对象内容进行JSON格式化,再将直接格式化的内容传递给视图模板中。由于变量名称与JSON格式化后的key值相同,会自动将key对应的vlaue代替对应的模板变量,并且将完全代替后的HTML内容显示在ID号为ulshowstus的<ul>元素中。
在实例化视图对象时,指定该视图对象的模型为stus,进行视图对象与模型对象间的关联,并通过调用视图对象的render方法,将视图模板中代替后的HTML内容显示在页面指定ID号的元素中,其最终实现的页面效果如上图所示。
6.2.3 显示多项内容的模板
在页面中使用<script>元素添加模板区域之后,默认情况下使用<%= %>标记设置模板变量,但在有些使用服务端程序开发的页面中,<%= %>标记可能会有冲突或不习惯。针对这种情况,开发人员可以调用Underscore框架中的templateSettings函数,使用正则表达式自定义模板变量的标记。接下来通过一个简单示例进行介绍。
示例6-6 自定义模板变量标记
1.功能描述
为了演示修改模板变量标记后的对比效果,将示例6-5代码进行修改,调用templateSettings函数自定义模板变量标记,其他代码功能保存不变。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body{
font-size:13px;
}
div{
width:260px;
padding:5px;
}
</style>
</head>
<body>
<ul id="ulshowstus"></ul>
<script type="text/template" id="stus-tpl">
<li>编号:{{Code}}</li>
<li>姓名:{{Name}}</li>
<li>分数:{{Score}}</li>
</script>
</body>
<script type="text/javascript">
_.templateSettings = {
interpolate:/\{\{(.+?)\}\}/g
};
var student = Backbone.Model.extend({
defaults:{
Code:"",
Name:"",
Score:0
}
});
var stus = new student({
Code:"10107",
Name:"皮卡丘",
Score:750
});
var stuview = Backbone.View.extend({
el:$("#ulshowstus"),
initialize:function(){
this.template = _.template($("#stus-tpl").html())
},
render:function(){
this.$el.html(this.template(this.model.toJSON()));
}
});
var stuv = new stuview({model:stus});
stuv.render();
</script>
</html>
2.源码分析
在本示例中,为了实现自定义模板变量标记的功能,在示例6-5的基础之上进行了两处修改。
(1)在JavaScript代码中,添加了一个名为templateSettings的工具类函数。该函数的功能是设置模板的配置项,其中interpolate属性为插入变量值匹配项,如果使用正则表达式修改该项的属性值就可以自定义模板变量的标记,如将该项的属性值设置为“/\{\{(.+?)\}\}/g”正则表达式,就可以将默认的<%= %>变量标记改为{{ }},也可以根据自己的需求自定义其他的变量标记
(2)在页面代码中,由于重新设置了模板变量标记,在页面模板区添加变量时,必须按照新设定的变量标记格式进行变量的添加。
其余代码的功能在示例6-5中有详细的介绍,不再赘述。
6.3 视图中的元素事件
通过前面章节的学习我们知道,视图对象与页面的交互最为密切,视图类中提供了许多侧重于页面交互的属性或方法,如el属性、render方法等。然而,视图对象与页面的交互远没有这么简单。众所周知,页面的元素不仅可以显示内容,还可以通过事件的触发完成既定的功能,实现人机交互的动态效果。因此,事件也是DOM元素一个重要的特征。
在构建视图类时,可以添加一个events属性,该属性的功能是将DOM元素与触发的事件和执行事件函数相绑定,事件绑定的格式如下。
eventName element:function
其中,用冒号:分成前后i两部分,前面部分定义绑定事件的元素和事件名称,中间用空格隔开。参数eventName表示绑定事件的名称,它包含任何DOM都支持的事件,如click、change等;element参数表示获取绑定元素的选择器,它支持各类的方式获取元素,如按类别、ID号、元素标签获取。function参数表示事件触发时执行的处理函数,该函数通常是在视图内部已定义好的方法。
视图的events属性声明的是一个DOM元素事件列表,多个元素的绑定事件可以使用逗号隔开,只要在事件列表中进行元素事件的绑定声明。在实例化视图对象时,新创建的视图对象将会自动分析events属性值中的事件列表。根据element参数获取DOM元素对象,自动绑定元素事件名称和事件触发时执行的函数。接下来通过完整的示例详细介绍在视图中元素事件的概念。
6.3.1
视图中简单事件绑定
通过前面的介绍我们知道,在视图中绑定一个元素的事件非常简单,只要在events属性值中按规则声明就可以。在声明之前,必须确保事件绑定的页面元素和事件触发时执行的处理函数存在即可。接下来通过一个简单示例进行介绍。
示例6-7 视图中简单事件绑定
1.功能描述
在页面浏览时,以实例化的方式创建一个视图对象,调用对象的render重载方法向页面的<body>元素中追加一个<div>元素,并在<div>元素中显示“backbone是构建前端MVC的利器”字样,当单击<div>元素时,自身的样式也会发生变化。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body{
font-size:13px;
}
div{
width:260px;
padding:5px;
text-align:center;
}
.changed{
border:solid 1px #555;
}
</style>
</head>
<body></body>
<script type="text/javascript">
var stuview = Backbone.View.extend({
el:$("body"),
initialize:function(){
this.render();
},
render:function(){
this.$el.append("<div id='backbone'>backbone是构建前端MVC的利器<div>");
},
events:{
"click div#backbone":"togcls"
},
togcls:function(){
$("#backbone").toggleClass("changed");
}
});
var stuv = new stuview();
</script>
</html>
2.源码分析
在本示例的JavaScript代码中,首先构建视图类时,通过el属性绑定页面中的DOM元素,在构建函数initialize中,调用已定义的render方法。该函数在实例化视图对象时自动执行,因此,当一个视图对象完成实例化后,在执行initialize函数代码时候就已调用了render方法。
为了绑定DOM元素中的事件,在构建视图类时添加events属性,在该属性值中根据视图事件绑定的规则,声明ID号为backbone的<div>元素在click事件中执行togcls处理函数。在执行视图对象的render方法时,将<div>元素追加至<body>元素中,在togcls自定义函数中,便可以按ID号获取该元素对象,并调用对象的toggleClass方法切换自身样式。
最后,实例化一个名为stuv的视图对象,这一操作将触发构造函数initialize的调用,自动执行视图对象render方法中的代码,向<body>元素中添加<div>元素,并自动解析events属性中声明的事件列表。通过选择器获取DOM元素对象,并将对应的事件绑定到对象中,指定事件触发时执行的处理函数。其最终实现的页面效果如上图所示。
6.3.2 绑定视图模板中的多个事件
与绑定页面中的元素事件相同,在视图中绑定模板中元素的事件也非常方便。通常情况下,首先调用_.template()函数获取视图模板中的HTML元素内容,并赋予视图的template属性中。视图对象重载render方法时,将保存在视图template属性中的HTML元素内容以字典传值的方式添加到el属性指定的DOM元素中。因此,当视图对象执行重载render方法后,el属性指定的DOM元素中已包含模板中的全部HTML元素,这样就可以像绑定页面中的元素事件一样绑定视图模板中的元素事件。接下来通过一个简单示例进行介绍。
示例6-8 绑定视图模板中的多个事件
1.功能描述
在页面中先添加一个<div>元素,用于放模板生成的HTML代码。然后使用<script>标记添加一个包含<div>和<input>元素的模板,单击通过模板生成的<div>元素时,本身会切换显示样式,单击<input>按钮时,上面的<div>元素会切换显示状态。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body{
font-size:13px;
}
div{
width:260px;
padding:5px;
text-align:center;
}
.changed{
border:solid 1px #555;
}
</style>
</head>
<body>
<div id="main"></div>
<script type="text/template" id="main-tpl">
<div id="backbone"><%=mess%></div>
<input id="btnshow" type="button" value="点击一下">
</script>
</body>
<script type="text/javascript">
var stuview = Backbone.View.extend({
el:$("#main"),
initialize:function(){
this.template = _.template($("#main-tpl").html());
this.render();
},
render:function(){
this.$el.html(this.template({
mess:"backbone是构建前端MVC的利器"
}));
},
events:{
"click div#backbone":"togcls",
"click input#btnshow":"toggle"
},
togcls:function(){
$("#backbone").toggleClass("changed");
},
toggle:function(){
$("#backbone").toggle();
}
});
var stuv = new stuview();
</script>
</html>
2.源码分析
在本示例的页面中,首先定义一个ID号为“main”的<div>元素,还使用<script>标记定义一个ID号为“main-tpl”的视图模板,在模板中定义一个名为“mess”的模板变量,用于接收并显示传入的内容。
在页面的JavaScript代码中,通过视图类的构造函数initialize将模板中的HTML元素内容保存到视图template属性中,并在重载render方法时,将这些已保存的模板HTML元素内容添加到ID号为“main”的页面元素中,实现在页面中生成模板元素和内容的过程。
在构建视图类时,为了绑定模板中的元素事件,添加了events事件属性。在该属性值中,按照绑定元素事件的规则,以逗号间隔。声明ID号为“backbone”和“btnshow”两个元素所绑定的事件和事件触发时执行的函数。第一个元素绑定的事件名为“click”,触发时执行togcls处理函数,该处理函数通过调用toggleClass方法实现样式的切换显示;第二个元素绑定的事件名也为“click”,触发时执行toggle处理函数,该处理函数通过调用toggle方法实现显示状态的切换。
在本示例的JavaScript代码最后一行,实例化一个名为“stuv”的视图对象,在实例化的过程中,将自动触发视图的重构函数的调用,重载视图对象的render方法,实现在页面中生成模板元素和内容及自动绑定已声明元素事件的过程,其最终实现的页面效果如上图所示。
6.3.2 动态绑定和取消视图中的事件
除了在构建视图类中,通过events属性的方式声明绑定元素的事件之外,视图内部还提供了delegateEvents和undelegateEvents两个方法,用于动态绑定和取消绑定元素的事件。
delegateEvents方法的功能是重新绑定events属性值中已声明的全部元素事件,其调用格式如下代码所示。
delegateEvents([events])
其中,可选项参数events为视图对象的events属性值,也可以不添加该参数,默认值就是视图对象自身的events属性值。
undelegateEvents方法的功能是取消所有已绑定元素的事件,其调用格式如下所示。
undelegateEvents()
该方法无参数,直接调用即可。接下来通过一个简单示例进行介绍。
示例6-9 动态绑定和取消视图中的事件
1.功能描述
在页面中,首先添加一个<div>元素,用于接收并生成模板中的元素内容。然后使用<script>标记添加一个视图模板,在模板按中添加一个用于显示文本内容的<div>元素和三个功能按钮。
单机“切换样式”按钮时,可以切换模板中<div>元素的样式;单击“取消绑定”按钮后,“切换样式”按钮的功能将失效;单击“重新绑定”按钮之后,“切换样式”按钮的功能又重新恢复。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body{
font-size:13px;
}
div{
width:260px;
padding:5px;
text-align:center;
}
.changed{
border:solid 1px #555;
}
</style>
</head>
<body>
<div id="main"></div>
<script type="text/template" id="main-tpl">
<div id="backbone">backbone是构建前端MVC的利器</div>
<input type="button" id="btn_a" value="切换样式"/>
<input type="button" id="btn_b" value="取消绑定"/>
<input type="button" id="btn_c" value="重新绑定" onclick="stuv.rebind()"/>
</script>
</body>
<script type="text/javascript">
var stuv = null;
var stuview = Backbone.View.extend({
el:$("#main"),
initialize:function(){
this.template = _.template($("#main-tpl").html());
this.render();
},
render:function(){
this.$el.html(this.template());
},
rebind:function(){
this.delegateEvents(this.events);
},
events:{
"click input#btn_a":"btnclick_a",
"click input#btn_b":"btnclick_b"
},
btnclick_a:function(){
$("#backbone").toggleClass("changed");
},
btnclick_b:function(){
this.undelegateEvents();
}
});
stuv = new stuview();
</script>
</html>
2.源码分析
在本示例的页面代码中,首先添加一个ID号为“main”的<div>元素,用于显示视图模板元素的内容,并使用<script>标签在页面中添加ID号为“main-tpl”的模板。
在JavaScript代码中,先定义一个全局变量stuv,用于保存实例化后的视图对象。接下来,在stuview的视图中的initialize构造函数中获取页面中的模板对象,并在视图对象重载render方法时,将模板中的HTML元素内容生成到el属性指定的元素中,实现在页面中生成模板元素和内容的过程。
在视图的events属性声明各个DOM元素所绑定的事件中,“切换样式”和“取消绑定”按钮绑定的click事件对应执行的处理函数为“btnclick_a”和“btnclick_b”,前者调用toggleClass方法实现元素样式显示的切换功能,后者调用undelegateEvents方法实现取消视图对象中全部元素已绑定事件的功能。
由于执行undelegateEvents方法之后,该视图中所有通过events属性值声明的绑定事件都被取消,因此“重新绑定”按钮所执行的click事件直接在定义元素时进行添加,这样在执行undelegateEvents方法后是不会取消“重新绑定”这个点击事件的。该事件执行的处理函数为stuv.rebind(),stuv是实例化后的视图对象名称。rebind是一个自定义的方法,功能是调用delegateEvents方法重新绑定视图对象的events属性值中全部声明的元素事件。因此,单击“重新绑定”按钮之后,“切换样式”按钮事件被重新绑定,功能使用恢复正常。
本示例的JavaScript代码的最后一行,使用new关键字实例化一个视图对象,并将该对象赋予全局变量stuv,在视图实例化过程中执行的操作与示例6-8基本相同,不再赘述。
6.4 使用Backbone框架开发前端Web应用
通过前面的学习,我们对Backbone框架的各个主要功能类模块有了一定的了解。总体来讲,Backbone框架中的model对象表示数据模型,用于定义数据结构;collcetion对象是管理数据模型的集合,用于保存或查找数据;view对象的主要功能是数据显示,并用于绑定DOM元素事件和处理页面逻辑。接下来通过一个完整的示例,详细介绍利用Backbone框架开发一个单页前端Web应用的过程。
6.4.1 功能描述
应用包括两个功能。首先数据录入功能,在页面中增加3个文本输入框分别用于输入“编号”、“姓名”、“分数”;增加一个“提交”按钮,单击该按钮时,将输入的数据以模型对象的方式添加到集合对象中。其次是数据显示功能,当输入的数据添加完成之后,将已添加的数据通过视图对象展现在页面的指定元素中。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
body
{
font-size: 12px;
}
ul
{
list-style-type: none;
padding: 0px;
margin: 0px;
width: 270px;
}
ul li
{
margin: 5px 0px;
}
ul .lh
{
font-weight: bold;
border-bottom: solid 1px #555;
background-color: #eee;
height: 23px;
line-height: 23px;
}
ul .lc
{
border-bottom: dashed 1px #ccc;
height: 23px;
line-height: 23px;
}
ul li span
{
padding-left: 10px;
width: 80px;
float: left;
}
</style>
</head>
<body>
<ul id="ulshowstus">
<li class="lh">
<span>编号</span>
<span>姓名</span>
<span>分数</span>
</li>
</ul>
<br/>
<ul>
<li>
编号
<input type="text" id="txtCode">
</li>
<li>
姓名
<input type="text" id="txtName">
</li>
<li>
分数
<input type="text" id="txtScore">
</li>
<li>
<input id="btnSubmit" type="button" value="提交"/>
</li>
</ul>
<!-- 模板代码 -->
<script type="text/template" id="stus-tpl">
<li class="lc">
<span><%=Code%></span>
<span><%=Name%></span>
<span><%=Score%></span>
</li>
</script>
</body>
<script type="text/javascript">
var student = Backbone.Model.extend({
defaults:{
Code:"10001",
Name:"张三",
Score:100
}
});
var stulist = Backbone.Collection.extend({
initialize:function(model,options){
this.on("add",options.view.showmodel);
}
});
var stuview = Backbone.View.extend({
el:$("body"),
initialize:function(){
this.stul = new stulist(null,{view:this})
},
events:{
"click #btnSubmit":"addmodel"
},
addmodel:function(){
var stum = new student({
Code:$("#txtCode").val(),
Name:$("#txtName").val(),
Score:$("#txtScore").val()
});
this.stul.add(stum);
},
showmodel:function(model){
this.template = _.template($("#stus-tpl").html());
$("#ulshowstus").append(this.template(model.toJSON()));
}
});
var stuv = new stuview();
</script>
</html>
2.源码分析
本示例的源码由页面代码和JavaScript代码两部分组成。通常情况下,页面代码是为了配合JavaScript代码的功能开发而设置的。本示例的页面代码由三部分组成,分别包含两个<ul>元素和一个<script>模板元素。ID号为“ulshowstus”的<ul>元素用于生成并显示<script>模板元素生成的HTML内容。在另一个<ul>元素中,添加三个<input>文本输入框和一个按钮元素,用于录入模型对象的各属性值和整个数据的提交。
在本示例的JavaScript代码中,由自定义的模型类、集合类、视图类三个部分组成,在构建student模型类时,使用defaults属性定义模型对象的基本属性结构并设置了初始值。在构建stulist集合类时,在构造函数iniaitlize中绑定对象的add事件,向集合中添加模型对象时将触发该事件,并执行形参options中view对象的showmodel方法。
在构建stuview视图类时,首先将el属性值设置为<body>元素,还在构造函数initialize中以实例化的方式定义一个stul集合对象。在定义过程中,采用字典的方式将view的实参值设为this,即实例化视图对象本身;而在集合对象实例化时,也同时触发了stulist集合类中的构造函数的调用。在调用过程中,形参options中view对象将自动变为传来的视图对象,因此向集合对象中添加模型对象时,将执行视图对象中的showmodel方法。
为了绑定ID号为“btnSubmit”的“提交”按钮的click事件,在构建stuview集合类时,添加了events属性。在属性值中定义了按钮的click事件,当触发该按钮的click事件时,将执行addmodel函数。在该处理函数中,先实例化一个stum模型对象,页面中三个文本框输入的值作为实例化对象时的实参值添加到模型对象中,然后调用add方法向向已定义的集合对象stul添加该模型对象。由于在调用add方法时,触发了已绑定的对应事件,在该事件处理函数中,将调用视图对象内部的showmodel方法,完成新增加模型对象的数据显示功能。
在视图内部自定义的showmodel方法中,先将页面中的模板赋予视图本身的template属性值,并将传回的model对象内容转成JSON格式再次重载template属性,最后将模板重载后的结果追加至ID号为“ulshowstus”的元素中,从而实现显示新增加模型对象数据的功能。