首页 > 解决方案 > 模板在 vue.js 中渲染两次

问题描述

在我的组件模板中,我有以下代码:

   <div
        class="program-point-container"
        v-for="p in programPoints"
        :key="p.id"
    >

        <div class="mt-6 mt-sm-3 mt-md-14 mb-3 font-weight-bold font-size-16" v-if="showDate(p.startsAt)">
            {{new Date(p.startsAt) | moment('DD.MM.YYYY')}} // Humboldt Carré
        </div>
</div>

我的 programPoints 数组中有 23 个对象。出于调试原因,我在控制台记录了一个字符串,以查看该函数被调用了 23 * 2 次。

在这种方法中,我将数据推送到数组中。并返回 true 或 false 以显示 div 容器。但是由于它已经在“第一次”渲染时推送并返回。我没有机会展示那个容器。

showDate(datetime) {
        const date = new Date(datetime).toDateString()
        // check if date already been pushed
        if(this.dates.includes(date)) {
            console.log('false')
            return false // date already been pushed
        }
        this.dates.push(date)
        console.log('true')
        return true

    },

标签: vue.jstemplatesnuxt.js

解决方案


扔掉“JQuery 思维”。这不是 Vue 的工作方式。您的模板已经并且将被多次渲染 - 每次它使用的一些反应数据发生变化时......

您无需关心之前渲染的内容以及更新结果以获取新数据状态的操作。这是 Vue 的工作。只需以“我想在屏幕上看到的”样式编写您的模板,其余部分由 Vue 处理...

只需删除与此相关showDate的所有内容 - 不需要。并阅读文档!

更新

在对象数组中,我有一个具有日期时间的属性。而且我只想在日期出现的第一个对象上显示一次日期。其余的忽略它。当出现新日期时,我希望它也显示它,但仅适用于第一个对象,依此类推

我想为对象添加一个额外的键,它是第一个迭代并具有唯一日期的对象。其他的将被忽略,直到另一个带有唯一日期。

Fight Club...ehm Vue 的第一条规则是:在模板渲染期间,切勿修改模板中使用的任何数据。在最好的情况下,您最终会得到不正确的结果(就像您所做的那样)。在最坏的情况下,你最终会出现无限循环......

更好的解决方案是创建表示您想要的替代数据结构,并且由于 Vue计算属性,即使原始数据发生更改,它也会保持最新......

const vm = new Vue({
  el: "#app",
  data() {
    return {
      programPoints: [
        { id: 1, name: 'Program A', startsAt: '2021/04/13' },
        { id: 2, name: 'Program B', startsAt: '2021/04/14' },
        { id: 3, name: 'Program C', startsAt: '2021/04/14' },
        { id: 4, name: 'Program D', startsAt: '2021/04/18' },
        { id: 5, name: 'Program E', startsAt: '2021/04/13' },
        { id: 6, name: 'Program F', startsAt: '2021/04/18' },        
      ]
    }
  },
  computed: {
    programByDays() {
      return this.programPoints.reduce((acc, item) => {
        if(!acc[item.startsAt]) {
          acc[item.startsAt] = []
        }
        acc[item.startsAt].push(item)
        
        return acc
      }, {})
    }
  },
  mounted() {
    setTimeout(() => this.programPoints.push({ id: 7, name: 'Program SPECIAL', startsAt: '2021/04/20' }), 2000)
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <ul>
    <li v-for="(programs, date) in programByDays" :key="date">
      <p> {{ date }} </p>
      <ul>
        <li v-for="program in programs" :key="program.id">
          {{ program.name }}
        </li>
      </ul
    </li>
  </ul>
</div>


推荐阅读