Named Arguments
一般的,参数用来做数据传入是比较方便的,但是由于一次传入多个参数时,参数的在helper 函数中接收的顺序并不确定。所以我们需要一种方法来解决这个问题。
那就是说,作为开发者我们需要helper的行为可配置。我们重新审视一下之前创建的format-currencyhelper,我们再次稍微改造一下这个helper,让它带有一个可配置的货币符号。
Helper会将命名参数作为一个JavaScript对象传递到函数里,该对象包含参数的名称以及它的值。 命名参数不受接收的参数位置的影响。
例子: 我们传一个名为sign的参数到format-currency helper中:
{{format-currency350sign="£"}}
上面的助手将会输出英镑:£3.50
命名参数被传入函数的时候是作为第二个参数被接收的。下面的代码就是我们改造后的 helper:
app/helpers/format-currency.js
import{ helper } from'@ember/component/helper';
export functionformatCurrency([value, ...reset], namedArgs) {
letdollars = Math.floor(value /100);
letcents = value %100;
letsign = namedArgs.sign === undefined ?'$': namedArgs.sign;
if(cents.toString( ).length ===1) {
cents ='0'+ cents;
}
return`$$.$`;
}
export defaulthelper(formatCurrency);
你想传多少命名参数都可以,这些参数都在namedArgs 里面:
{{my-helper option1="hello" option2="world"}}
app/helpers/my-helper.js
import{ helper } from'@ember/component/helper';
export functionmyHelper(params, namedArgs) {
console.log(namedArgs.option1); // => "hello"
console.log(namedArgs.option2); // => "world"
}
export defaulthelper(myHelper);
普通参数和命名参数可以同时传入helper。
Class-based Helper
默认的,helper是无状态的。他们接收多个输入,经过一系列操作返回一个输出。它没啥副作用并且它不会保存任何东西。
不过在某些场合,你可能需要helper支持一些交互行为。那么,这时候,你就可以创建基于类的helper了,它可以保存状态和访问service。
相对于之前创建helper的方式,要创建类基的helper,你需要继承Ember.Helper. 并且必须要包含一个名为compute的方法(该方法相当于之前创建helper时定义的函数)。
作为练习,我们来重构一下之前创建的format-currencyhelper使它成为一个类基的helper:
app/helpers/format-currency.js
importHelper from'@ember/component/helper';
export defaultHelper.extend({
compute([value, ...reset], hash) {
letdollars = Math.floor(value /100);
letcents = value %100;
letsign =hash.sign === undefined ?'$':hash.sign;
if(cents.toString( ).length ===1) {
cents ='0'+ cents;
}
return`$$.$`;
}
});
改造完毕,上面的例子与改造之前的 function 版本目前是等价。
下面,我们将为这个helper注入service:
app/helpers/format-currency.js
importHelperfrom'@ember/component/helper';
import{ injectasservice }from'@ember/service';
export defaultHelper.extend({
authentication: service( ),
compute([value, ...reset], hash) {
letauthentication =this.get('authentication');
if(authentication.get('isAuthenticated')) {
return'Welcome back, '+ authentication.get('username');
}else{
returnNot logged in';
}
}
});
Escaping HTML Content
为了抵御跨站脚本攻击(XSS),Ember会把从helper中返回的任何值都转换为安全的字符串。
例子, 现在有个make-boldhelper,它返回的值中带有HTML标签:
app/helpers/make-bold.js
import{ helper }from'@ember/component/helper';
export functionmakeBold([param, ...rest]) {
return`$`;
}
export defaulthelper(makeBold);
我们这么调用它:
{{make-bold "Hello world"}}
Ember的转化结果:
Hello world
结果就是,helper返回的内容被当作字符串原样输出了。不过我们也可以让Ember不转化返回内容:
app/helpers/make-bold.js
import{ helper }from'@ember/component/helper';
import{ htmlSafe }from'@ember/string';
export functionmakeBold([param, ...rest]) {
returnhtmlSafe(`$`);
}
export defaulthelper(makeBold);
如果你返回的是一个SafeString. 那么Ember就知道你已经确保返回值中没有恶意的代码。
但是请注意,在上面的代码中,我们可能会无意中在应用程序中引入了XSS漏洞! 通过盲目地将字符串标记为安全,恶意用户可以将自己的HTML导入我们的应用程序,从而允许他们执行访问敏感的客户数据等操作。
例如,假设我们有一个聊天应用程序,并使用我们的make-bold助手来欢迎新用户:
Welcome! {{make-bold model.firstName}} has joined the channel..
现在,恶意用户只需要将其firstName设置为包含恶意代码的HTML的字符串(例如,客户的隐私数据通过包裹,然后发到server),那么他就可以轻松获得别人的资料了。
为了应对这种行为,Ember提供了 excapeExpression 来防止恶意script注入。
app/helpers/make-bold.js
importEmberfrom'ember';
import{ helper }from'@ember/component/helper';
import{ htmlSafe }from'@ember/string';
export functionmakeBold([param, ...rest]) {
letvalue = Ember.Handlerbars.Utils.excapeExpresstion(params);
returnhtmlSafe(`$`);
}
export defaulthelper(makeBold);
现在,被注入的恶意脚本将不会起作用了。
Welcom back! alert('pwned!');</script; has joined the channel..</p><p><strong>每天学习一点点,日积月累也能变大神!</strong></p>
领取专属 10元无门槛券
私享最新 技术干货