在用 Backbone 开发的 JavaScript 应用里面,除了模型与集合以外,另一个重要的部分就是视图,英文是 View 。在视图里面,我们可以去监听在页面上发生的事件,还有与视图相关的模型和集合的事件,可以去定义处理这些事件用的方法,可以设置包装数据用的元素等等。
模型视图
下面, 先去为 Todo 这个模型的数据创建一个视图,定义这个视图的代码放在 js/Views/TodoView.js 这个文件里面。打开这个文件,输入下面这些代码:
var app = app || {}; /** * 视图 View * * 为任务模型创建的视图 - TodoView */ app.TodoView = Backbone.View.extend({ // 设置视图的 el 属性的标签 tagName: 'li', // 创建一个模板来组织任务模型数据 itemTemplate: _.template($('#item-template').html()), // 设置视图 el 属性里的具体内容 render: function() { this.$el.html(this.itemTemplate(this.model.attributes)); return this; } });
这里的 app.TodoView 就是我们为 Todo 这个模型定义的视图。在 Backbone 里面,创建一个视图可以让它等于 Backbone.View.extend
。
在这个视图里面,设置了一下 tagName
这个属性,它的值就是这个视图的 el 属性的包装元素。另外,你还可以设置 className
,id
,或者 attributes
属性,去在这个包装元素上面添加 css 类名,id,还有其它的属性。attributes
这个属性的值是一个对象,在这个对象里面,你可以去设置想要添加到这个包装元素上面的属性的名字,还有对应的值。
itemTemplate
,这是为任务这个模型设计的一个模板,在 Backbone 里面,可以使用第三方提供的模板功能,比如 Mustache,Handlebars,Underscore 的 Template 功能等等。在下面,我们会用到 Underscore 的模板功能为任务模板创建一个模板。先继续往下看。
接着我们又在视图里面,添加了一个 render
方法。这个方法可以设置一下与显示相关的逻辑。在这里,去设置了一下任务这个模型的显示,用视图的 el 元素包装了一下用定义好的模板处理好的内容。最后用了一个 return this
,这样我们可以继续使用链式调用的方式去使用其它的方法与属性。
模板
先回到应用的主页:index.html,在这里,找一个地方去为任务模型定义一个模板,这个模板就是在上面定义的任务的视图里面用到的那个。在 index.html 这个文档的 body 标签里面,可以随便找一个地方,然后输入下面的代码:
<!-- 任务模型的模板 --> <script type="text/template" id="item-template"> <div class="view"> <input type="checkbox" class="toggle" <%= completed ? 'checked' : '' %>> <label><%= title %></label> </div> </script>
我们把模板定义在了一组 script
标签里面,在这个标签上,添加了一个 type="text/template"
,它的作用就是不让浏览器认为它里面的东西是 JavaScript 的代码,这样浏览器会忽略掉这些 script 标签里面的东西。
在这组 script
标签里面,id
这个属性的值,可以认为是这个模板的名字。在这里就是 item-template
,在视图里面,需要用到这个 id 来定位这组 script 标签里面的内容,也就是模板的具体的内容。
模板的结构就是先用了一组 div
标签,上面有一个叫 view
的 css 类。然后在它里面,先是一个 checkbox 类型的 input 元素,也就是一个复选框,它的作用就是改变任务的完成的状态,勾选了复选框,表示任务已经完成了,没勾选的话,就表示任务没有完成。
在这个复选框里面,用了一组特殊的标记:<%= ... %>
,这是 Underscore 的模板功能要用到的特殊的标记,表示在这里要输出点东西,在这里,我们先判断了一下 completed
这个东西的值,它的值要在视图里面传递进来。如果 completed
的值是 true
的话,就在这个复选框元素上,添加一个 checked
属性,表示勾选了这个复选框。如果 completed
的值是 false
的话,就不会在这个复选框上添加这个 checked
属性。
label
元素里面,同样用了一组特殊标记,要输出的东西叫做 title
,也就是任务的标题,它的值,也需要在视图里面传递进来。
在视图里使用模板
再回到 TodoView.js 这个文件来看一下 app.TodoView 这个视图。先看一下这行代码:
itemTemplate: _.template($('#item-template').html()),
它的作用就是在视图里定义了一个模板的方法,叫 itemTemplate
,定义它的时候,用到了 Underscore 的模板功能(_.template),我们需要把定义好的模板的具体的内容交给这个 _.template
方法,所以,我们用到了 jQuery 来找到在页面上包含 #ite-template
这个 id 的元素,也就是在 index.html 文档里面为任务模型创建的模板,定位到这个元素以后,又调用了 jQuery 的 html
这个方法来得到这个元素里面的具体的内容。
有了这个模板的方法以后,我们就可以用它去组织一下模型的内容了。需要把模板里面需要的几个东西交给这个模板的方法。在这里就是,你需要告诉模板,completed
的值是什么,title
的值是什么。告诉它以后,模板的方法就会用具体的这个值来替换掉在模板里面的特殊标记里的东西。
再看一下在视图的 render 这个方法里面的这行代码:
this.$el.html(this.itemTemplate(this.model.attributes));
this.$el
,this 表示当前的这个视图,用它的 $el ,这个 $el 是用 jQuery 包装之后的视图的 el 属性的一个简单的写法,这样我们就可以使用其它的方法去处理这个 el 属性里面的东西了。在这里,用到了 html
这个方法,去设置了一个它里面的具体的内容。这个内容就是用定义好的模板处理之后的模型的内容。
this.itemTemplate
,使用当前视图的 itemTemplate 这个模板方法,然后把模板需要的内容交给了这个方法。this.model.attributes
,可以得到与当前视图相关的模型里面的属性,在我们定义的 Todo 这个模型里面,包含 title 属性,还有 completed 属性,这些属性的值,就是在定义好的模板里面要用到的。
练习
到现在,你可能还是有些模糊。下面, 通过一些练习,再来理解一下,视图的作用,模板是什么,视图里的 el 属性是什么,视图的 render 方法又有什么作用。
用 Chrome 浏览器打开应用的主页 index.html,打开浏览器的控制台(Mac:alt + command + J,Win:alt + ctrl + J),然后:
1. 先在控制台新建一个任务的模型。
var todo_1 = new app.Todo({title: '学习 Backbone', completed: false})
在上面,我们创建了一个叫 todo_1 的任务模型,在创建它的时候,给它指定了一下 title 还有 completed 这两个属性的值。
2. 然后访问一下这个新建的模型里面的属性。
todo_1.attributes
你会看到在创建模型的时候,为模型设置的属性。得到的是一个对象,里面的内容就是模型的属性还有对应的值。
3. 再去创建一个任务模型的视图。
var todoView = new app.TodoView({model: todo_1})
在创建这个任务模型的时候,我们为它指定了一个相关的模型,这个模型就是最开始创建的那个 todo_1。
4. 访问一下视图的 el 属性。
todoView.el
因为还没有使用视图的 render 方法,所以,默认视图的 el 属性就是一组标签,在创建视图的时候,我们设置了一下 tagName 这个属性,指定了 el 属性的标签为 li ,所以,在这里,你会看到给我们返回来的就是一组 li 标签。
5. 调用视图的 render 方法。
todoView.render()
在视图的 render 方法里面,我们为视图的 el 属性设置了具体的内容,所以,在调用视图的这个 render 方法以后,就会用设计好的内容填充到这个 el 属性的包装元素里面。
6. 再次访问一下视图的 el 属性。
todoView.el
现在,你看到的,就是渲染之后的视图的 el 属性的值。得到的就是用设置好的包装元素(li)包装的并且用模板组织好的模型的内容。
JavaScript Backbone