多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## Backbone.View(视图) Backbone 视图几乎约定比他们的代码多 — 他们并不限定你的HTML或CSS, 并可以配合使用任何JavaScript模板库。 一般是组织您的接口转换成逻辑视图, 通过模型的支持, 模型变化时, 每一个都可以独立地进行更新, 而不必重新绘制该页面。我们再也不必钻进 JSON 对象中,查找 DOM 元素,手动更新 HTML 了,通过绑定视图的 `render` 函数到模型的 `"change"` 事件 — 模型数据会即时的显示在 UI 中。 **extend**`Backbone.View.extend(properties, [classProperties])` 开始创建自定义的视图类。 通常我们需要重载 [render](#View-render) 函数,声明 [events](#View-delegateEvents), 以及通过 `tagName`, `className`, 或 `id` 为视图指定根元素。 ``` var DocumentRow = Backbone.View.extend({ tagName: "li", className: "document-row", events: { "click .icon": "open", "click .button.edit": "openEditDialog", "click .button.delete": "destroy" }, initialize: function() { this.listenTo(this.model, "change", this.render); }, render: function() { ... } }); ``` 直到运行时, 像`tagName`, `id`, `className`, `el`, 和 `events`这样的属性也可以被定义为一个函数, **constructor / initialize**`new View([options])` 有几个特殊的选项, 如果传入,则直接注册到视图中去: `model`, `collection`, `el`, `id`, `className`, `tagName`, `attributes` 和 `events`。 如果视图定义了一个**initialize**初始化函数, 首先创建视图时,它会立刻被调用。 如果希望创建一个指向 DOM 中已存在的元素的视图,传入该元素作为选项:`new View({el: existingElement})`。 ``` var doc = documents.first(); new DocumentRow({ model: doc, id: "document-row-" + doc.id }); ``` **el**`view.el` 所有的视图都拥有一个 DOM 元素(**el** 属性),即使该元素仍未插入页面中去。 视图可以在任何时候渲染,然后一次性插入 DOM 中去,这样能尽量减少 reflows 和 repaints 从而获得高性能的 UI 渲染。 `this.el` 可以从视图的 `tagName`, `className`, `id` 和 `attributes` 创建,如果都未指定,**el** 会是一个空 `div`。 ``` var ItemView = Backbone.View.extend({ tagName: 'li' }); var BodyView = Backbone.View.extend({ el: 'body' }); var item = new ItemView(); var body = new BodyView(); alert(item.el + ' ' + body.el); ``` **$el**`view.$el` 一个视图元素的缓存jQuery对象。 一个简单的引用,而不是重新包装的DOM元素。 ``` view.$el.show(); listView.$el.append(itemView.el); ``` **setElement**`view.setElement(element)` 如果你想应用一个Backbone视图到不同的DOM元素, 使用**setElement**, 这也将创造缓存`$el`引用,视图的委托事件从旧元素移动到新元素上。 **attributes**`view.attributes` 属性的键值对, 将被设置为视图`el`上的HTML DOM元素的属性, 或者是返回这样的键值对的一个函数。 **$ (jQuery)**`view.$(selector)` 如果页面中引入了 jQuery,每个视图都将拥有 **$** 函数,可以在视图元素查询作用域内运行。 如果使用该作用域内的 jQuery 函数,就不需要从列表中指定的元素获取模型的 ids 这种查询了,我们可以更多的依赖 HTML class 属性。 它等价于运行:`view.$el.find(selector)`。 ``` ui.Chapter = Backbone.View.extend({ serialize : function() { return { title: this.$(".title").text(), start: this.$(".start-page").text(), end: this.$(".end-page").text() }; } }); ``` **template**`view.template([data])` 虽然模板化的视图 不是Backbone直接提供的一个功能, 它往往是一个在你视图定义**template**函数很好的约定。 如此, 渲染你的视图时, 您方便地访问实例数据。 例如,使用Underscore的模板: ``` var LibraryView = Backbone.View.extend({ template: _.template(...) }); ``` **render**`view.render()` **render** 默认实现是没有操作的。 重载本函数可以实现从模型数据渲染视图模板,并可用新的 HTML 更新 `this.el`。 推荐的做法是在 **render** 函数的末尾 `return this` 以开启链式调用。 ``` var Bookmark = Backbone.View.extend({ template: _.template(...), render: function() { this.$el.html(this.template(this.model.attributes)); return this; } }); ``` Backbone并不知道您首选HTML模板的方法。 **render**(渲染) 函数中可以采用拼接HTML字符串,, 或者使用`document.createElement`生成DOM树。 但还是建议选择一个好的 Javascript 模板引擎。 [Mustache.js](http://github.com/janl/mustache.js), [Haml-js](http://github.com/creationix/haml-js), 和 [Eco](http://github.com/sstephenson/eco) 都是很好的选择。 因为[Underscore.js](http://www.css88.com/doc/underscore/)已经引入页面了,如果你喜欢简单的插入JavaScript的样式模板。  [_.template](http://www.css88.com/doc/underscore/#template)可以使用并是一个很好的选择。 无论基于什么考虑,都_永远_不要在 Javascript 中拼接 HTML 字符串。 在DocumentCloud中, 我们使用[Jammit](http://documentcloud.github.com/jammit/) 来打包JavaScript模板,并存储在`/app/views`中,作为我们主要的`core.js`包的一部分。 **remove**`view.remove()` 从 DOM 中移除一个视图。同事调用[stopListening](#Events-stopListening)来移除通过 [listenTo](#Events-listenTo)绑定在视图上的 所有事件。 **delegateEvents**`delegateEvents([events])` 采用 jQuery 的`on`函数来为视图内的 DOM 事件提供回调函数声明。 如果未传入 **events** 对象,使用 `this.events` 作为事件源。 事件对象的书写格式为 `{"event selector": "callback"}`。 省略 `selector` 则事件被绑定到视图的根元素(`this.el`)。 默认情况下,`delegateEvents` 会在视图的构造函数内被调用,因此如果有 `events` 对象,所有的 DOM 事件已经被连接, 并且我们永远不需要去手动调用本函数。 `events` 属性也可以被定义成返回 **events** 对象的函数,这样让我们定义事件,以及实现事件的继承变得更加方便。 视图 [render](#View-render) 期间使用 **delegateEvents** 相比用 jQuery 向子元素绑定事件有更多优点。 所有注册的函数在传递给 jQuery 之前已被绑定到视图上,因此当回调函数执行时, `this` 仍将指向视图对象。 当 **delegateEvents** 再次运行,此时或许需要一个不同的 `events` 对象,所以所有回调函数将被移除,然后重新委托 — 这对模型不同行为也不同的视图挺有用处。 搜索结果页面显示文档的视图看起来类似这样: ``` var DocumentView = Backbone.View.extend({ events: { "dblclick" : "open", "click .icon.doc" : "select", "contextmenu .icon.doc" : "showMenu", "click .show_notes" : "toggleNotes", "click .title .lock" : "editAccessLevel", "mouseover .title .date" : "showTooltip" }, render: function() { this.$el.html(this.template(this.model.attributes)); return this; }, open: function() { window.open(this.model.get("viewer_url")); }, select: function() { this.model.set({selected: true}); }, ... }); ``` **undelegateEvents**`undelegateEvents()` 删除视图所有委托事件。如果要从临时的DOM中禁用或删除视图时,比较有用。