【问题标题】:How to traverse through every 2 items using _.each() in Underscore.js如何在 Underscore.js 中使用 _.each() 遍历每 2 个项目
【发布时间】:2015-07-31 15:17:59
【问题描述】:

您好,我们的部分代码使用 underscore.js 库:

{{ _.each(items, function(item) { }} 

    <li class="">
        <a class="title" href="{{= item.Id }}"><h2>{{= item.Name}}</h2></a>
        <p>{{= item.ShortDesc}}</p>
    </li>

{{ }); }}

将输出:

<li><a><h2>Element 1</h2></a><p>Description of element 1</p></li>
<li><a><h2>Element 2</h2></a><p>Description of element 2</p></li>
...

但我们想要的是:

<li>
    <a><h2>Element 1</h2></a><p>Description of element 1</p>
    <a><h2>Element 2</h2></a><p>Description of element 2</p>
</li>
<li>
    <a><h2>Element 3</h2></a><p>Description of element 3</p>
    <a><h2>Element 4</h2></a><p>Description of element 4</p>
</li>
...

基本上,使用_.each 每 2 项填写一次&lt;li&gt;

请指教。谢谢

【问题讨论】:

  • 无论如何你有两个&lt;/li&gt;,产生无效的html。
  • 您对第二个 a 和 p 的期望是什么?
  • @MarcB 这是一个错字...我删除了它。
  • @dbarnes 我想要的效果是
  • 基本上每 2 个项目填充
  • ,使用 .each,我不知道是否可能
  • 你不能把它们放在那里吗?这似乎需要 html,所以为什么不能在 li 中添加额外的元素?
  • 标签: javascript jquery foreach underscore.js


    【解决方案1】:

    传递给_.each() 的回调函数将循环索引或对象键作为其第二个参数,因此理论上您可以使用它。也就是说,如果不小心处理,您可能会发现自己在末尾缺少一个结束 &lt;/li&gt; 标记。

    我的建议是使用_.groupBy 组合成两个的连续倍数,然后遍历其中的每一个:

    // In the code which renders the template
    // (because you REALLY don't want this in your template):
    
    var groups = _.groupBy(items, function (item, index) {
        return Math.floor(index / 2);
    });
    
    // In your template:
    
    {{ _.each(groups, function(itemsInGroup) { }} 
        <li class="">
    
        {{ _.each(itemsInGroup, function (item) { }}
            <a class="title" href="{{= item.Id }}"><h2>{{= item.Name}}</h2></a>
            <p>{{= item.ShortDesc}}</p>
        {{ }); }}
    
        </li>
    {{ }); }}
    

    这种方法的优点是您以后可以更改组中的项目数,并且您只需要修改输入模板的 JavaScript 文件 - 无论组大小如何,模板本身都可以工作。

    【讨论】:

    • 这是一个很好的解决方案,但我认为没有必要使用分组元素创建另一个结构来呈现它们,特别是如果它们很多并且假设它们像简单数组一样存储,除非您打算再次使用相同的结构。但是,如果它们已经分组,我会选择这种方法。
    • @Danziger 你说得对,这在某些方面可能有点矫枉过正,但我​​正在回应由要求引入的一类新问题。就个人而言,正确的方法(在我看来)是为每个元素渲染&lt;li&gt;(出于语义的原因——即,假设每个项目的价值相等,它应该是它自己的列表项目)然后根据需要使用 CSS 对对进行分组。
    • 我同意这一点。事实上,我认为改用definition list 可能会更好,但这种方法可能会使样式和事件处理变得比应有的更复杂,而且在不牺牲语义和制作 HTML 标记的情况下很难解决这个问题复杂,因为它反映在这个question 中。所以是的,可能一个无序列表 (&lt;li&gt;) 为我们提供了语义和实用性之间的最佳折衷。
    【解决方案2】:

    _.each 还通过向迭代器函数添加第二个参数为您提供当前迭代的索引,因此您可以这样做:

    {{ _.each(items, function(item, index) { }} 
    
        {{ if(rem = index % 2 == 0) { }} <li class=""> {{ } }}
            <a class="title" href="{{= item.Id }}"><h2>{{= item.Name}}</h2></a>
            <p>{{= item.ShortDesc}}</p>
        {{ if(! rem) { }} </li> {{ } }}
    
    {{ }); }}
    
    // Just in case items has an odd number of elements:
    {{ if(items.length % 2 != 0){ }} </li> {{ } }}
    

    你可以在这个 sn-p 中试试。它使用Array.prototype.forEach(),而不是Underscore.js one,但回调的参数是相同的:(element, index, list)

    let html = '';
    
    items = ['A-1', 'A-2', 'B-1', 'B-2', 'C-1', 'C-2', 'D-1', 'D-2', 'Odd last element.'];
    
    items.forEach((item, index) => { 
      const rem = index % 2;
      
      if(!rem) html += '<li>';
    
      html += `<div>${ item }</div>`;
    
      if(rem) html += '</li>';
    });
    
    if (items.length % 2 != 0) html += '</li>'
    
    document.getElementById('wrapper').innerHTML = html;
    body {
      margin: 8px;
      font-family: monospace;
    }
    
    ul {
      list-style: none;
      padding: 0;
    }
    
    li {
      border: 1px solid black;
      margin: 8px 0 0 0;
    }
    
    div {
      border: 1px solid #CCC;
      margin: 8px;
      padding: 8px;
    }
    &lt;ul id="wrapper"&gt;&lt;/ul&gt;

    【讨论】:

    • 这不适用于奇数长度的列表,我不认为(最终的&lt;/li&gt; 不会生成)。
    • 你说得对,我想元素的数量是偶数。在这种情况下,我已经更新了代码以添加最终的&lt;/li&gt;
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签