You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue修改活动数组前重新渲染Moment.js日期导致闪烁问题求助

问题分析与解决方案

咱们来拆解你遇到的这个日期闪烁问题的核心原因,再给出对应的解决办法:

核心原因

1. Vue异步更新队列的执行顺序

Vue的DOM更新是异步批量执行的。当你通过vm.$set给activity赋值新数组时,Vue并不会立刻替换DOM,而是把这个更新操作加入到异步队列等待处理。但模板里的myFromNow(item.date)作为方法调用,会在当前渲染周期先触发现有DOM元素的日期重新计算(因为Vue会先处理依赖更新),而新数组的DOM替换要等到下一个Tick才完成。这就导致旧列表的日期先刷新,之后才被新列表替换,出现肉眼可见的闪烁。

2. 虚拟DOM的diff逻辑问题

如果你的列表没有设置唯一的key属性,Vue在对比新旧数组时,会默认使用索引作为标识。当新旧数组长度不同时,Vue会先尝试更新现有DOM节点的内容(包括重新计算fromNow),再添加/删除节点匹配新数组。这种部分更新再全量替换的过程,也会造成明显的闪烁。


解决办法

方法一:给列表项设置唯一key(最关键)

确保列表渲染时绑定活动项的唯一标识(比如ID)作为key,让Vue能精准识别新增/删除的元素,避免不必要的旧元素更新:

<div v-for="item in activity" :key="item.id">
  {{ myFromNow(item.date) }}
</div>

方法二:用加载状态控制列表显示

在获取数据的过程中,添加加载状态暂时隐藏旧列表,等新数据完全就绪后再显示,从根源上避免旧内容的刷新:

methods:{ 
  getActivity(){ 
    let vm = this
    vm.isLoading = true // 开启加载状态
    this.$swagger.Activity.Activity_activityAll(
      { filter: JSON.stringify({ order: 'Date DESC', include: [{ relation: 'person', scope: { order: 'DateCreated ASC' } } ] }) }
    )
    .then(function (resp) {
      vm.activity = resp.body['activity']
      vm.isLoading = false // 数据就绪后关闭加载状态
    })
  } 
}

模板中配合v-if控制显示:

<div v-if="!isLoading">
  <div v-for="item in activity" :key="item.id">
    {{ myFromNow(item.date) }}
  </div>
</div>
<div v-else>加载中...</div>

方法三:缓存fromNow计算结果

把日期格式化逻辑提前到数据获取阶段,避免DOM更新时重复计算,减少不必要的渲染开销:

methods:{ 
  getActivity(){ 
    let vm = this
    this.$swagger.Activity.Activity_activityAll(...)
    .then(function (resp) {
      // 提前格式化日期并缓存到每个活动项中
      const newActivities = resp.body['activity'].map(item => ({
        ...item,
        formattedDate: vm.myFromNow(item.date)
      }))
      vm.activity = newActivities
    })
  },
  myFromNow(date) {
    return moment(date).fromNow()
  }
}

模板直接使用缓存好的结果:

{{ item.formattedDate }}

内容的提问来源于stack exchange,提问作者Mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:45:08