Backbone.js教程(初级篇) 这是菜鸟与老油条,屌丝与高富帅的战争 —— 译者:茶几 @chajn 原作者:脱袜子·戴蕾丝 原文:http://backbonetutorials.com/

Backbone.js教程(初级篇)

这是菜鸟与老油条,屌丝与高富帅的战争 —— 译者:茶几 @chajn

原作者:脱袜子·戴蕾丝  原文:http://backbonetutorials.com/

1. 为啥你需要Backbone.js?

我们知道,仅仅使用jQuery或MooTools啥的来构建web应用或复杂的用户界面是极其困难的。
主要是因为这些JS库都把心思花费在它们擅长做的事情上了,而并没有意识到的是,即便没有任何页面结构,也是可以构建完整的应用的。
用Backbone就可以很容易的把你的应用部署到一个通过jQuery回调的嵌套堆中,然后在页面生成DOM元素实体。

我不需要解释为什么没有结构的页面构建是一个坏主意。
你当然可以每次构造应用的时候都发明一种实现方式,但这只是瞬间的美丽,你错过的是后世的精彩!
那你将永远只能是个屌ser。Balabala……

2. 啥是model?

网络上对MVC的定义是比较尿的,你甚至不知道怎样去理解和怎样去做。
但backbone.js的作者对backbone.js的model表现的定义就很明确。
Models是任何JS应用的核心部分,包括数据交互和众多相关逻辑:格式转换,校验,属性计算,访问控制等。
好的,让我们先创建一个model:

?
1
2
3
4
5
6
7
Person = Backbone.Model.extend({
         initialize:  function (){
             alert( "Welcome to this world" );
         }
     });
    
     var  person =  new  Person;

-
SO我们看到new一个model的实例后就会触发initialize()函数(models,collections 和 views 的工作机制都是一样滴)。虽然可以不声明initialize,但我们可能会经常用到。

2.1 设置属性

现在我们想设置一些属性,有两种方式,可以在创建model实例时进行传参,也可以在实例生成后通过model.set(obj)来进行设置。  

?
01
02
03
04
05
06
07
08
09
10
11
Person = Backbone.Model.extend({
         initialize:  function (){
             alert( "Welcome to this world" );
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67});
     delete  person;
     //或者用set,操作等价
     var  person =  new  Person();
     person.set({ name:  "Thomas" , age: 67});

-
两种方式在功能上是一样的。有设置属性,就有读取属性,下一步我们来获取它们。

2.2 获取属性

很简单,用 model.get(name)方法就可以读取属性值了。

?
01
02
03
04
05
06
07
08
09
10
11
Person = Backbone.Model.extend({
         initialize:  function (){
             alert( "欢迎来到这个二蛋的世界" );
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
    
     var  age = person.get( "age" );  // 67
     var  name = person.get( "name" );  // "Thomas"
     var  children = person.get( "children" );  // ['Ryan']

-

2.3 设置model默认属性

有的时候你可能会想让model有默认属性值。
没的问题,只要在进行model声明的时候设置个'defaults'就行了。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Person = Backbone.Model.extend({
         defaults: {
             name:  'Fetus' ,
             age: 0,
             children: []
         },
         initialize:  function (){
             alert( "欢迎来到这个三蛋的世界" );
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
    
     var  age = person.get( "age" );  // 67
     var  name = person.get( "name" );  // "Thomas"
     var  children = person.get( "children" );  // ['Ryan']

-

2.4 操纵model的属性

Models可以添加自定义方法来进行自身的属性修改,默认这些方法都是公开的。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Person = Backbone.Model.extend({
         defaults: {
             name:  'Fetus' ,
             age: 0,
             children: []
         },
         initialize:  function (){
             alert( "欢迎来到这个四蛋的世界" );
         },
         adopt:  function ( newChildsName ){
             var  children_array =  this .get( "children" );
             children_array.push( newChildsName );
             this .set({ children: children_array });
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
     person.adopt( 'John Resig' );
     var  children = person.get( "children" );  // ['Ryan', 'John Resig']

-
添加了自定义方法之后,我们就可以更好的控制实例的自身属性了。

2.5 监听model的属性改变

现在说点有用的,我们可以通过model.bind(event,callback)方法来绑定change事件来监听属性改变。
下面的这个例子就是在initialize方法中绑定了一个name属性改变的事件监听。
如果person的name属性改变了,就会弹出个对话框显示新值。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Person = Backbone.Model.extend({
         defaults: {
             name:  'Fetus' ,
             age: 0,
             children: []
         },
         initialize:  function (){
             alert( "欢迎来到这个无蛋的世界" );
             this .bind( "change:name" function (){
                 var  name =  this .get( "name" );  // 'Stewie Griffin'
                 alert( "我的名字变为"  + name );
             });
         },
         replaceNameAttr:  function ( name ){
             this .set({ name: name });
         }
     });
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
     person.replaceNameAttr( 'Stewie Griffin' );  // 改变后触手会alert()

-
可以单个属性监听,也可以直接监听所有的属性,如:'this.bind("change", function(){});'

2.6 提取,存储和销毁

Models实际上是collection的一部分,用于向服务器请求啥的。
本部分的教程关注的是个体models,咳咳,更多的功能请查看collection部分。

2.7 提示和技巧

2.7.1 获取当前所有的属性

?
1
2
3
4
5
6
var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
     var  attributes = person.toJSON();  // { name: "Thomas", age: 67, children: ['Ryan']}
     /* 返回对当前属性的copy */
     delete  attributes;
     var  attributes = person.attributes;
     /* 上行返回属性的直接引用,对其的任何改变就等于实例属性本身的改变,所以还是建议你使用.set()来进行属性的设置,因为还有backbone的监听呀 */

-

2.7.2 在设置或存储属性的时候进行数据校验

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Person = Backbone.Model.extend({
         // 如果从validate中返回字符串了, Backbone就会抛个实例异常
         validate:  function ( attributes ){
             if ( attributes.age < 0 && attributes.name !=  "Dr Manhatten"  ){
                 return  "你的存在是个错误" ;
             }
         },
         initialize:  function (){
             alert( "欢迎来到这个报错的世界" );
             this .bind( "error" function (model, error){
                 // 收到个错误,记录,警告,然后忘记它。╮(‵▽′)╭
                 alert( error );
             });
         }
     });
    
     var  person =  new  Person;
     person.set({ name:  "Mary Poppins" , age: -1 });
     // 会触发error,输出警告
     delete  person;
    
     var  person =  new  Person;
     person.set({ name:  "Dr Manhatten" , age: -1 });
// 上帝为何怜悯我们的灵魂,只因为打开的方式不对

-

3. 啥是view?

Backbone的views是用来体现应用的数据模型的。他们还可以用于监听事件。
本部分教程不会说关于views绑定models和collections的事情,重点说一下视图能力和如何使用views与JS模板库,特别是Underscore.js的 _.template。
我们使用jQuery 1.5操作DOM,当然也可以使用其他的库比如MooTools或Sizzle,但Backbone.js的官方文档说支持使用jQuery。
咳咳,也就是说Backbone.View事件在jQuery以外的库中可能无法使用。
好我们开始,这回我们要实现一个搜索框。

?
1
2
3
4
5
6
7
8
9
SearchView = Backbone.View.extend({
         initialize:  function (){
             alert( "Alerts suck." );
         }
     });
    
     // The initialize function is always called when instantiating a Backbone View.
     // Consider it the constructor of the class.
     var  search_view =  new  SearchView;

-

3.1 “el”属性

“el”属性引用DOM对象。每个Backbone.js的view都会有个“el”属性。
如果没定义的话它会默认创建一个空的div元素。
来让我们设置个div#search_container到el属性上去,以保证这个Backbone.View是有效的。

?
01
02
03
04
05
06
07
08
09
10
11
< div  id = "search_container" ></ div >
    
< script  type = "text/javascript" >
     SearchView = Backbone.View.extend({
         initialize: function(){
             alert("Alerts suck.");
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-
注意:既然是绑定在了这个容器元素了,那就代表着所有的事件都是以此DOM元素为基础而触发的噢。

3.2 模板加载

Backbone.js是依赖于Underscore.js的,因为它包括micro-templating方案。
更多信息请参考Underscore.js'的官方文档去。
让我们实现一个“render()”方法进行视图初始化,“render()”方法会用jQuery加载我们的模板到“el”属性的容器中。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
< div  id = "search_container" ></ div >
   
< script  type = "text/template"  id = "search_template" >
     < label >Search</ label >
     < input  type = "text"  id = "search_input"  />
     < input  type = "button"  id = "search_button"  value = "Search"  />
</ script >
   
< script  type = "text/javascript" >
     SearchView = Backbone.View.extend({
         initialize: function(){
             this.render();
         },
         render: function(){
             // Compile the template using underscore
             var template = _.template( $("#search_template").html(), {} );
             // Load the compiled HTML into the Backbone "el"
             this.el.html( template );
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-
提示:可以将你的模板放到CDN中的单独文件里,这样用户使用就不用每次都下载了。

3.3 事件监听

在view加一个监听,可以用Backbone.View的“events”属性。
要记得,事件监听只能绑定到“el”属性的子元素中。
让我们绑定个“click”事件到按钮上去。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
< div  id = "search_container" ></ div >
   
< script  type = "text/template"  id = "search_template" >
     < label >Search</ label >
     < input  type = "text"  id = "search_input"  />
     < input  type = "button"  id = "search_button"  value = "Search"  />
</ script >
   
< script  type = "text/javascript" >
     SearchView = Backbone.View.extend({
         initialize: function(){
             this.render();
         },
         render: function(){
             var template = _.template( $("#search_template").html(), {} );
             this.el.html( template );
         },
         events: {
             "click input[type=button]": "doSearch"
         },
         doSearch: function( event ){
             // Button clicked, you can access the element that was clicked with event.currentTarget
             alert( "Search for " + $("#search_input").val() );
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-

3.4 提示和技巧

3.4.1 使用模板变量

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
< div  id = "search_container" ></ div >
   
< script  type = "text/template"  id = "search_template" >
     <!-- Access template variables with <%= %> -->
     < label ><%= search_label %></ label >
     < input  type = "text"  id = "search_input"  />
     < input  type = "button"  id = "search_button"  value = "Search"  />
</ script >
   
< script  type = "text/javascript" >
      SearchView = Backbone.View.extend({
         initialize: function(){
             this.render();
         },
         render: function(){
             //Pass variables in using Underscore.js Template
             var variables = { search_label: "My Search" };
             // Compile the template using underscore
             var template = _.template( $("#search_template").html(), variables );
             // Load the compiled HTML into the Backbone "el"
             this.el.html( template );
         },
         events: {
             "click input[type=button]": "doSearch"
         },
         doSearch: function( event ){
             // Button clicked, you can access the element that was clicked with event.currentTarget
             alert( "Search for " + $("#search_input").val() );
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-

4. 啥是collection?

Backbone的collections其实就是个有序的models集合。适用于以下情况;

  • Model: Student, Collection: ClassStudents

  • Model: Todo Item, Collection: Todo List

  • Model: Animals, Collection: Zoo

通常你的collection可能只用一个类型的model,但是models并不局限于某一类型的collection;

  • Model: Student, Collection: Gym Class

  • Model: Student, Collection: Art Class

  • Model: Student, Collection: English Class

关于Model/Collection,这里有一个通用的例子。

?
1
2
3
4
5
6
7
8
9
var  Song = Backbone.Model.extend({
         initialize:  function (){
             console.log( "Music is the answer" );
         }
     });
    
     var  Album = Backbone.Collection.extend({
         model: Song
     });

-

4.1 构建 collection

现在我们来点实在的,下面的例子演示了collection的使用方法。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
var  Song = Backbone.Model.extend({
         defaults: {
             name:  "Not specified" ,
             artist:  "Not specified"
         },
         initialize:  function (){
             console.log( "Music is the answer" );
         }
     });
    
     var  Album = Backbone.Collection.extend({
         model: Song
     });
    
     var  song1 =  new  Song({ name:  "How Bizarre" , artist:  "OMC"  });
     var  song2 =  new  Song({ name:  "Sexual Healing" , artist:  "Marvin Gaye" });
     var  song3 =  new  Song({ name:  "Talk It Over In Bed" , artist:  "OMC"  });
    
     var  myAlbum =  new  Album([ song1, song2, song3]);
     console.log( myAlbum.models );  // [song1, song2, song3]

-

5. 啥是router?

?
1
2
3
4
5
//@注1:本章的所有实例都是在http://example.com顶级域名下实现的。
//如果是http://example.com/tset/test.html的形式,则路径标记#前不能加/。
//@注2:Backbone.js 0.9.2 的取路径后的值是posts/12,匹配^/posts/([^/]+)$不能(/posts/:id转换后的正则表达式)。所以原参数要改为posts/:id,测试才能通过。
//以下有错误的地方标红不改,以此类推。

-
Backbone的routers其实就相当于你的应用URL的hash(#)。
如果你读过“啥是view?”,那你应该知道,他们并不符合传统的MVC语义,本章将会详细解释这一点。
尽管Backbone的“router”对任何程序和功能都很有用,但它需要URL的routing/history功能。
Routers的定义包括路径和映射函数,下面的例子就让我们定义一个路径。
还请注意,routes只解析url的“#”之后的标记。
你的应用的所有链接都应该是像“#/action”或“#action”这样。
(附加个斜杠看起来会更好一些,比如:http://example.com/#/user/help)

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<script>
     var  AppRouter = Backbone.Router.extend({
         routes: {
             "*actions" "defaultRoute"  // matcheshttp://example.com/#anything-here
         },
         defaultRoute:  function ( actions ){
             // The variable passed in matches the variable in the route definition "actions"
             alert( actions );
         }
     });
     // Initiate the router
     var  app_router =  new  AppRouter;
     // Start Backbone history a neccesary step for bookmarkable URL's
     Backbone.history.start();
    
</script>
    
_URL进行变化_
[Activate route]( #action)
[Activate another route]( #/route/action)

-
请注意:Backbone 0.5 (released 1. July 2011)之前的版本,Router被称作Controller。为了避免字义混淆,Backbone的开发人员把名字改成Router了。
因此,如果你发现自己使用了Backbone的一个旧版本,那你应该写Backbone.Controller.extend({ ** });

5.1 动态Routing

原始框架允许你的routes定义包含动静混合态路径参数。
例如,你可能想进行检索一个post的id,你的URL看起来可能会是“http://example.com/#/posts/12”。
一旦这个路径被激活,你就可以取到id的值并做相应的处理了。下面是这个例子的实现。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
     var  AppRouter = Backbone.Router.extend({
         routes: {
             "/posts/:id" "getPost" , //@注2
             "*actions" "defaultRoute"  // Backbone will try match the route above first
         },
         getPost:  function ( id ) {
             // Note the variable in the route definition being passed in here
             alert(  "Get post number "  + id );
         },
         defaultRoute:  function ( actions ){
             alert( actions );
         }
     });
     // Instantiate the router
     var  app_router =  new  AppRouter;
     // Start Backbone history a neccesary step for bookmarkable URL's
     Backbone.history.start();
    
</script>
    
_URL进行改变_
[Post 120]( #/posts/120)
[Post 130]( #/posts/130)

-

5.2 动态路径对比——":params"和"*splats"

Backbone使用两种参数模式实现路径,第一种是":params"匹配URL路径内任何斜杠之间的字符串,而还有一种是"splats"匹配任意数量的URL路径。
注意"splat"的本质意思,他总是最后一个变量,因为它匹配的是URL路径之后的全部内容。
在route中定义的任何"*splats"或":params"都会以参数的形式穿入关联函数中。
比如一个route定义了"/:route/:action",那就会传入两个参数(“route”和“action”) 到回调函数中。
下面的示例使用":params"和"*splats"。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
routes: {
             "/posts/:id" "getPost" , //@注2,下同
             // <a href="http://example.com/#/posts/121">Example</a>
             "/download/*path" "downloadFile" ,
             // <a href="http://example.com/#/download/user/images/hey.gif">Download</a>
             "/:route/:action" "loadView" ,
             // <a href="http://example.com/#/dashboard/graph">LoadRoute/Action View</a>
         },
    
         getPost:  function ( id ){
             alert(id);  // 121
         },
         downloadFile:  function ( path ){
             alert(path);  // user/images/hey.gif
         },
         loadView:  function ( route, action ){
             alert(route +  "_"  + action);  // dashboard_graph
         }

-

这是菜鸟与老油条,屌丝与高富帅的战争 —— 译者:茶几 @chajn

原作者:脱袜子·戴蕾丝  原文:http://backbonetutorials.com/

1. 为啥你需要Backbone.js?

我们知道,仅仅使用jQuery或MooTools啥的来构建web应用或复杂的用户界面是极其困难的。
主要是因为这些JS库都把心思花费在它们擅长做的事情上了,而并没有意识到的是,即便没有任何页面结构,也是可以构建完整的应用的。
用Backbone就可以很容易的把你的应用部署到一个通过jQuery回调的嵌套堆中,然后在页面生成DOM元素实体。

我不需要解释为什么没有结构的页面构建是一个坏主意。
你当然可以每次构造应用的时候都发明一种实现方式,但这只是瞬间的美丽,你错过的是后世的精彩!
那你将永远只能是个屌ser。Balabala……

2. 啥是model?

网络上对MVC的定义是比较尿的,你甚至不知道怎样去理解和怎样去做。
但backbone.js的作者对backbone.js的model表现的定义就很明确。
Models是任何JS应用的核心部分,包括数据交互和众多相关逻辑:格式转换,校验,属性计算,访问控制等。
好的,让我们先创建一个model:

?
1
2
3
4
5
6
7
Person = Backbone.Model.extend({
         initialize:  function (){
             alert( "Welcome to this world" );
         }
     });
    
     var  person =  new  Person;

-
SO我们看到new一个model的实例后就会触发initialize()函数(models,collections 和 views 的工作机制都是一样滴)。虽然可以不声明initialize,但我们可能会经常用到。

2.1 设置属性

现在我们想设置一些属性,有两种方式,可以在创建model实例时进行传参,也可以在实例生成后通过model.set(obj)来进行设置。  

?
01
02
03
04
05
06
07
08
09
10
11
Person = Backbone.Model.extend({
         initialize:  function (){
             alert( "Welcome to this world" );
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67});
     delete  person;
     //或者用set,操作等价
     var  person =  new  Person();
     person.set({ name:  "Thomas" , age: 67});

-
两种方式在功能上是一样的。有设置属性,就有读取属性,下一步我们来获取它们。

2.2 获取属性

很简单,用 model.get(name)方法就可以读取属性值了。

?
01
02
03
04
05
06
07
08
09
10
11
Person = Backbone.Model.extend({
         initialize:  function (){
             alert( "欢迎来到这个二蛋的世界" );
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
    
     var  age = person.get( "age" );  // 67
     var  name = person.get( "name" );  // "Thomas"
     var  children = person.get( "children" );  // ['Ryan']

-

2.3 设置model默认属性

有的时候你可能会想让model有默认属性值。
没的问题,只要在进行model声明的时候设置个'defaults'就行了。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Person = Backbone.Model.extend({
         defaults: {
             name:  'Fetus' ,
             age: 0,
             children: []
         },
         initialize:  function (){
             alert( "欢迎来到这个三蛋的世界" );
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
    
     var  age = person.get( "age" );  // 67
     var  name = person.get( "name" );  // "Thomas"
     var  children = person.get( "children" );  // ['Ryan']

-

2.4 操纵model的属性

Models可以添加自定义方法来进行自身的属性修改,默认这些方法都是公开的。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Person = Backbone.Model.extend({
         defaults: {
             name:  'Fetus' ,
             age: 0,
             children: []
         },
         initialize:  function (){
             alert( "欢迎来到这个四蛋的世界" );
         },
         adopt:  function ( newChildsName ){
             var  children_array =  this .get( "children" );
             children_array.push( newChildsName );
             this .set({ children: children_array });
         }
     });
    
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
     person.adopt( 'John Resig' );
     var  children = person.get( "children" );  // ['Ryan', 'John Resig']

-
添加了自定义方法之后,我们就可以更好的控制实例的自身属性了。

2.5 监听model的属性改变

现在说点有用的,我们可以通过model.bind(event,callback)方法来绑定change事件来监听属性改变。
下面的这个例子就是在initialize方法中绑定了一个name属性改变的事件监听。
如果person的name属性改变了,就会弹出个对话框显示新值。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Person = Backbone.Model.extend({
         defaults: {
             name:  'Fetus' ,
             age: 0,
             children: []
         },
         initialize:  function (){
             alert( "欢迎来到这个无蛋的世界" );
             this .bind( "change:name" function (){
                 var  name =  this .get( "name" );  // 'Stewie Griffin'
                 alert( "我的名字变为"  + name );
             });
         },
         replaceNameAttr:  function ( name ){
             this .set({ name: name });
         }
     });
     var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
     person.replaceNameAttr( 'Stewie Griffin' );  // 改变后触手会alert()

-
可以单个属性监听,也可以直接监听所有的属性,如:'this.bind("change", function(){});'

2.6 提取,存储和销毁

Models实际上是collection的一部分,用于向服务器请求啥的。
本部分的教程关注的是个体models,咳咳,更多的功能请查看collection部分。

2.7 提示和技巧

2.7.1 获取当前所有的属性

?
1
2
3
4
5
6
var  person =  new  Person({ name:  "Thomas" , age: 67, children: [ 'Ryan' ]});
     var  attributes = person.toJSON();  // { name: "Thomas", age: 67, children: ['Ryan']}
     /* 返回对当前属性的copy */
     delete  attributes;
     var  attributes = person.attributes;
     /* 上行返回属性的直接引用,对其的任何改变就等于实例属性本身的改变,所以还是建议你使用.set()来进行属性的设置,因为还有backbone的监听呀 */

-

2.7.2 在设置或存储属性的时候进行数据校验

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Person = Backbone.Model.extend({
         // 如果从validate中返回字符串了, Backbone就会抛个实例异常
         validate:  function ( attributes ){
             if ( attributes.age < 0 && attributes.name !=  "Dr Manhatten"  ){
                 return  "你的存在是个错误" ;
             }
         },
         initialize:  function (){
             alert( "欢迎来到这个报错的世界" );
             this .bind( "error" function (model, error){
                 // 收到个错误,记录,警告,然后忘记它。╮(‵▽′)╭
                 alert( error );
             });
         }
     });
    
     var  person =  new  Person;
     person.set({ name:  "Mary Poppins" , age: -1 });
     // 会触发error,输出警告
     delete  person;
    
     var  person =  new  Person;
     person.set({ name:  "Dr Manhatten" , age: -1 });
// 上帝为何怜悯我们的灵魂,只因为打开的方式不对

-

3. 啥是view?

Backbone的views是用来体现应用的数据模型的。他们还可以用于监听事件。
本部分教程不会说关于views绑定models和collections的事情,重点说一下视图能力和如何使用views与JS模板库,特别是Underscore.js的 _.template。
我们使用jQuery 1.5操作DOM,当然也可以使用其他的库比如MooTools或Sizzle,但Backbone.js的官方文档说支持使用jQuery。
咳咳,也就是说Backbone.View事件在jQuery以外的库中可能无法使用。
好我们开始,这回我们要实现一个搜索框。

?
1
2
3
4
5
6
7
8
9
SearchView = Backbone.View.extend({
         initialize:  function (){
             alert( "Alerts suck." );
         }
     });
    
     // The initialize function is always called when instantiating a Backbone View.
     // Consider it the constructor of the class.
     var  search_view =  new  SearchView;

-

3.1 “el”属性

“el”属性引用DOM对象。每个Backbone.js的view都会有个“el”属性。
如果没定义的话它会默认创建一个空的div元素。
来让我们设置个div#search_container到el属性上去,以保证这个Backbone.View是有效的。

?
01
02
03
04
05
06
07
08
09
10
11
< div  id = "search_container" ></ div >
    
< script  type = "text/javascript" >
     SearchView = Backbone.View.extend({
         initialize: function(){
             alert("Alerts suck.");
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-
注意:既然是绑定在了这个容器元素了,那就代表着所有的事件都是以此DOM元素为基础而触发的噢。

3.2 模板加载

Backbone.js是依赖于Underscore.js的,因为它包括micro-templating方案。
更多信息请参考Underscore.js'的官方文档去。
让我们实现一个“render()”方法进行视图初始化,“render()”方法会用jQuery加载我们的模板到“el”属性的容器中。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
< div  id = "search_container" ></ div >
   
< script  type = "text/template"  id = "search_template" >
     < label >Search</ label >
     < input  type = "text"  id = "search_input"  />
     < input  type = "button"  id = "search_button"  value = "Search"  />
</ script >
   
< script  type = "text/javascript" >
     SearchView = Backbone.View.extend({
         initialize: function(){
             this.render();
         },
         render: function(){
             // Compile the template using underscore
             var template = _.template( $("#search_template").html(), {} );
             // Load the compiled HTML into the Backbone "el"
             this.el.html( template );
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-
提示:可以将你的模板放到CDN中的单独文件里,这样用户使用就不用每次都下载了。

3.3 事件监听

在view加一个监听,可以用Backbone.View的“events”属性。
要记得,事件监听只能绑定到“el”属性的子元素中。
让我们绑定个“click”事件到按钮上去。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
< div  id = "search_container" ></ div >
   
< script  type = "text/template"  id = "search_template" >
     < label >Search</ label >
     < input  type = "text"  id = "search_input"  />
     < input  type = "button"  id = "search_button"  value = "Search"  />
</ script >
   
< script  type = "text/javascript" >
     SearchView = Backbone.View.extend({
         initialize: function(){
             this.render();
         },
         render: function(){
             var template = _.template( $("#search_template").html(), {} );
             this.el.html( template );
         },
         events: {
             "click input[type=button]": "doSearch"
         },
         doSearch: function( event ){
             // Button clicked, you can access the element that was clicked with event.currentTarget
             alert( "Search for " + $("#search_input").val() );
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-

3.4 提示和技巧

3.4.1 使用模板变量

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
< div  id = "search_container" ></ div >
   
< script  type = "text/template"  id = "search_template" >
     <!-- Access template variables with <%= %> -->
     < label ><%= search_label %></ label >
     < input  type = "text"  id = "search_input"  />
     < input  type = "button"  id = "search_button"  value = "Search"  />
</ script >
   
< script  type = "text/javascript" >
      SearchView = Backbone.View.extend({
         initialize: function(){
             this.render();
         },
         render: function(){
             //Pass variables in using Underscore.js Template
             var variables = { search_label: "My Search" };
             // Compile the template using underscore
             var template = _.template( $("#search_template").html(), variables );
             // Load the compiled HTML into the Backbone "el"
             this.el.html( template );
         },
         events: {
             "click input[type=button]": "doSearch"
         },
         doSearch: function( event ){
             // Button clicked, you can access the element that was clicked with event.currentTarget
             alert( "Search for " + $("#search_input").val() );
         }
     });
    
     var search_view = new SearchView({ el: $("#search_container") });
</ script >

-

4. 啥是collection?

Backbone的collections其实就是个有序的models集合。适用于以下情况;

  • Model: Student, Collection: ClassStudents

  • Model: Todo Item, Collection: Todo List

  • Model: Animals, Collection: Zoo

通常你的collection可能只用一个类型的model,但是models并不局限于某一类型的collection;

  • Model: Student, Collection: Gym Class

  • Model: Student, Collection: Art Class

  • Model: Student, Collection: English Class

关于Model/Collection,这里有一个通用的例子。

?
1
2
3
4
5
6
7
8
9
var  Song = Backbone.Model.extend({
         initialize:  function (){
             console.log( "Music is the answer" );
         }
     });
    
     var  Album = Backbone.Collection.extend({
         model: Song
     });

-

4.1 构建 collection

现在我们来点实在的,下面的例子演示了collection的使用方法。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
var  Song = Backbone.Model.extend({
         defaults: {
             name:  "Not specified" ,
             artist:  "Not specified"
         },
         initialize:  function (){
             console.log( "Music is the answer" );
         }
     });
    
     var  Album = Backbone.Collection.extend({
         model: Song
     });
    
     var  song1 =  new  Song({ name:  "How Bizarre" , artist:  "OMC"  });
     var  song2 =  new  Song({ name:  "Sexual Healing" , artist:  "Marvin Gaye" });
     var  song3 =  new  Song({ name:  "Talk It Over In Bed" , artist:  "OMC"  });
    
     var  myAlbum =  new  Album([ song1, song2, song3]);
     console.log( myAlbum.models );  // [song1, song2, song3]

-

5. 啥是router?

?
1
2
3
4
5
//@注1:本章的所有实例都是在http://example.com顶级域名下实现的。
//如果是http://example.com/tset/test.html的形式,则路径标记#前不能加/。
//@注2:Backbone.js 0.9.2 的取路径后的值是posts/12,匹配^/posts/([^/]+)$不能(/posts/:id转换后的正则表达式)。所以原参数要改为posts/:id,测试才能通过。
//以下有错误的地方标红不改,以此类推。

-
Backbone的routers其实就相当于你的应用URL的hash(#)。
如果你读过“啥是view?”,那你应该知道,他们并不符合传统的MVC语义,本章将会详细解释这一点。
尽管Backbone的“router”对任何程序和功能都很有用,但它需要URL的routing/history功能。
Routers的定义包括路径和映射函数,下面的例子就让我们定义一个路径。
还请注意,routes只解析url的“#”之后的标记。
你的应用的所有链接都应该是像“#/action”或“#action”这样。
(附加个斜杠看起来会更好一些,比如:http://example.com/#/user/help)

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<script>
     var  AppRouter = Backbone.Router.extend({
         routes: {
             "*actions" "defaultRoute"  // matcheshttp://example.com/#anything-here
         },
         defaultRoute:  function ( actions ){
             // The variable passed in matches the variable in the route definition "actions"
             alert( actions );
         }
     });
     // Initiate the router
     var  app_router =  new  AppRouter;
     // Start Backbone history a neccesary step for bookmarkable URL's
     Backbone.history.start();
    
</script>
    
_URL进行变化_
[Activate route]( #action)
[Activate another route]( #/route/action)

-
请注意:Backbone 0.5 (released 1. July 2011)之前的版本,Router被称作Controller。为了避免字义混淆,Backbone的开发人员把名字改成Router了。
因此,如果你发现自己使用了Backbone的一个旧版本,那你应该写Backbone.Controller.extend({ ** });

5.1 动态Routing

原始框架允许你的routes定义包含动静混合态路径参数。
例如,你可能想进行检索一个post的id,你的URL看起来可能会是“http://example.com/#/posts/12”。
一旦这个路径被激活,你就可以取到id的值并做相应的处理了。下面是这个例子的实现。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
     var  AppRouter = Backbone.Router.extend({
         routes: {
             "/posts/:id" "getPost" , //@注2
             "*actions" "defaultRoute"  // Backbone will try match the route above first
         },
         getPost:  function ( id ) {
             // Note the variable in the route definition being passed in here
             alert(  "Get post number "  + id );
         },
         defaultRoute:  function ( actions ){
             alert( actions );
         }
     });
     // Instantiate the router
     var  app_router =  new  AppRouter;
     // Start Backbone history a neccesary step for bookmarkable URL's
     Backbone.history.start();
    
</script>
    
_URL进行改变_
[Post 120]( #/posts/120)
[Post 130]( #/posts/130)

-

5.2 动态路径对比——":params"和"*splats"

Backbone使用两种参数模式实现路径,第一种是":params"匹配URL路径内任何斜杠之间的字符串,而还有一种是"splats"匹配任意数量的URL路径。
注意"splat"的本质意思,他总是最后一个变量,因为它匹配的是URL路径之后的全部内容。
在route中定义的任何"*splats"或":params"都会以参数的形式穿入关联函数中。
比如一个route定义了"/:route/:action",那就会传入两个参数(“route”和“action”) 到回调函数中。
下面的示例使用":params"和"*splats"。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
routes: {
             "/posts/:id" "getPost" , //@注2,下同
             // <a href="http://example.com/#/posts/121">Example</a>
             "/download/*path" "downloadFile" ,
             // <a href="http://example.com/#/download/user/images/hey.gif">Download</a>
             "/:route/:action" "loadView" ,
             // <a href="http://example.com/#/dashboard/graph">LoadRoute/Action View</a>
         },
    
         getPost:  function ( id ){
             alert(id);  // 121
         },
         downloadFile:  function ( path ){
             alert(path);  // user/images/hey.gif
         },
         loadView:  function ( route, action ){
             alert(route +  "_"  + action);  // dashboard_graph
         }

-

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
---------------- backbone开发经典 336页清晰完整版pdf-------------- 内容简介 · · · · · · backbone.js提供了一套web开发的框架,为复杂javascript应用程序提供一个mvc结构。 《backbone.js应用程序开发》详细介绍了如何使用backbone.js完成web应用开发。全书从了解mvc、spa和backbone.js的基本知识开始,然后着手构建3个示例应用程序;此外,backbone和grunt-bbb、jquery mobile等开发工具的配合使用,以及jasmine、qunit和sinonjs等测试解决方案。 本书的作者是知名的javascript专家、谷歌chrome团队的工程师addy osmani。本书适合于javascript程序员、web开发人员,尤其是想要学习和使用backbone.js的读者阅读参考。 如果你想使用单页应用程序(spa)模型创建前端站点,本书向你展示了如何使用backbone.js完成这类工作。你将学会使用backbone自有风格的模型-视图-控制器(mvc)架构,来创建结构化的javascript应用程序。 《backbone.js应用程序开发》先从了解mvc、spa和backbone的基本知识开始,然后着手构建示例应用程序——一个简单的todo列表应用程序、restful风格的图书应用程序、以及使用backbone和requirejs的模块化应用程序。本书的作者是谷歌chrome团队的工程师addy osmani,他还演示了框架的高级应用。 《backbone.js应用程序开发》包括以下内容: 了解backbone.js如何给客户端带来mvc方面的好处; 编写易于阅读的、结构化的和易扩展代码 ; 使用backbone.marionette和thorax扩展框架; 解决使用backbone.js时会遇到的常见问题; 使用amd和requirejs将代码进行模块化组织; 使用backbone.paginator插件为collections数据分页; 使用样板代码引导新的backbone.js应用程序; 使用jquery mobile,并解决两者之间的路由问题; 使用jasmine、qunit和sinonjs对backbone应用进行单元测试。 作者简介 · · · · · · Addy Osmani,本书的作者是知名的JavaScript专家、谷歌Chrome团队的工程师,他对JavaScript应用程序架构有着强烈的爱好,还创建了一些比较流行的项目,如TodoMVC,并且对Yeoman、Modernizr和jQuery等其他开源项目也有重要贡献。除此之外,Addy Osmani也是一位高产的博主(http://addyosmani.com/blog),同时也是O'reilly出版的《JavaScript设计模式》一书的作者。 徐涛(网名:汤姆大叔;微博:@TomXuTao),微软最有价值专家(MVP)、项目经理、软件架构师,擅长大型互联网产品的架构与设计,崇尚敏捷开发模式,熟悉设计模式、前端技术、以及各种开源产品,曾获MCP、MCSE、MCDBA、MCTS、MCITP、MCPD、PMP认证。《JavaScript编程精解》、《JavaScript启示录》译者,博客地址:Http://www.cnblogs.com/TomXu。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值