Emberjs 20150601


http://guides.emberjs.com/v1.11.0/templates/displaying-a-list-of-items/


我们使用Handlebars的{{#each}} 来枚举一个对象列表内容。
<ul>
{{#each person in people}}
<li>Hello, {{person.name}} !</li>
{{/each}}
</ul>
位于{{#each}}{{/each}}块内的模板将会被重复呈现:
<ul>
  <li>Hello, Yehuda!</li>
  <li>Hello, Tom!</li>
  <li>Hello, Trek!</li>
</ul>
{{#each}} 是绑定感知助手,如果你的应用程序添加一个新的元素到数组,或者移除一个元素,DOM会自动更新,而不需要编写任何代码。


{{#each}} 有一个匹配关键字{{else}} ,其块内容会在数组为空时显示。
{{#each person in people}}
  Hello, {{person.name}}!
{{else}}
  Sorry, nobody is here.
{{/each}}


绑定元素属性:
http://guides.emberjs.com/v1.11.0/templates/binding-element-attributes/


除了标准的文本,你也可能想让你的模板包含一些属性绑定到controller的HTML元素。
比如,假设你的Controller有一个属性包含一个图片的URL:
<div id="logo">
<img src={{logoUrl}} alt="logo">
</div>


会生成如下HTML:
<div id="logo">
  <img src="http://www.example.com/images/logo.png" alt="Logo">
</div>


绑定多个值:
我们可以为单个属性绑定多个值:handlebar <div class="{{priority}} {{placement}}"</div>


绑定布尔值:
如果我们要绑定一个布尔值,则意味着它会添加或者移除特定属性。 比如:
<input type="checkbox" disabled={{isAdministrator}}>


添加数据属性:
默认情况下,view 助手不接受 data 属性,比如
{{#link-to "photos" data-toggle="dropdown"}}Photos{{/link-to}}
{{input type="text" data-toggle="tooltip" data-placement="bottom" title="Name"}}
将会渲染出如下内容:
<a id="ember239" class="ember-view" href="#/photos">Photos</a>
<input id="ember257" class="ember-view ember-text-field" type="text" title="Name">


有两种方式可以view助手支持data属性,一种是为特定属性添加一个绑定到view的属性,比如Ember.LinkView 或者 Ember.TextField
export default Ember.LinkView.reopen({
attributeBindings: ['data-toggle']
});


export defalut Ember.TextField.reopen({
attributeBinding:['data-toggle','data-placement']
});
这样,上面的同样HBS代码渲染的内容变为:
<a id="ember240" class="ember-view" href="#/photos" data-toggle="dropdown">Photos</a>


<input id="ember259" class="ember-view ember-text-field"
       type="text" data-toggle="tooltip" data-placement="bottom" title="Name">


另一种方式:自动绑定data属性到基视图 base view:
export default Ember.View.reopen({
init:function(){
this._super();
var self = this;

//bind attributes beginning with 'data-'
Em.keys(this).forEach(function(key){
if(key.substr(0,5) === 'data-'{
self.get('attributeBindings').pushObject(key);
}
});
}
});
这样一来你就可以添加任意data- 开头的属性而不用必须指定他们的名字了。




链接:
http://guides.emberjs.com/v1.11.0/templates/links/


{{link-to}}助手,用于创建一个指向一个route的链接。
app/router.js
Router.map(function(){
this.route("photos", function(){
this.route("edit", {path: "/:photo_id"});
});
});


app/templates/photos.hbs
<ul>
{{#each photo in photos}}
<li> {{#link-to 'photos.eadit' photo}}{{photo.title}}{{/link-to}}</li>
{{/each}}
</ul>


如果photos.hbs模板对应的一个三个对象的model,那么渲染结果如下:
<ul>
  <li><a href="/photos/1">Happy Kittens</a></li>
  <li><a href="/photos/2">Puppy Running</a></li>
  <li><a href="/photos/3">Mountain Landscape</a></li>
</ul>


如果某个渲染的链接刚好匹配当前的route,并且传入到{{#link-to}}助手的对象刚好匹配,那么该链接将会被添加class="ative" 属性。


{{link-to}}助手使用route的name,这里可能是 index,photos,或者photos.edit
每个动态片段最多有一个model,默认情况下Ember.js 将使用对应对象的id替换每个动态变量。
如果没有model对象传入给{{link-to}}助手,我们可以显式的指定该变量值。 该值会被填充到动态变量里,并保证触发controller的model 钩子。
title是可选项,用于绑定到a 的title属性。
app/templates/photos.hbs
{{#link-to 'photos.edit' 1}}
First Photo Ever
{{/link-to}}




多个动态变量的例子:
如果是一个嵌套路由,你可以提供一个model或者为每一个动态变量指定值。
app/router.js
Router.map(function(){
this.route("photos", function(){
this.route("photo", {path: "/:photo_id"}, function(){
this.route("comments");
this.route("comment", {path: "/comments/:comment_id" });
});
});
});


app/templates/photo/index.hbs
<div class="photo">
{{body}}
</div>
<p> {{#link-to 'photos.photo.comment' primaryComment}} Main Comment {{/link-to}}</p>
如果你只指定了一个model,它将显示最内部的动态变量即 :comment_id。 而:photo_id变量将沿用当前的photo对象


所以我们可以传入一个photo和一个comment对象该{{link-to}}助手:
app/templates/photo/index.hbs
<p>
{{#link-to 'photo.comment' 5 primaryComment}}
Main Comment for the Next Photo
{{/link-to}}
</p>
上例中,PhotoRoute的model钩子将会使用params.photo_id = 5 运行。 CommentRoute的model钩子将不会运行,因为你为comment变量提供了一个model对象。
comment的id将会根据CommentRoute的 serialize 钩子发布URL


将{{link-to}}作为一个内嵌助手使用:
除了用于块状表达式外,link-to助手还可以用于行内,此时它需要链接文本作为第一个参数。


A link in {{#link-to 'index'}}Block Expression Form{{/link-to}}, and a link in {{link-to 'Inline Form' 'index'}}.


其输出如下:
A link in <a href='/'>Block Expression Form</a>,
and a link in <a href='/'>Inline Form</a>.


给链接添加额外属性:
在生成链接时你可能需要为其添加额外的属性,我们可以通过link-to助手的额外参数来完成。
<p>
{{link-to 'Eidit this photo' 'photo.edit' photo class="btn btn-primary"}}
</p>
许多个HTML属性都可以这样设置,当添加class 名时,Ember将同时应用标准ember-view和可能的active class名。


替换历史入口:
link-to 默认情况下在两个路由之间传输时会添加入口到浏览器的历史记录,然而,我们可以使用replace=true选项来替换浏览器历史中的当前入口。
<p>
{{#link-to 'photo.comment' 5 primaryComment replace=true}}
Main Comment for the Next Photo
{{/link-to}}
</p>




Action 助手
http://guides.emberjs.com/v1.11.0/templates/actions/


我们的应用程序需要一种方式来让用户跟我们的控件交互来改变应用程序的状态。比如,假设你有一个显示博客的模板,支持使用其它信息扩展博文。
我们可以使用{{action}} 助手来设置一个可以单击的HTML元素,当用户单击该元素时,指定的事件就会发送给应用程序。
app/templates/post.hbs
<div class='intro'>
{{intro}}
</div>


{{#if idExpanded}}
<div class='body'>{{body}}</div>
<button {{action 'contract'}}>Contract</button>
{{else}}
<button {{action 'expand'}}>Show More...</button>
{{/if}}


app/controllers/post.js
export default Ember.ObjectController.extend({
//initial value
isExpand: false,

actions:{
expand: function(){
this.set('isExpanded', true);
},

contract: function(){
this.set('isExpanded', false);
}
}
});


注意,action可以被附加到任何DOM元素,但是不是所有的都响应click事件。
比如一个附加到 一个没有 href属性 <a> 链接的action,或者附加到一个div,有些浏览器不会执行相关函数。
如果真的要为这些元素定义action,一个CSS工作区可以让它们可以被单击,cursor:pointer
[data-ember-action]{
cursor: pointer;
}


Action Bubbling: Action传递
默认情况下,{{action}}助手会触发模板对应的controller里的一个方法。
如果我们模板对应的Controller里没有定义该action的处理方法(该方法必须和action同名),那么action会被发送给router,
在router里的当前活动的route会有机会来处理该action.


无论是在routes还是在controller里来定义处理action都必须把处理器方法放在一个叫actions的hash表里。
在route中,action handler定义如果不放入actions[],即使定义了同名的action处理器,也不会被触发。
但在controller中,现在也弃用了对直接定义处理器的触发支持,转而要求放入actions哈希表,来达到向上兼容一致。


app/routes/post.js
export defalut Ember.Route.extend({
actions:{
expand: function(){
this.controller.set('isExpanded', true);
},
contract: function(){
this.controller.set('isExpanded', false);
}
}
});
注意,这里的关键字this是指route,而非actions 哈希表


如果需要继续向上传递action,则需要action处理方法返回 true。
app/route/post.js


export default Ember.Route.extend({
actions:{
expand:function(){
this.controller.set('isExpanded' , true);
},

contract:function(){
this.controller.set('isExpanded', false);
if(actionShouldAlsoBeTriggeredOnParentRoute){
return true;
}
}
}
});


如果出现无论是模板对应的controller还是当前活动的route都没有实现对action的处理方法,action将会继续被向上传递到任何一个父级route。
最终到达ApplicationRoute。


如果controller和所有层级的route都没有对应的实现方法,那么就会有错误抛出。


这种冒泡传递机制可以让你有机会为某个按钮在不同目录层级提供不同的行为处理实现。 比如,你可能想让在一个侧边栏里的button
在/posts route下时做一些事情,在/about route下时做另外一些事情。


Action的参数:
我们可能需要为Action的处理方法传递参数,Emberjs会把所有的跟在{{Action}} 名称 后面的参数传入给其对应的处理方法。
比如下面例子传递post参数给处理方法:
<p><button {{action "select" post}}Right</button>{{post.title}}</p>
对应的controller中定义的该action处理方法:
app/controllers/post.js
export default Ember.ObjectController.extend({
actions:{
select: function(post){
console.log(post.get('title'));
}
}
});




指定Action的事件类型:
默认情况下,{{action}} 助手监听click事件并在用户单击该元素时触发相应的事件处理器。
我们可以使用 on 可选关键字在为其指定替代的触发事件类型:
<p>
<button {{action "select" post on="mouseUp"}} Right</button>
{{post.title}}
</p>
需要注意的是你需要使用标准的事件名,通常是两个单词联合比如keyPress




指定白名单修饰关键字:
默认情况下,{{action}}会在pressed 有修饰关键字下忽略click事件,我们可以使用allowedKeys 选项来指定哪个键不能被忽略。
<div {{action 'anActionName' allowedKeys="alt"}}>
click me
</div>
这里{{action}}的处理器只有当用户按住alt键单击时才会被触发。


阻止action事件传播:
默认情况下{{action}}允许事件处理被向上传递给父级DOM节点,如果你想阻止他们传递,你可以使用bubble=false 属性来完成。


如果有一个x button 在一个链接里面,你希望用户单击该button时,该链接不会被触发:
{{#link-to 'post'}}
Post
<button {{action 'close' bubbles=false}}>X </button>
{{/link-to}}


上例中如果没有bubbles=false,那么用户单击该X 按钮时,Ember.js会触发action,然后浏览器会把click传递给链接。
有了它,就会阻止浏览器传递该click事件给父级元素。








指定一个Target:
默认情况下,{{action}} 会发送action到视图的target,通常为该视图的controller。
注意:如果是Ember.Component的情况下,默认的target是 component 自己。


我们可以通过target 参数来指定一个替代的目的地,这通常用在将action发往view而不是controller的时候。


<p>
  <button {{action "select" post target=view}}>✓</button>
  {{post.title}}
</p>


如此我们可以在views中定义处理action的方法:
app/views/post.js
export default Ember.View.extend({
actions:{
select: function(post){
//do you business
}
}
});
注意按照这种方式发给view的action不会再在视图层级体系中向上传递。如果你想在父级视图来处理该action,则需要直接将action
发往该父级视图。
<p>
  <button {{action "select" post target=view.parentView}}>✓</button>
  {{post.title}}
</p>




Input 助手:
http://guides.emberjs.com/v1.11.0/templates/input-helpers/


{{input}}和{{textarea}}在Ember.js中是创建通用表单控件的最容易的方式。
{{input}} 助手封装了内建的Ember.TextField和Ember.Checkbox 视图,而{{textarea}} 封装的是Ember.TextArea。
使用它们声明创建这些视图几乎跟传统的<input>或者<textarea>元素一样。
{{input value="http://www.facebook.com"}}
将会渲染为:
<input type="text" value="http://www.facebook.com"/>
我们可以在{{input}}助手中传入如下标准属性:
`readonly` `required` `autofocus`
`value` `placeholder` `disabled`
`size` `tabindex` `maxlength`
`name` `min` `max`
`pattern` `accept` `autocomplete`
`autosave` `formaction` `formenctype`
`formmethod` `formnovalidate` `formtarget`
`height` `inputmode` `multiple`
`step` `width` `form`
`selectionDirection` `spellcheck`


这些属性设置时如果使用双引号包裹,那么这些值会直接设置在该元素上。
然而,当保持没有引号时,这些值会被绑定到模板当前渲染上下文的一个属性上。比如:
{{input type="text" value = firstName disabled=entryNotAllowed size="50"}}
这里的value会绑定到当前上下文的 firstName上,disabled 属性会绑定到当前上下文的entryNotAllowed 上。




要派遣某个Action到指定事件,比如enter 或者 key-press,可以使用on 关键字:
{{input value=firstName action="updateFirstName" on="key-press"}}
注意在给on赋值的时候,事件名称必须是短线分割形式。




CHECKBOX:
我们还可以使用{{input}}设置其type属性为 checkbox 来创建Checkbox
{{input type="checkbox" name="isAdmin" checked=isAdmin}}


Checkbox支持如下属性:
checked
disabled
tabindex
indeterminate
name
autofocus
form
同样的它们都可以用于设置属性值用引号包裹,或者绑定容器属性,无引号包裹。


TEXTAREA:
{{textarea value=name cols="80" rows="6"}}
这里将绑定textarea的value属性到容器的name属性上。
它同时还支持绑定或设置如下属性:
value
name
rows
cols
placeholder
disabled
maxlength
tabindex
selectionEnd
selectionStart
selectionDirection
wrap
readonly
autofocus
form
spellcheck
required




扩展内建的控件:将会在视图View的内建控件部分介绍。




开发助手helpers:
http://guides.emberjs.com/v1.11.0/templates/development-helpers/


Handlebar和Ember拥有一些助手类使得我们开发模板时工作变得更容易了。这些助手可以使得输出到你浏览器控制台的变量简化,或者从你模板中激活调试器。


日志:{{log}}
该助手可以方便的从你当前的渲染环境中将变量或者表达式输出到浏览器的控制台。
{{log 'Name is: " name}}


{{log}}助手同样接受像字符串或者数字这类基本类型。




设置一个断点:{{debugger}} 提供了一个等价于javascript的debugger 关键字的handlebar版本。
它能够停止位于该助手块内地代码执行并让你能够检查当前渲染的上下文。
{{debugger}}
在该助手被调用之前有两个有用的变量需要定义:
templateContext :当前可以获取值的上下文,类似controller
typeOfTemplateContext: 一个描述templateContext的字符串


比如,我们想知道为什么一个特定的变量没有显示在我们的模板中时,我们可以使用{{debugger}}助手,设置了断点后,我们就可以在浏览器的控制台
使用templateContext查看该属性了。
> templateContext.get('name')
"Bruce Lee"






使用助手进行渲染:
http://guides.emberjs.com/v1.11.0/templates/rendering-with-helpers/


Ember.js提供了许多助手类来帮助你以不同的方式渲染视图和模板。
{{partial}} 助手类:
能将模板当作一个参变量进行渲染,并且渲染到指定位置。
{{partial}}不会改变上下文或范围。它只是把一个给定的模板使用当前范围放置到指定的位置。


app/templates/author.hbs
Written by {{author.firstName}} {{author.lastName}}


app/templates/post.hbs
<h1>{{title}}</h1>
<div>{{body}}</div>
{{partial "author"}}


渲染结果:
<div>
  <h1>Why You Should Use Ember.JS</h1>
  <div>Because it's awesome!</div>
  Written by Yehuda Katz
</div>




{{view}}助手类:
类似于{{partial}},但是它不是提供一个模板template渲染到当前模板中,而是提供一个视图view类,由该视图决定着要渲染什么到当前模板照中。
app/views/author.js


export default Ember.View.extend({
//We are setting templateName manually here to the default value
templateName:"author",

//A fullName property should probably go on App.Author, but we're doing it here for the example
fullName: function(){
return this.get("author").get("firstName")+ " " + this.get("author").get("lastName");
}).property("firstName", "lastName")
});


app/views/author.hbs
Written by {{view.fullName}}


app/templates/author.hbs
<h1>{{title}}</h1>
<div>{{body}}</div>
{{view "author"}}


渲染结果为:
<div>
  <h1>Why You Should Use Ember.JS</h1>
  <div>Because it's awesome!</div>
  Written by Yehuda Katz
</div>


比较{{partial}}和{{view}}如下:
我们使用{{partial "author"}} 时,不需要创建author 视图view,直接嵌入给定的模板。
而我们使用{{view "author"}}时,创建了一个新的author 视图,然后将该模板和其关联的view渲染到指定位置。




{{render}}助手类:
它需要两个参数,第一个描述要装配的上下文,第二个是可选的,是model,如果提供了它,它将被传送给该模板对应的controller


{{render}}主要完成如下几个工作:
没有提供model时,它会获取一个对应controller的单例实例。
提供了model时,它会获取对应controller的唯一实例。
使用获取的controller 渲染指定的模板
设置对应controller的model值


app/templates/author.js
Written by {{firstName}} {{lastName}}
Total Posts:{{postCount}}


app/templates/post.hbs
<h1>{{title}}</h1>
<div>{{body}}</div>
{{render "author" author}}


app/controller/author.js
export default Ember.ObjectController.extend({
postCount: function(){
return this.get("model.posts.length");
}.property("model.posts.[]")
});


此例中{{render}}将完成如下内容:
如果视图author类存在,将首先获取一个视图author的实例,否则就会使用默认生成的视图
使用对应的模板,这里是author模板
生成一个单例的AuthorController实例
将其第二个参数author model设置为AuthorController的model属性值,这里author字段在post上。
使用上面创建的上下文,在指定位置渲染模板。


{{render}}不需要显示出匹配的route
{{render}}类似{{outlet}}, 它们俩都是告诉Ember.js为页面的某个部分贡献点什么。
{{outlet}} 路由器router决定路由route并装配相应的controller/view/model
{{render}} 我们自己直接或间接地指定适当的controller/view/model


注意:{{render}} 在同一个route下,在没有指定model的情况下,{{render}}不能被多次调用。


如下对照表:
Helper        Template            Model             View           Controller
{{partial}}    Specified Template    Current Model     Current View   Current Controller
{{view}}    View's Template        Current Model     Specified View   Current Controller
{{render}}    View's Template        Specified Model     Specified View   Specified Controller


具体实例对比:
Helper                     Template            Model           View            Controller
{{partial "author"}}     templates/author.hbs models/post.js   views/post.js controllers/post.js
{{view "author"}}         templates/author.hbs models/post.js   views/author.js controllers/post.js
{{render "author" author}} templates/author.hbs models/author.js   views/author.js controllers/author




编写助手类:
http://guides.emberjs.com/v1.11.0/templates/writing-helpers/
有时候,你可能在应用程序中多次使用同一段HTML代码,这种情况下,你可以将其注册为自定义的助手类,从而在整个应用程序中多次调用它们。


比如:假设你经常将某个值放到<span>标签中,那么我们就可以将其定义为一个类:
app/helpers/highlight.js
export default Ember.Handlebars.makeBoundHelper(function(value, options){
var escaped = Handlebars.Utils.escapeExpression(value);
return new Ember.Handlerbars.SafeString('<span class="highlight">'+ escaped + '</span>');
});
如果你想从助手类中返回HTML,有不想它被安全过滤,那么一定要返回一个new SafeString对象,但在这之前首先必须确保过滤了用户的输入。


之后,我们便可以在我们应用程序的任意Handlerbar模板中调用它了。
{{highlight}}


其渲染结果是:<span class="highlight">Peter</span>


如果当前上下文的name 属性发生了变化,Ember.js会再次自动执行helper来更新DOM。




依赖:
假设你想渲染一个人Person的全名,如果Person发生变化后能够更新输出,或者firstName 或者 lastName属性变化时也能自动更新输出。


app/helpers/full-name.js
export default Ember.Handlebars.makeBoundHelper(function(person){
return person.get('firstName') + ' ' + person.get('lastName');
},'firstName','lastName');


定义完后我们便可以使用该模板:
{{fullName person}}


现在,无论上下文中的person如何变化,或者当其依赖的属性值发生变化,输出都会自动更新。


传入fullName助手类的路径和它的依赖见可能是全限定属性路径,比如 person.address.sountry






自定义视图帮助类:
其实我们经常在多个地方使用{{view}}助手类来渲染视图类,这时候我们也可以注册一个视图助手类来简化一下。
比如,假设我们有一个叫Calendar的视图,我们可以注册它为一个助手类。
import Calendar from 'my-app/views/calendar';
Ember.Handlebars.makeBoundHelper('canledar', Calendar);


这样我们就可以直接在template中使用它:
{{calendr}}


这样写类似于:
{{view "calendar"}}












转载于:https://my.oschina.net/u/924064/blog/423432

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值