3.12 Templates -- Wrting Helpers(编写辅助器)
一、概述
1. Helpers允许你向你的模板添加超出在Ember中开箱即用的额外的功能。辅助器是最有用的,用于将来自模型和组件的原始值转换成更适合于用户的格式。
2. 例如,假设我们有一个Invoice model,它包含一个totalDue属性,它代表那个invoice的总数。由于我们不希望我们的公司由于奇怪的JavaScript舍入误差而倒闭,我们把这个值存为美分,而不是浮点美元值(we store this value in cents instead of a floating point dollar value)。
3. 然而,如果我们向我们的用户显示美元值为"100¢"而不是"$1.00",他们可能会非常困惑。我们可以编写一个辅助器去格式化这些值为合适的人类可读的形式。
4. 让我们创建一个format-currency helper,以一个整数计算每份并且把它格式化为美元。为了使用format-currency helper,在模板中使用花括号来调用它:
Your total is {{format-currency model.totalDue}}.
5. 让我们来实现这个辅助器。辅助器是functions,它携带一个或者两个输入并且返回一个单一的输出,这个输出应该放入进HTML。
6. 为了添加一个新的辅助器,在应用程序的helpers文件夹中创建一个和helper名字相同的文件。你也可以用命令行让Ember为你生成这个文件:
ember generate helper format-currency
这个文件应该用Ember.Helper.helper()封装导出一个function:
import Ember from "ember";
export default Ember.Helper.helper(function(params) {
let value = params[0],
dollars = Math.floor(value / 100),
cents = value % 100,
sign = '$';
if (cents.toString().length === 1) { cents = '0' + cents; }
return `${sign}${dollars}.${cents}`;
});
在这个例子中,这个function接收一个美分的金额作为第一个参数(params[0])。然后我们使用原始的JS把美分数量转换成一个格式化过的字符串,例如"$5.00"。
7. 不管什么时候你在一个模板中使用你的辅助器,Ember将会调用这个function并且把从你的辅助器返回的结果插入到DOM中。
所里,例如,如果我们有一个模板,比如我们传递一个值到format-currency中:
Your total is {{format-currency 250}}.
Ember将用格式化过的amout替换{{}}中的内容:
Your total is $2.50.
不管什么时候你改变传递给一个辅助器的参数,无论它们来自一个model还是一个component,Ember将会使用新的值再次自动调用你的辅助器并且更新DOM。
二、Helper Names
不像组件,辅助器不要求在它们的名字中有一个中划线(-)。
三、Helper Arguments
你可以传递一个或者更多个参数到这个function。在上面的例子中,我们传送的美分金额作为第一个并且是唯一的参数。
为了传送多个参数到一个辅助器,在辅助器的name后添加它们,中间有空格分隔:
{{my-helper "hello" "world"}}
一个这些参数的数组被传递到辅助器的function:
app/helpers/my-helper.js
import Ember from "ember";
export default Ember.Helper.helper(function(params) {
let arg1 = params[0];
let arg2 = params[1];
console.log(arg1); // => "hello"
console.log(arg2); // => "world"
});
你也可以使用JS的写法来简化代码。这个例子等同于上面的例子(注意function签名):
app/helpers/my-helper.js
import Ember from "ember";
export default Ember.Helper.helper(function([arg1, arg2]) {
console.log(arg1); // => "hello"
console.log(arg2); // => "world"
});
四、Named Arguments
1. 常规的参数是有用的,用于传递传递数据到辅助器的functions。然而,因为你传递参数的顺序很重要,通常不要让helpers获得多余一个或两个参数是最好的。
2. 也就是说,有时候你可能希望辅助器的行为是可以开发人员配置的,他们从模板调用它。例如,让我们放弃我们的美国方式并且更新我们的format-currency helper,带有一个可选的配置来决定展示什么货币符号。
3. 辅助器允许你以一个JS对象的形式传递命名的参数,包含参数的名称和一个关联的值。命名参数的顺序不影响功能。
在这个例子中,我们可以为ormat-currency helper传递一个sign参数:
{{format-currency 350 sign="£"}}
我们希望我们的辅助器打印出英镑而不是美元:
£3.50
这个对象包含命名参数,它作为第二个参数被传递到helper的function。把上面例子更新为支持可选的sign选项:
app/helpers/format-currency.js
import Ember from "ember";
export default Ember.Helper.helper(function(params, namedArgs) {
let value = params[0],
dollars = Math.floor(value / 100),
cents = value % 100,
sign = namedArgs.sign === undefined ? '$' : namedArgs.sign;
if (cents.toString().length === 1) { cents = '0' + cents; }
return `${sign}${dollars}.${cents}`;
});
4. 你想传递几个命名的参数就传递几个。它们会添加到namedArgs参数传递到function:
{{my-helper option1="hello" option2="world" option3="goodbye cruel world"}}
app/helpers/my-helper.js
import Ember from "ember";
export default Ember.Helper.helper(function(params, namedArgs) {
console.log(namedArgs.option1); // => "hello"
console.log(namedArgs.option2); // => "world"
console.log(namedArgs.option3); // => "goodbye cruel world"
});
简化代码:
app/helpers/my-helper.js
import Ember from "ember";
export default Ember.Helper.helper(function(params, { option1, option2, option3 }) {
console.log(option1); // => "hello"
console.log(option2); // => "world"
console.log(option3); // => "goodbye cruel world"
});
5. 总之,参数是传递值很好的方式:
{{format-date currentDate}}
Hashes对于配置一个辅助器的行为是非常有用的:
{{print-current-date format="YYYY MM DD"}}
只要你想,你可以有无数多个,只要参数放在第一个:
{{format-date-and-time date time format="YYYY MM DD h:mm" locale="en"}}
- 上例中包含两个参数:
- date
- time
- 两个命名参数:
- format="YYY MM DD h:mm"
- locale="en"
五、Stateful Helpers
1. 默认情况下,helpers是无状态的。输入传入它们,它们在这些输入上采取操作并且返回一个单一的输出。它们没有副作用,并且把保存任何信息由于该函数的随后运行。
2. 在某些情况下,然而,你可能需要编写一个helper和你的应用程序的其他部分进行交互。你可以创建状态化的heplers,可以访问在应用程序中的服务,并且也可以有选择的保存状态。
3. 为了创建一个状态化的辅助器,而不是返回一个简单的function,你应该返回一个Ember.Helper的子类。Helper类必须包含一个compute方法,和传递给Ember.Helper.helper同样的行为。
4. 实际上,我们可以重构上面你的无状态辅助器为一个有状态的辅助器,仅仅通过把这个function变为在类上的compute方法:
app/helpers/format-currency.js
import Ember from "ember";
export default Ember.Helper.extend({
compute(params, hash) {
let value = params[0],
dollars = Math.floor(value / 100),
cents = value % 100,
sign = hash.sign === undefined ? '$' : hash.sign;
if (cents.toString().length === 1) { cents = '0' + cents; }
return `${sign}${dollars}.${cents}`;
}
});
这确实等同于上面的例子。如果它不要求任何状态,对于长类形式你可以认为函数版本是一个简写。
六、Adding Services
状态化的辅助器可以获取应用程序中的服务。为了获取一个服务,你必须首先把它注入这个状态化辅助器。一旦添加了,你可以调用这个服务的方法或者访问它的属性,来自内部的compute()方法。
app/helpers/is-authenticated.js
import Ember from "ember";
export default Ember.Helper.extend({
authentication: Ember.inject.service()
compute() {
let authentication = this.get('authentication');
if (authentication.get('isAuthenticated')) {
return "Welcome back, " + authentication.get('username');
} else {
return "Not logged in";
}
}
});
七、Escaping Html Content
1. 为了保护你的应用程序避免XSS攻击,Ember自定转移从辅助器返回的任何值,这样浏览器不会把它解释为HTML。
2. 例如,这里一个make-bold辅助器,它返回一个包含HTML的字符串:
app/helpers/make-bold.js
import Ember from "ember";
export default Ember.Helper.helper(function(params) {
return `<b>${params[0]}</b>`;
});
你可以这样调用它:
{{make-bold "Hello world"}}
Ember将会转移HTML标签,像这样:
<b>Hello world</b>
3. 这里向用户展示非法的字符串<b>Hello world</b>,而不是你期望的黑体文字。我们可以告诉Ember不要转移返回的值通过使用htmlSafe:
app/helpers/make-bold.js
import Ember from "ember";
export default Ember.Helper.helper(function(params) {
return Ember.String.htmlSafe(`<b>${params[0]}</b>`);
});
如果你返回一个SafeString(一个字符串被htmlSafe封装),Ember知道你已经确认了它的行为,它不包含恶意的HTML。
4. 然而,注意,在上面的例子中我们可能只是无意中把一个XSS漏洞引入到了我们的应用程序中!通过盲目的标记字符串安全,恶意用户可以获取它们自己的HTML到我们引用程序,允许它们做的事情比如获取敏感的客户数据。
例如,假设我们有一个chat app并且使用我们的make-bold helper来欢迎进入频道的新用户:
Welcome back! {{make-bold model.firstName}} has joined the channel.
现在,一个恶意用户仅仅需要设置这个firstName为一个包含HTML标签的字符串(像一个<script>标签,发送客户的隐私数据到它们的服务器),并且聊天室里的每个用户都受到了损害。
5. 通常,如果你想要封装你的内容到HTML中你应该跟喜欢使用组件。然而,如果你真的希望把来自models混合的HTML和values包含进你的helper返回的内容中,确保你转义了任何可能来自一个不受信任的用户的东西,使用escapeExpression :
import Ember from "ember";
export default Ember.Helper.helper(function(params) {
let value = Handlebars.Utils.escapeExpression(params[0]);
return Ember.String.htmlSafe(`<b>${value}</b>`);
});
现在,传递进这个辅助器的值的HTML已经被转义,但是我们希望包裹着值的可信任的<b>标签没有被转义。一个而已用户设置它的firstName为一些包含HTML的内容,HTML会变成这样:
Welcome back! <b><script
type="javascript">alert('pwned!');</script></b> has joined the channel.
3.12 Templates -- Wrting Helpers(编写辅助器)的更多相关文章
- 使用整体模型模板辅助器 Using Whole-Model Templated Helpers 模板辅助器方法 精通ASP.NET MVC 5
怎么会
- mvc4自定义辅助器方法的学习
1.什么是辅助器 它们可以对代码块和标记进行打包,以便能够在mvc框架应用程序中重用.可以理解成编写在页面上的C#代码(方法). 2 .自定义辅助器 创建“基本”的mvc示例,并创建Basic控制器, ...
- 3.9 Templates -- Input Helpers
一.Input Helpers Ember中{{input}}和{{textarea}}是创建常规表单控件最简单的方法. {{input}}包裹内建的Ember.TextField和Ember.Che ...
- 3.10 Templates -- Development Helpers
一.Development Helpers Handlebar和Ember有好多个辅助器可以使模板开发更容易. 这些辅助器输出变量到浏览器的控制台,或者从模板中激活debugger. 二.Loggin ...
- 011_URL和Ajax辅助器方法
创建基本的链接和URL 在我们介绍链接或URL之前先做一些准备,我们这部分要介绍的知识将要使用的项目就是之前建立的HelperMethods项目,现在需要先为其添加一个People控制器,并在其中定义 ...
- MVC:添加Html辅助器
本文的方法来自 <精通asp.net Mvc5>. 一.添加视图模型 为了支持Html辅助器方法,可以把可用页面数,当前面,以及存储库中产品数等信息传递给视图.在Model文件夹内增加一个 ...
- 编写装饰器实现python请求错误重试功能
在做接口自动化测试的时候,总会遇到,因连接超时等错误导致,接口脚本失败. 官方给出的方法: max_retries=5 出错重试5次注意的是,这个只对DNS,连接错误进行重试. from reques ...
- Unity3D Shader官方教程翻译(十九)----Shader语法,编写表面着色器
Writing Surface Shaders Writing shaders that interact with lighting is complex. There are different ...
- 用C++编写发布器和订阅器节点
1.转移到之前教程在catkin工作空间所创建的package路径下: $ roscd package_name/ 例子:$ roscd practice/2.在package路径下创建src目录: ...
随机推荐
- 深入volley(三)自己来写volley
https://github.com/Smalinuxer/android-SpillOver 这是我自己写的一个请求缓存框架,基于volley的,沿袭了volley的架构与设计思想,而对其进一步的封 ...
- swift开发之--UISearchBar的使用/UISearchController的使用
记录下UISearchBar的基本用法,补充:ios 8.0以后,原来的UISearchDisplayController被官方废弃,建议使用UISearchController,下面就简单的记录下这 ...
- hadoop程序MapReduce之MaxTemperature
需求:求每年当中最高的温度 样本:temp.log 2016080623 2016072330 2015030420 输出结果:2016 30 2015 20 MapReduce分析设计: Mappe ...
- storm中的基本概念
Storm是一个流计算框架,处理的数据是实时消息队列中的,所以需要我们写好一个topology逻辑放在那,接收进来的数据来处理,所以是通过移动数据平均分配到机器资源来获得高效率. Storm的优点是全 ...
- 下载SpringJar包
方法一: 地址:http://repo.spring.io/release/org/springframework/spring/ 此方法简单. 方法二: 安装TortoiseSVN后,在电脑的任意空 ...
- 最简单的VS-Qt-CMake项目框架
使用qtcreator新建一个空工程,可以得到main.cpp,mainwindow.cpp,mainwindow.h和mainwindow.ui四个文件 下面主要介绍CMakeLists.txt的内 ...
- Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取
为什么要写这篇文章 1. 因为最近在学习<软件调试>这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了K ...
- Androidの共享登录之方案研究
由于最近公司提到了一个需求是,一个应用登录成功了,另一个自动登录. 绞尽脑汁想了好几天,看起来很容易但是想深点就漏洞百出,有的时候代码都写完了测试都成功了突然发现给一个假设就完全失效. 先前几个同事之 ...
- Android 7.1 SystemUI--Multi-Window多窗口模式
PhoneStatusBar.java private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClic ...
- 百度地图API功能
984aca5bc78b070e59f34e230f11cf6d http://api.map.baidu.com/api?v=2.0&ak=您的密钥" <html> & ...