在 Mustache 中,如何获取当前部分的索引

发布于 2024-10-17 21:09:31 字数 445 浏览 3 评论 0原文

我正在使用 Mustache 并使用数据

{ "names": [ {"name":"John"}, {"name":"Mary"} ] }

我的胡子模板是:

{{#names}}
    {{name}}
{{/names}}

我想要做的是获得数组中当前数字的索引。比如:

{{#names}}
    {{name}} is {{index}}
{{/names}}

并打印出来

John is 1
Mary is 2

可以用 Mustache 得到这个吗?或者使用车把或其他扩展?

I am using Mustache and using the data

{ "names": [ {"name":"John"}, {"name":"Mary"} ] }

My mustache template is:

{{#names}}
    {{name}}
{{/names}}

What I want to be able to do is to get an index of the current number in the array. Something like:

{{#names}}
    {{name}} is {{index}}
{{/names}}

and have it print out

John is 1
Mary is 2

Is it possible to get this with Mustache? or with Handlebars or another extension?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

〗斷ホ乔殘χμё〖 2024-10-24 21:09:31

这就是我在 JavaScript 中的做法:

var idx = 0;

var data = { 
   "names": [ 
       {"name":"John"}, 
       {"name":"Mary"} 
    ],
    "idx": function() {
        return idx++;
    }
};

var html = Mustache.render(template, data);

你的模板:

{{#names}}
    {{name}} is {{idx}}
{{/names}}

This is how I do it in JavaScript:

var idx = 0;

var data = { 
   "names": [ 
       {"name":"John"}, 
       {"name":"Mary"} 
    ],
    "idx": function() {
        return idx++;
    }
};

var html = Mustache.render(template, data);

Your template:

{{#names}}
    {{name}} is {{idx}}
{{/names}}
椒妓 2024-10-24 21:09:31

作为参考,此功能现已内置于 Handlebars 中,并且与 Mustache 兼容。

使用 {{@index}}

{{#names}}
    {{name}} is {{@index}}
{{/names}}

约翰是 0

玛丽是 1

For reference, this functionality is now built in to Handlebars which has compatibility with Mustache.

Use {{@index}}

{{#names}}
    {{name}} is {{@index}}
{{/names}}

John is 0

Mary is 1

忆伤 2024-10-24 21:09:31

在handlebars.js 中,您可以使用辅助函数来完成此操作。 (事实上​​,这里提到的车把的优点之一 http://yehudakatz.com/2010/09 /09/announcing-handlebars-js/ 是你可以使用助手,而不必在调用模板之前重写对象

因此,你可以这样做:

  var nameIndex = 0;
  Handlebars.registerHelper('name_with_index', function() {
    nameIndex++;
    return this.name + " is " + nameIndex;
  })

然后你的模板可以是这样的:

{{#names}}
<li>{{name_with_index}}</li>
{{/names}}

你的数据是。与之前相同,即:

{ "names": [ {"name":"John"}, {"name":"Mary"} ] };

您会得到以下输出:

<li>John is 1</li>
<li>Mary is 2</li>

为了使其真正起作用,每次渲染模板时都需要重置 nameIndex,因此您可以在列表的开头有一个重置助手。代码如下所示:(

  var data = { "names": [ {"name":"John"}, {"name":"Mary"} ] };
  var templateSource = "<ul>{{reset_index}}{{#names}}<li>{{name_with_index}}</li>{{/names}}</ul>";
  var template = Handlebars.compile(templateSource);

  var helpers = function() {
    var nameIndex = 0;
    Handlebars.registerHelper('name_with_index', function() {
      nameIndex++;
      return this.name + " is " + nameIndex;
    });
    Handlebars.registerHelper('reset_index', function() {
      nameIndex = 0;
    })
  }();

  var htmlResult= template(data);
  $('#target').html(htmlResult);

  var htmlResult2= template(data);
  $('#target2').html(htmlResult2);

这可以正确渲染模板两次。)

In handlebars.js you can accomplish this with a helper function. (In fact, one of the advantages mentioned about handlebars here http://yehudakatz.com/2010/09/09/announcing-handlebars-js/ is that you can use helpers instead of having to rewrite the objects before calling the template.

So, you could do this:

  var nameIndex = 0;
  Handlebars.registerHelper('name_with_index', function() {
    nameIndex++;
    return this.name + " is " + nameIndex;
  })

And, then your template can be this:

{{#names}}
<li>{{name_with_index}}</li>
{{/names}}

Your data is the same as before, i.e.:

{ "names": [ {"name":"John"}, {"name":"Mary"} ] };

And you get this output:

<li>John is 1</li>
<li>Mary is 2</li>

To make this really work, nameIndex needs to get reset each time the template is rendered, so to do that you can have a reset helper at the beginning of the list. So full code looks like this:

  var data = { "names": [ {"name":"John"}, {"name":"Mary"} ] };
  var templateSource = "<ul>{{reset_index}}{{#names}}<li>{{name_with_index}}</li>{{/names}}</ul>";
  var template = Handlebars.compile(templateSource);

  var helpers = function() {
    var nameIndex = 0;
    Handlebars.registerHelper('name_with_index', function() {
      nameIndex++;
      return this.name + " is " + nameIndex;
    });
    Handlebars.registerHelper('reset_index', function() {
      nameIndex = 0;
    })
  }();

  var htmlResult= template(data);
  $('#target').html(htmlResult);

  var htmlResult2= template(data);
  $('#target2').html(htmlResult2);

(This can correctly render the template twice.)

贪恋 2024-10-24 21:09:31

您可以在对象列表上运行以下循环。

该方案具有以下优点:

  • 不改变模型数据
  • 索引可多次访问

代码:

for( var i=0; i< the_list.length; i++) {
    the_list[i].idx = (function(in_i){return in_i+1;})(i);
}

说明:

使用函数代替变量名,因此数据没有发生变异。闭包用于返回在循环中创建函数时的“i”值,而不是循环结束时的 i 值。

You can run the following loop on your list of objects.

This solution has the following advantages:

  • Does not change the model data
  • The index can be accessed multiple times

Code:

for( var i=0; i< the_list.length; i++) {
    the_list[i].idx = (function(in_i){return in_i+1;})(i);
}

Explanation:

A function is used instead of a variable name, so the data is not mutated. Closure is used to return the value of 'i' at the time the function is created in the loop instead of the value of i at the end of the loop.

倒数 2024-10-24 21:09:31

对于 Mustache 来说,更好的方法是使用一个使用 indexOf 获取索引的函数:

var data = { 
   names: [ {"name":"John"}, {"name":"Mary"} ],
    index: function() {
        return data.names.indexOf(this);
    }
};

var html = Mustache.render(template, data);

在模板中:

{{#names}}
    {{name}} is {{index}}
{{/names}}

缺点是这个 index 函数对数组进行了硬编码 data.names 为了使其更加动态,我们可以使用另一个函数,如下所示:

var data = { 
   names: [ {"name":"John"}, {"name":"Mary"} ],
    index: function() {
        return function(array, render) {
            return data[array].indexOf(this);
        }
    }
};

var html = Mustache.render(template, data);

在模板中使用:

{{#names}}
    {{name}} is {{#index}}names{{/index}}
{{/names}}

还有一个小缺点是您必须将数组名称传递给本示例中的索引函数名称{{#index}}名称{{/index}}

A better approach for Mustache would be using a function that gets the index using indexOf:

var data = { 
   names: [ {"name":"John"}, {"name":"Mary"} ],
    index: function() {
        return data.names.indexOf(this);
    }
};

var html = Mustache.render(template, data);

In your template:

{{#names}}
    {{name}} is {{index}}
{{/names}}

The drawback is that this index function has the array hard coded data.names to make it a more dynamic, we can use another function like this:

var data = { 
   names: [ {"name":"John"}, {"name":"Mary"} ],
    index: function() {
        return function(array, render) {
            return data[array].indexOf(this);
        }
    }
};

var html = Mustache.render(template, data);

Usage in your template:

{{#names}}
    {{name}} is {{#index}}names{{/index}}
{{/names}}

Also a small drawback is that you have to pass the array name to the index function in this example names, {{#index}}names{{/index}}.

鱼窥荷 2024-10-24 21:09:31

这里的好帮手:

// {{#each_with_index records}}
//  <li class="legend_item{{index}}"><span></span>{{Name}}</li>
// {{/each_with_index}}

Handlebars.registerHelper("each_with_index", function(array, fn) {
    var buffer = "";
    for (var i = 0, j = array.length; i < j; i++) {
        var item = array[i];

        // stick an index property onto the item, starting with 1, may make configurable later
        item.index = i+1;

        // show the inside of the block
        buffer += fn(item);
    }

    // return the finished buffer
    return buffer;

});

来源:https://gist.github.com/1048968

Great helper here:

// {{#each_with_index records}}
//  <li class="legend_item{{index}}"><span></span>{{Name}}</li>
// {{/each_with_index}}

Handlebars.registerHelper("each_with_index", function(array, fn) {
    var buffer = "";
    for (var i = 0, j = array.length; i < j; i++) {
        var item = array[i];

        // stick an index property onto the item, starting with 1, may make configurable later
        item.index = i+1;

        // show the inside of the block
        buffer += fn(item);
    }

    // return the finished buffer
    return buffer;

});

Source: https://gist.github.com/1048968

梦在深巷 2024-10-24 21:09:31

推荐的解决方案


我的建议是添加 index

let data = {
  "names": [
    {"name": "John"}, 
    {"name": "Mary"}
  ]
};

// Add an index manually
data = {
  names: [
    { index: 0, name: "John" },
    { index: 1, name: "Mary" }
  ]
};

// Add an index with a loop
data = data.names.map((name, index) => name.index = index);

// Nested arrays with indices (parentIndex, childIndex)
data = {
  names: [{
    parentIndex: 0,
    name: "John",
    friends: [{
      childIndex: 0,
      name: "Mary"
    }]
  }]
};

建议的 Mustache Index 解决方案存在问题


其他建议的解决方案并不那么干净,如下详述...

@Index< /strong>

Mustache 不支持 @Index

IndexOf

此解决方案运行时间为 O(n^2),因此它没有最佳表现。此外,还必须为每个列表手动创建索引。

const data = {
  list: ['a', 'b', 'c'],
  listIndex: function () {
    return data.list.indexOf(this);
  }
};

Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);

全局变量

这个解决方案运行时间为 O(n),因此这里的性能更好,但也“污染了全局空间”(即向 window 对象添加属性,并且在浏览器窗口关闭之前,垃圾收集器不会释放内存),并且必须为每个列表手动创建索引。

const data = {
  list: ['a', 'b', 'c'],
  listIndex: function () {
    return (++window.listIndex || (window.listIndex = 0));
  }
};

Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);

局部变量

该解决方案运行时间为 O(n),不会“污染全局空间”,并且不需要为每个列表手动创建。然而,该解决方案很复杂,并且不能很好地处理嵌套列表。

const data = {
  listA: ['a', 'b', 'c'],
  index: () => name => (++data[`${name}Index`] || (data[`${name}Index`] = 0))
};

Mustache.render('{{#listA}}{{#index}}listA{{/index}}{{/listA}}', data);

Recommended Solution


My recommendation is to add an index key

let data = {
  "names": [
    {"name": "John"}, 
    {"name": "Mary"}
  ]
};

// Add an index manually
data = {
  names: [
    { index: 0, name: "John" },
    { index: 1, name: "Mary" }
  ]
};

// Add an index with a loop
data = data.names.map((name, index) => name.index = index);

// Nested arrays with indices (parentIndex, childIndex)
data = {
  names: [{
    parentIndex: 0,
    name: "John",
    friends: [{
      childIndex: 0,
      name: "Mary"
    }]
  }]
};

Problems with proposed Mustache Index solutions


Other proposed solutions are not as clean, as detailed below...

@Index

Mustache does not support @Index

IndexOf

This solution runs in O(n^2) time, and therefore it does not have the best performance. Also the index must be manually created for each list.

const data = {
  list: ['a', 'b', 'c'],
  listIndex: function () {
    return data.list.indexOf(this);
  }
};

Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);

Global Variable

This solution runs in O(n) time, so better performance here, but also "pollutes the global space" (i.e. adds properties to the window object, and the memory is not freed by the garbage collector until the browser window closes), and the index must be manually created for each list.

const data = {
  list: ['a', 'b', 'c'],
  listIndex: function () {
    return (++window.listIndex || (window.listIndex = 0));
  }
};

Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);

Local Variable

This solution runs in O(n) time, does not "pollute the global space", and does not need to be manually created for each list. However, the solution is complex and does not work well with nested lists.

const data = {
  listA: ['a', 'b', 'c'],
  index: () => name => (++data[`${name}Index`] || (data[`${name}Index`] = 0))
};

Mustache.render('{{#listA}}{{#index}}listA{{/index}}{{/listA}}', data);
韶华倾负 2024-10-24 21:09:31

如果您可以控制 JSON 字符串的输出,那么请尝试一下。

{ "names": [ {"name":"John", "index":"1"}, {"name":"Mary", "index":"2"} ] }

因此,当您创建 JSON 字符串时,请将索引添加为每个对象的另一个属性。

If you can control the output of the JSON string, then try this out.

{ "names": [ {"name":"John", "index":"1"}, {"name":"Mary", "index":"2"} ] }

So when you make your JSON string, add the index as another property for each object.

拧巴小姐 2024-10-24 21:09:31

只要您不访问多个数组,您就可以将索引存储在助手上,并在上下文发生变化时递增。我正在使用类似于以下内容的东西:

var data = {
    foo: [{a: 'a', 'b': 'a'}, {'a':'b', 'b':'b'}], 
    i: function indexer() {
        indexer.i = indexer.i || 0;
        if (indexer.last !== this && indexer.last) {                                          
            indexer.i++;
        }   
        indexer.last = this;
        return String(indexer.i);
     }   
};

Mustache.render('{{#foo}}{{a}}{{i}}{{b}}{{i}}{{/foo}}', data);

As long as you're not traveling into more than one array you can store the index on the helper and just increment when the context changes. I'm using something similar to the following:

var data = {
    foo: [{a: 'a', 'b': 'a'}, {'a':'b', 'b':'b'}], 
    i: function indexer() {
        indexer.i = indexer.i || 0;
        if (indexer.last !== this && indexer.last) {                                          
            indexer.i++;
        }   
        indexer.last = this;
        return String(indexer.i);
     }   
};

Mustache.render('{{#foo}}{{a}}{{i}}{{b}}{{i}}{{/foo}}', data);
始终不够 2024-10-24 21:09:31

(在节点 4.4.7、mustache 2.2.1 中测试。)

如果您想要一种干净的功能方式来完成此操作,不涉及全局变量或改变对象本身,请使用此函数;

var withIds = function(list, propertyName, firstIndex) {
    firstIndex |= 0;
    return list.map( (item, idx) => {
        var augmented = Object.create(item);
        augmented[propertyName] = idx + firstIndex;
        return augmented;
    })
};

当你组装视图时使用它;

var view = {
    peopleWithIds: withIds(people, 'id', 1) // add 'id' property to all people, starting at index 1
};

这种方法的巧妙之处在于它创建了一组新的“视图模型”对象,使用旧的集合作为原型。您可以像读取 person.firstName 一样读取 person.id。但是,此函数根本不会更改您的人员对象,因此其他代码(可能依赖于不存在的 ID 属性)不会受到影响。

算法是 O(N),非常好而且快。

(Tested in node 4.4.7, moustache 2.2.1.)

If you want a nice clean functional way to do it, that doesn't involve global variables or mutating the objects themselves, use this function;

var withIds = function(list, propertyName, firstIndex) {
    firstIndex |= 0;
    return list.map( (item, idx) => {
        var augmented = Object.create(item);
        augmented[propertyName] = idx + firstIndex;
        return augmented;
    })
};

Use it when you're assembling your view;

var view = {
    peopleWithIds: withIds(people, 'id', 1) // add 'id' property to all people, starting at index 1
};

The neat thing about this approach is that it creates a new set of 'viewmodel' objects, using the old set as prototypes. You can read the person.id just as you would read person.firstName. However, this function doesn't change your people objects at all, so other code (which might have relied on the ID property not being there) will not be affected.

Algorithm is O(N), so nice and fast.

对你而言 2024-10-24 21:09:31

我正在使用预计算函数将“@index”注入数组。

const putIndexInArray = array => {
    let putIndex = (value, index) => {
        value['@index'] = index;

        return value;
    };

    if (!Array.isArray(array)) {
        return array;
    }

    return array.map(putIndex);
};

Mustache.render(template, {
    array: putIndexInArray(['Homer', 'Marge', 'Lisa'])
});

然后像这样使用:

{{#array}}
    {{@index}}
{{/array}}

I'm using a pre calculate function to inject '@index' into array.

const putIndexInArray = array => {
    let putIndex = (value, index) => {
        value['@index'] = index;

        return value;
    };

    if (!Array.isArray(array)) {
        return array;
    }

    return array.map(putIndex);
};

Mustache.render(template, {
    array: putIndexInArray(['Homer', 'Marge', 'Lisa'])
});

and then using like this:

{{#array}}
    {{@index}}
{{/array}}
无所的.畏惧 2024-10-24 21:09:31

我的主要用例是能够在项目上放置“活动”类。我尝试将“equals”帮助器与“index_for_each”帮助器结合起来,但它太复杂了。

相反,我想出了以下基本的“主动”助手。它非常具体,但对于任何菜单/选择列表场景来说都是一个常见的用例:

用法:

  <ul>
    {{{active 2}}}
    {{#each menuItem}}
      <li class="{{{active}}}">{{this}}</li>
    {{/each}}
  </div>

将使第三个菜单项具有“class='active'”。

助手在这里(这是 CoffeeScript 版本):

active = 0
cur = 0
handlebars.registerHelper 'active', (item, context) ->
  if arguments.length == 2
    active = item
    cur = 0
    ''
  else if cur++ == active
    'active'

My major use case for this was the ability to place an 'active' class on items. I messed around with combining an "equals" helper with and "index_for_each" helper, but it was way too complicated.

Instead, I came up with the following basic "active" helper. It's very specific, but is such a common use case for any menu / select list scenario:

Usage:

  <ul>
    {{{active 2}}}
    {{#each menuItem}}
      <li class="{{{active}}}">{{this}}</li>
    {{/each}}
  </div>

Would make the 3rd menu item have a "class='active'".

The helper is here (this is the CoffeeScript version):

active = 0
cur = 0
handlebars.registerHelper 'active', (item, context) ->
  if arguments.length == 2
    active = item
    cur = 0
    ''
  else if cur++ == active
    'active'
如梦初醒的夏天 2024-10-24 21:09:31
<script>var index = 1;</script>
{{#names}}
    {{name}} is <script>document.write(index++);</script>
{{/names}}

这工作得很好。

<script>var index = 1;</script>
{{#names}}
    {{name}} is <script>document.write(index++);</script>
{{/names}}

This works perfectly fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文