【问题标题】:vue.js insert block for every 6th loop elementvue.js 为每 6 个循环元素插入块
【发布时间】:2019-01-28 19:18:03
【问题描述】:

我通过循环呈现提供卡列表。每个第 3 列(引导程序)元素我添加行 div。现在我需要为每 6 个元素添加另一个 col 元素(横幅块)。渲染类似的东西:

我该如何实现?

我现在的代码

<div class="row" v-for="i in Math.ceil(offers.length / 3)">
    <div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="offer in offers.slice((i-1)*3, i*3)">
        <h2>{{offer.name}}</h2>
        <h2>{{offer.desc}}</h2>
    </div>
</div>

【问题讨论】:

    标签: javascript loops vue.js vue-component


    【解决方案1】:

    for循环:

        <div class="mycol" v-for="(offer,ind) in offers">
          <template v-if="ind % 5 == 0">
           <h2>banner</banner>
          </template>
          <template v-else>
           <h2>{{offer.name}}</h2>
           <h2>{{offer.desc}}</h2>
          </template>
        </div>
    

    对于每三个列的新行,您可以使用 css

    .mycol:nth-child(3n+1){
     clear:left;
    }
    

    【讨论】:

    • 这个很简单,
    【解决方案2】:

    我建议您在视图中少编程,多在视图模型中编程。创建一个computed,将您的数据拆分为一系列优惠和横幅以及行,然后以直接的方式使用计算出来的数据。

    const chunk = (arr, size) =>
      arr
      .reduce((acc, _, i) =>
        (i % size) ?
        acc :
        [...acc, arr.slice(i, i + size)], []);
        
    new Vue({
      el: '#app',
      data: {
        offers: []
      },
      computed: {
        rows() {
          const withBanners = chunk(this.offers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b), []);
    
          return chunk(withBanners, 3);
        }
      },
      mounted() {
        setTimeout(() => {
          this.offers = [{
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          },
          {
            name: 'offer'
          }
        ];
        }, 500);
      }
    });
    #app {
      display: grid;
    }
    
    .row {
      display: grid;
      grid-gap: 2rem;
      grid-template-columns: repeat(3, auto);
      justify-content: left;
    }
    
    .box {
      width: 8rem;
      height: 8rem;
    }
    
    .banner {
      background-color: #f9c;
    }
    
    .offer {
      background-color: #99f;
    }
    <script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
    <div id="app">
      <div class="row" v-for="row in rows">
        <div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="item in row">
          <div v-if="item.type === 'Banner'" class="banner box">
            <h2>{{item.name}}</h2>
          </div>
          <div v-else class="offer box">
            <h2>{{item.name}}</h2>
          </div>
        </div>
      </div>
    </div>

    【讨论】:

    • 但是我正在通过 axios 从服务器获取报价
    • 从哪里得到它并不重要。分配报价时,计算结果将是正确的。
    • 我已更新 sn-p 以在程序启动后分配优惠。
    • 还有一个问题,横幅不能替换(在查询中)第 6 个报价,并且此报价在新行中下拉,我得到 7 列,而不是 6。加上横幅附加到末尾,无论如何列表中有很多优惠
    • 这些都是你可以在计算中处理的事情。让它生成你想要使用的数据。
    【解决方案3】:

    这应该完全符合你的要求。我不得不对数据进行一些操作,因为 Vue 的模板语言不是为处理这种用例的逻辑而设计的

    HTML

    <div id="app">
      <div v-for="items in rows" class="row">
        <div v-for="item in items" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">{{item}}</div>
      </div>
    </div>
    

    脚本

    created () {
        while (this.items.length > 0) {
          const howMany = (this.rows.length % 3 === 0) ? 3 : 2
          const row = this.items.splice(0, howMany)
          if (howMany === 2) row.push('banner')
          this.rows.push(row)
    
        }
    },
    

    https://jsfiddle.net/jamesharrington/k6c0rgL3/17/

    【讨论】:

    • 如果他这样做,第6个就会消失,
    • 但是对于每个 3d 行的行 div 驱动呢?
    • 对不起,第 6 个元素将被横幅替换。这是他想要的吗?
    • @RaphaelParreira 我改变了它,这样就不会发生,但我试图找出每行 3 个问题
    • 好吧,我想我明白了 :)
    【解决方案4】:

    我假设您希望每 6 个元素添加一个横幅,但您希望显示第 6 个。我会在我的数据对象上处理这个,在其中插入横幅。这更容易。你可以用这种方式分割你的数组。

    let firstPart = myData.slice(0,5)
    let lastPart = myData.slice(5,)
    
    let newData = [...firstPart, banner, ...lastPart]
    

    现在,您只需每 6 个元素执行一次。

    【讨论】:

      【解决方案5】:

      如果可能的话,我建议使用 flex。 所以代码看起来像:http://jsfiddle.net/n89dbo37/

      new Vue({
        el: '#app',
        data() {
          return {
              items: _.times(20, i => ({type: 'offer'})),
          };
        },
        computed: {
          itemsWithBanners() {
            let result = [];
            this.items.forEach((item, idx) => {
              if (idx && idx % 5 === 0) {
                  result.push({type: 'banner'});
              }
              result.push(item);
            });
            return result;
          },
        },
      });
      

      【讨论】:

        【解决方案6】:

        感谢大家,我采用 Roy J 解决方案,为我的案例重建并获得结果。我的代码:

        <template>
          <div class="section-space80 results-col" >
            <div class="container" >
              <div class="row">
                  <div class="col-md-12">
                    <div class="wrapper-content bg-white pinside40">
                      <div class="row" v-for="row in rows">
                        <div v-for="offer in row" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">
                          <div class="lender-listing" v-if="offer.type && offer.type === 'Banner'">
                            <div class="lender-head">
                                Banner
                            </div>
                          </div>
                          <div class="lender-listing" v-if="offer.mfoName">
                            <div class="lender-head">
                                <div class="lender-logo">Offer</div>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
              </div>
            </div>
          </div>
        </template>
        
        <script>
          const chunk = (arr, size) =>
          arr
          .reduce((acc, _, i) =>
            (i % size) ?
            acc :
            [...acc, arr.slice(i, i + size)], []);
        
          import axios from 'axios'
          export default {
            data() {
              return {
                showOffers: true,
                loanOffers: [],
                isVisible: false,
                loadMore: true,
                offset: 0,
                rows: ''
        
              }
            },
        
            methods: {
              getOffersList: function () {
                let dataElements = this
                dataElements.loading = true
                axios.get('/api/v1/getUserOffers')
                  .then(function (response) {
                    dataElements.loanOffers = response.data
                    const withBanners = chunk(dataElements.loanOffers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b));
                    dataElements.rows = chunk(withBanners, 3);
                  })
              },
            },
            beforeMount(){
              this.getOffersList()
            }
          }
        
        </script>
        

        【讨论】:

          【解决方案7】:

          我提议使用模板并循环它。 然后在里面检查 v-if="i%6" --> 你的文章 v-else --> yuor ad。

          【讨论】: