Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Backbone 开发实战
Search
edokeh
September 01, 2013
Technology
220
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Backbone 开发实战
edokeh
September 01, 2013
More Decks by edokeh
See All by edokeh
新一站 HTML5 触屏版开发总结
edokeh
34
8.6k
模块化的Javascript开发-FTF
edokeh
16
1.2k
iphone webapp入门实战
edokeh
14
860
REST实践指南
edokeh
12
660
chrome 插件开发
edokeh
7
770
Other Decks in Technology
See All in Technology
【Gen-AX】20260530開催_JJUG CCC 2026 Spring
genax
0
430
OCI Oracle AI Database Services新機能アップデート(2026/03-2026/05)
oracle4engineer
PRO
0
250
先取りMaven4 ~16年ぶりのメジャーアップデート、その進化とは?~
ogiwarat
0
140
速さだけじゃない! VoidZero ツールが移行先に選ばれる理由
mizdra
PRO
6
760
「嘘をつくテスト」の失敗例から学ぶ 良いテストコード #frontend_phpcon_do
asumikam
0
490
Rancherの紹介&Update情報(RancherJP Online Meetup #09)
yoshiyuki_kono
0
120
個人最適 から 全体最適 へ AI情報共有会・AIギルド・AI-DLC で進める カンリーの組織展開
rfdnxbro
0
1.7k
コードレビューを制するチームがソフトウェアデリバリーのフローを制す / Beyond Code Review: Distributing Its Responsibilities Across the SDLC
mtx2s
4
1.2k
Claude code Orchestra
ozakiomumkj
3
980
Platform engineering for developers, architects & the rest of us (AI agents)
danielbryantuk
0
180
AI と創る新たな世界 / A New World Created with AI
ks91
PRO
0
120
Amazon Bedrock AgentCore ワークショップ JAWS UG TOHOKU / amazon-bedrock-agentcore-workshop-jawsug-tohoku-2026
gawa
8
340
Featured
See All Featured
Skip the Path - Find Your Career Trail
mkilby
1
140
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
The Curse of the Amulet
leimatthew05
1
13k
The SEO identity crisis: Don't let AI make you average
varn
0
480
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Statistics for Hackers
jakevdp
799
230k
30 Presentation Tips
portentint
PRO
1
320
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
430
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
56k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
For a Future-Friendly Web
brad_frost
183
10k
Transcript
Backbone 开发实战 葛亮@焦点科技 2013.09.01
麦通 Web 版
讲些什么 • Backbone 简介 • Model 篇 • View 篇
• 其他经验
Backbone 简介
Backbone 原理 Model & Collection View DOM 服务器 事件通知 change
add, remove … 更新 DOM 用户交互事件 调用方法 更新数据
Backbone 的哲学 关注点分离 简洁、灵活 • 依赖 Underscore 与 jQuery,丏业的事交给丏业的库 •
基本的数据模型支持,但没有针对复杂场景建模 • View 非常简单,由开发者决定如何渲染 DOM Model • 数据存取 • 事件通知 • 业务逻辑 View • 根据 Model 展示界面 • 监听事件,修改界面 • 将用户的输入反馈给 Model Backbone 给开发者预留的空间太大 反而让不少初学者感到迷惑
Model 篇 • 以数据为中心 • Model 的关联 • 虚属性
以数据为中心 events : { 'click li' : 'changeStatus' }, changeStatus
: function (e) { var target = $(e.currentTarget); var status = target.data('status'); this.$('.title').text(target.text()); this.model.set('status', status); }, initialize : function() { this.listenTo(this.model, 'change', this.render); } 不要将数据与展示混在一起 请抛弃 jQuery 思维
Model 的关联 var Group = Backbone.Model.extend({ initialize : function (options)
{ // 直接使用属性保存,Friends 是 Collection this.friends = new Friends(options.friends); // 做一下属性的清理 this.unset('friends'); } }); var group = new Group({ name : '我的好友', friends : [ {name : 'geliang'}, {name : 'zhangxu'} ] }); Group 包含多个 Friend 但 Backbone 没有内置 Model 的关联 • 简单的场景下选用简单的方式 • 复杂的场景可以尝试Backbone-relational 等 • 可以将 friends 的事件冒泡至自身 this.listenTo(this.friends, 'all', function () { arguments[0] = 'friends:' + arguments[0]; this.trigger.apply(this, arguments); });
虚属性 initialize : function (options) { …… this.listenTo(this.friends, 'add remove
change:status', this.updateCount); }, updateCount : function () { this.set({ 'onlineCount' : ……, 'totalCount' : this.friends.length }); } 虚属性 • 添加虚属性可以方便 View 的渲染 • 面向场景不同,因此客户端与服务器的模型不必完全一致 • 请让服务器接口宽松一些 服务器并不保存 Group 的在线人数
View 篇 • View 的渲染效率 • 渲染 Collection • 如何处理超大
View • View 乊间如何交互
View 的渲染效率 var UserView = Backbone.View.extend({ template : _.template($('#tpl').html()), initialize
: function () { this.listenTo(this.model, 'change', this.render); this.render(); }, render : function () { var html = this.template(this.model.toJSON()); this.$el.html(html); } }); 修改一个属性就重绘整个 View 会不会有效率问题?
View 的渲染效率 initialize : function () { this.listenTo(this.model, 'change:name', this.renderName);
this.render(); }, renderName:function(){ this.$('.name').text(this.model.get('name')); }, render : function () { var html = this.template(this.model.toJSON()); this.$el.html(html); this.renderName(); } 注意避免渲染逻辑的重复 PS:Backbone.ModelBinder 等方案可以简化这个过程
View 的渲染效率 局部渲染 vs 整体渲染 • 性能有差距,尤其是 IE 较明显 •
从绝对值来看,整体渲染的性能可以接受 • 模板变大时,整体渲染性能下降 73 984 35 151 0 200 400 600 800 1000 1200 Chrome IE8 改变 status 属性 1000 次 局部渲染 整体渲染 1525 152 984 151 0 500 1000 1500 2000 整体渲染 局部渲染 大模板 vs 小模板 小模板 大模板 <a class="{{ status }}">{{ nick }}</a>
View 的渲染效率 局部渲染 vs 整体渲染 • 尽量使用整体渲染,减少复杂度 • 针对明显的性能瓶颈使用局部渲染 •
细粒度的 View • 选用更快的模板引擎(?) 99 224 173 2886 1771 0 500 1000 1500 2000 2500 3000 3500 artTemplate Handlebars doT underscore Mustache 100 条数据万次渲染
渲染 Collection 问题场景 • 用 Collection 存储分组的好友列表 • 每个好友对应一个的 View
• 该怎么编写这个分组的 View? FriendView 展示 Friend 模型 GroupView 对应 Group 模型 Group 包含 Friend 的 Collection
渲染 Collection 需要考虑的问题 • 编写逻辑添加、删除子 View • 内部维护所有子 View 以便查找
• 管理子 View 的生命周期 Marionette.View ItemView CollectionView Layout CompositeView Backbone.View 建议使用 Marionette 的 View 组件
渲染 Collection 试试 ItemView var FriendView = Backbone.Marionette.ItemView.extend({ template :
_.template($('#item-template').html()), initialize : function () { this.render(); this.model.on('change', this.render, this); }, render : function () { this.$el.html(this.template(this.model.toJSON())); } }); template : '#item-template', modelEvents : { 'change' : 'render' }, ui : { 'status' : '.status' }, onRender : function () { } 指定模板时可以用选择器 默认的 render 方法 有 events 为啥没有 modelEvents 呢? 可以这样用 this.ui.status.addClass(…) 渲染完毕乊后的回调
渲染 Collection 超简单的 CollectionView var FriendsView = Backbone.Marionette.CollectionView.extend({ itemView: FriendView,
emptyView: EmptyFriendView }); var friendsView = new FriendsView({ collecion : friends }); • 自劢监听并处理 collection 的 add, remove, reset 事件 • 子 view 的生命周期的自劢管理 • 不支持模板,完全由子 View 组成 与 FriendView 配合渲染 friends 为空时显示这个 View 显示 Group 可以用 CompositeView
渲染 Collection 更强大的 CompositeView var GroupView = Backbone.Marionette.CompositeView.extend({ template :
'#group-tpl' itemView : FriendView, emptyView : EmptyFriendView, itemViewContainer : 'ul', }); var groupView = new GroupView({ model : group, collection : group.friends }); CollectionView & CompositeView • 回调函数:onAfterItemAdded, onItemRemoved • 子 View 事件冒泡至自身:itemview:* • 重载 appendHtml 自定义子 View 如何放置 • …… 模板,同 ItemView 指定子 view 该添加到哪里
如何处理超大 View 聊天信息区域 公司信息区域 窗口标题 表情选择弹窗 输入区域 快捷键选择菜单 • 拆分成多个子
View • 在父 View 中组装管理这些子 View
如何处理超大 View 使用 Marionette.Layout var ChatWindowView = Backbone.Marionette.Layout.extend({ template :
'#chat-window-tpl', regions : { 'titleWrap' : '#titleWrap', 'companyWrap' : '#companyWrap' }, onRender : function () { this.titleWrap.show(new TitleView({model : this.model})); this.companyWrap.show(new CompanyView({model : this.model})); } }); 模板,同 ItemView 定义 Region 渲染完毕后组装子 View 通过 Region 的 show 方法显示子 View • Region 可以自劢管理子 View 的生命周期 • .close() 可以彻底删除子 View • .show() 会隐式调用 .close() • 尽量避免 Layout 的整体重绘
View 之间如何交互 选择表情乊后,在输入框中显示 • FaceView • InputView
View 之间如何交互 EventBus • 一个对所有对象可见的“事件频道” • Backbone 对象自带这项功能 var FaceView
= Backbone.Marionette.ItemView.extend({ events : { 'click .face' : 'selectFace' }, selectFace : function () { Backbone.trigger('selectFace', $(this).data('value')); } }); var InputView = Backbone.View.extend({ initialize : function () { Backbone.on('selectFace', this.insertText, this); }, // ... });
View 之间如何交互 中介者模式 • 由中介者监听事件,并作出处理 • 推荐由父 view 充当中介者 var
FaceView = Backbone.Marionette.ItemView.extend({ selectFace : function () { this.trigger('selectFace', $(this).data('value')); } }); var MainView = Backbone.Marionette.Layout.extend({ onRender : function () { var inputView = new InputView(); var faceView = new FaceView(); faceView.on('selectFace', inputView.insertText); // ... } });
View 之间如何交互 该如何选择? • 业务耦合较紧密时选用中介者模式,否则选用 EventBus • 使用中介者模式需要对架构做一些设计 • EventBus
可能会造成一些可维护性困难 • 注意避免 EventBus 的滥用,例如替代 Model 事件
其他经验 • 如何吭劢应用 • mixin • 慎用 _.bindAll(this) • 使用
.listenTo()
如何启动应用 使用 Marionette.Application var app = new Backbone.Marionette.Application(); app.addRegions({ 'main'
: '#main', 'nav' : '#nav' }); app.addInitializer(function () { this.main.show(new MainView()); }); app.addInitializer(function () { this.nav.show(new NavView()); }); app.start(); 又见 Region 定义多个 Initializer 以拆分代码 吭劢应用,会执行 Initializer
mixin var Status = { isOnline : function () {
// ... }, statusText : function () { // ... } }; _.extend(Friend.prototype, Status); _.extend(User.prototype, Status); • 通过 mixin 在多个类乊间复用代码 • 可以看做是包含了实现的 Java Interface • 规避了继承和组合
慎用 _.bindAll(this) var Friends = Backbone.Collection.extend({ model : Friend, initialize
: function () { _.bindAll(this); } // ... }); var friends = new Friends([{name : 'geliang'}]); 通过 bindAll 希望确保所有方法 执行时 this 依然为 Friends 对象 IE 下会报错 • _.bindAll(this) 是对所有 function 属性执行 _.bind() • _.bind() 为 IE 提供的实现对 new 操作符支持有问题 • Underscore 1.5 已经修复,但 bindAll 不再支持单个参数 • 养成好习惯,请明确指定需要 bind 的参数 Friend 也被 bind 了 Marionette.CollectionView 等尤其要注意哦! _.bindAll(this, 'methodA', 'methodB');
使用 .ListenTo() var FriendView = Backbone.View.extend({ initialize : function ()
{ this.model.on('change', this.render, this); this.listenTo(this.model, 'change', this.render); }, // ... }); 传入此参数指定回调函数的 this • listenTo 不需要额外参数来指定 this • Marionette.View 的 modelEvents 等属性调用了 listenTo • listenTo 让监听者能够保存所有事件监听,方便后续移除 remove: function() { this.$el.remove(); this.stopListening(); return this; }
一些小结 • Backbone 提供了基本的架构,留给开发者较大的自由 • 一件事可能有多种解决方案,根据场景权衡 • Marionette 为一些场景提供了默认解决方案 •
Marionette 有大量组件和理念可供挖掘
感谢聆听 Questions ?