zoukankan      html  css  js  c++  java
  • 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标签,像这样:

    &lt;b&gt;Hello world&lt;/b&gt;

    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>&lt;script
    type="javascript"&gt;alert('pwned!');&lt;/script&gt;</b> has joined the channel.
  • 相关阅读:
    Java Output流写入包装问题
    SpringBoot项目单元测试不经过过滤器问题
    SpringSecurity集成启动报 In the composition of all global method configuration, no annotation support was actually activated 异常
    JWT jti和kid属性的说明
    Maven 排除依赖
    第五章 基因概念的发现
    第三章 孟德尔遗传的拓展
    第二章 孟德尔遗传
    第一章 引言
    GWAS全基因组关联分析
  • 原文地址:https://www.cnblogs.com/sunshineground/p/5153472.html
Copyright © 2011-2022 走看看