几天来,我开始使用车把,目前正在尝试装饰器。我了解它在保持简单的情况下如何工作:
例如:仅装饰名称:bill gaTes-> Bill GATES先生

然后,我尝试在“每个”循环中使用decorator,以执行与以前完全相同的操作,但使用的是人员列表,而不是一个人列表。问题是:当我在装饰器函数中时,我需要知道我在看哪个元素(来自数组)。

因此,我想在参数中给出“每个”循环的索引(然后,因为我可以访问数据,所以可以检索当前元素)或当前元素。

我尝试使用@index(通常效果很好),但是调试时却未定义。
而且我找不到在装饰器中获取当前元素的方法。

这是代码:

index.html

<!doctype html>
<html>
    <head>
        <title>Test Handlebars Decorators 4</title>
    </head>
    <body>
        <div id = "main"> </div>

        <script id = "rawTemplate" type = "text/x-handlebars-template">

            {{#each this}}
                Decorated: {{formatGenderHelper this}}
                {{* activateFormatter @index}}
                <br />
            {{/each}}

        </script>

        <script type = "text/javascript" src = "js/lib/handlebars.min-latest.js"></script>
        <script type = "text/javascript" src = "js/lib/jquery-2.2.4.min.js"></script>
        <script type = "text/javascript" src = "js/data.js"></script>
        <script type = "text/javascript" src = "js/index.js"></script>
    </body>
</html>


data.js

var data = [{
    "firstname": "Bill",
    "lastname": "Gates",
    "gender": "MALE"
}, {
    "firstname": "Hillary",
    "lastname": "Clinton",
    "gender": "FEMALE"
}];

function formatMale(author) {
    return "M. " + author.firstname + " " + author.lastname.toUpperCase();
}
function formatFemale(author) {
    return "Mme " + author.firstname + " " + author.lastname.toUpperCase();
}

Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) {
    var genderHelper;
    var gender = context.args[0] || context.data.root[0].gender;

    switch(gender) {
        case "MALE":
            genderHelper = formatMale;
            break;
        case "FEMALE":
            genderHelper = formatFemale;
            break;
        default:
            console.log('Gender format not set. Please set before rendering template.');
            genderHelper = function() {};
    }

    container.helpers = {
        formatGenderHelper: genderHelper
    };
});


index.js

// Get the template
var rawTemplate = $('#rawTemplate').html();

// Compile the template
var compiledTemplate = Handlebars.compile(rawTemplate);

// Apply the template on the data
var content = compiledTemplate(data);

// Finally, re-inject the rendered HTML into the DOM
$('#main').html(content);


如果您需要更多信息,请告诉我。

谢谢您的帮助:)

最佳答案

有两个问题使您的示例失败。一个是您的代码中的一个小问题,另一个是装饰器的工作方式,它本质上只是“不在循环中”(除非您正在使用局部函数,请参见此答案的最后一部分)。



首先,您没有告诉装饰者要传递给它的@index。您可以更改装饰器功能,但是由于您在#each块中包含装饰器,因此this是传递给formatGenderHelper的同一装饰器,这意味着我们可以传递装饰器this.gender,该装饰器解析为性别字符串。这意味着模板的编写者确切地知道了他们传递给装饰器的内容,而逻辑并没有试图对模板所告诉的内容进行猜测。

index.html

...
{{#each this}}
    Decorated: {{formatGenderHelper this}}
    {{* activateFormatter this.gender}}
    <br />
{{/each}}
...



  另外,我认为您是基于Ryan Lewis's sitepoint demo的示例。他的代码存在的一个问题/局限性不是立即显而易见的(因为在简单的情况下甚至都不是问题),这是因为他的装饰器覆盖了所有可用的帮助器,除了格式化提供的帮助器之外。为了避免在执行更复杂的操作时避免出现“错误:TypeError:无法读取未定义的属性'调用'”错误,建议在装饰器函数中使用此错误。
  
  data.js

  Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) {
        // leaving out the code here for brevity
        container.helpers = Object.assign({}, container.helpers, {
            formatGenderHelper: genderHelper
        });
    });





第二个问题是在循环中使用装饰器的一般性问题,这仅仅是Handlebars与装饰器一起工作的结果。根据decorators API doc


  装饰器在实例化并传递块程序(程序,道具,容器,上下文,数据,blockParams,深度)时执行。


这意味着(自动)首先实例化该块的模板时,即在需要在该块上运行的任何其他帮助程序或程序之前,它执行装饰器,并且装饰器在执行之前进行所需的修改。创建块的程序(在本例中为#each)。这意味着要使装饰器以不同的方式区分#each的每个迭代,它需要在#each的孙子块中运行,因此它在#each之后但在formatGenderHelper之前执行,但是,如果您要这样做,并根据迭代的上下文在每次迭代中重新定义装饰的帮助程序,那么最好注册一个嵌入了性别格式化逻辑的帮助程序。



但是,这是一种无法回答的问题。因此,为回答您的问题,我发现您可以使车把做您想做的事,但这有点不合时宜。因为诀窍是您需要从#each的子子块渲染带有装饰器的块,所以我们可以部分渲染它。为此,我们可以将其粘贴到另一个文件中并将其注册为部分文件,但这并不是很方便,因此我们有两个更好的选择。 1)我们可以将代码包装在未定义的partial-block中,并让Handlebars在该partial失败时将其呈现为fallback块,或者((slicker选项)2)我们可以使用提供的内置装饰器#*inline定义内联的partial 。


故障转移部分阻止方法

index.html

...
{{#each this}}
   {{#>nothing}}
       Decorated: {{formatGenderHelper this}}
       {{* activateFormatter this.gender}}
       <br />
   {{/nothing}}
{{/each}}
...

#*inline方法

index.html

...
{{#*inline "formattedAuthor"}}
    Decorated: {{formatGenderHelper this}}
    <br />
{{/inline}}
{{#each this}}
   {{#>formattedAuthor}}
       {{* activateFormatter this.gender}}
   {{/formattedAuthor}}
{{/each}}
...



关键是我们使用*activeFormatter装饰器在每次调用部分时动态地重新配置部分。第二个内联示例更清楚地说明了这一点。当然可能还有其他很好的用例,但这是我看到装饰器真正闪耀的地方,即允许我们从我们称为它们的地方动态地重新配置逻辑或局部帮助器。

但是,有一个警告:如果我们的部分使用了仅在从该部分的定义之外调用的装饰器中提供的帮助器(如我们在示例2中的上面所述),则该部分将无法找到该帮助器装饰器未在正确的位置调用。这也是为什么最好使用以上两种方法中的任何一种来提供partial的原因:我们将partial的定义与decorator调用保存在同一文件中,因此我们可以知道helper仅动态提供,而不是全局注册。

09-30 16:28
查看更多