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

Vue中v-for内v-if条件渲染偶发卡顿问题排查与优化咨询

问题分析与解决方案

核心问题排查

你的代码存在几个关键问题,导致了后续操作的偶发卡顿:

  1. 图标状态与项状态不匹配:
    展开按钮的图标绑定了全局的 listItemExpanded 变量,但实际切换的是每个 item 自身的 expanded 属性,这会导致图标显示与实际展开状态不一致,同时可能触发不必要的全局重渲染。

  2. 响应性缺失:
    如果 actors 数组中的对象初始没有 expanded 属性,直接通过 item.expanded = !item.expanded 添加属性时,Vue 无法检测到这个新增属性的变化,导致渲染不及时或卡顿。

  3. 低效的列表渲染:
    你在每个分组下遍历所有 actors,再通过 v-if 筛选匹配的项,这种方式会让 Vue 渲染大量不必要的元素,当数据量较大时必然导致性能问题。

  4. 缺少唯一标识(key):
    外层的 <template v-for="item in actors"> 没有设置 :key,Vue 无法精准跟踪每个列表项的状态,会导致频繁的 DOM 复用与重渲染,引发卡顿。


分步修复方案

1. 修正图标状态绑定

将图标切换逻辑改为使用当前项的 expanded 属性:

<v-icon>
  {{ item.expanded ? "mdi-chevron-up" : "mdi-chevron-down" }}
</v-icon>

2. 确保 expanded 属性的响应性

有两种方式解决:

  • 初始化时添加属性:在获取或创建 actors 数组时,为每个对象预添加 expanded: false:
    // 示例:从接口获取数据后处理
    this.actors = fetchedActors.map(actor => ({
      ...actor,
      expanded: false
    }));
    
  • 使用 Vue.set 动态添加:如果无法提前初始化,修改展开方法:
    import Vue from 'vue';
    
    expandListItem(item) {
      Vue.set(item, 'expanded', !item.expanded);
    }
    

3. 预分组优化渲染效率

添加计算属性提前按分组整理演员数据,避免重复遍历:

computed: {
  groupedActors() {
    return this.actors.reduce((result, actor) => {
      const groupKey = actor.relation.toLowerCase();
      if (!result[groupKey]) result[groupKey] = [];
      result[groupKey].push(actor);
      return result;
    }, {});
  }
}

然后修改模板,直接遍历预分组后的对应数据:

<v-list>
  <div v-for="group in groups" :key="group">
    <h4 class="ml-4 my-2">{{ group }}</h4>
    <!-- 直接遍历当前分组的演员,无需额外筛选 -->
    <template v-for="item in groupedActors[group.toLowerCase()] || []" :key="item.id">
      <v-hover v-slot="{ hover }">
        <v-card :elevation="hover ? 6 : 2" class="mx-4 my-2">
          <v-list-item>
            <!-- 保留原有列表项内容 -->
          </v-list-item>
        </v-card>
      </v-hover>
    </template>
  </div>
</v-list>

4. 添加正确的 key 属性

确保所有 v-for 循环都设置唯一的 key(如 item.id),帮助 Vue 高效跟踪元素状态。


替代方案:使用 Vuetify 内置展开面板

如果不需要完全自定义样式,Vuetify 的 v-expansion-panel 组件已经针对展开/收起场景做了性能优化,代码更简洁:

<v-expansion-panels>
  <div v-for="group in groups" :key="group">
    <h4 class="ml-4 my-2">{{ group }}</h4>
    <v-expansion-panel
      v-for="item in groupedActors[group.toLowerCase()] || []"
      :key="item.id"
    >
      <v-expansion-panel-header>
        <v-list-item>
          <v-list-item-content>
            <v-list-item-title>{{ item.name }}</v-list-item-title>
          </v-list-item-content>
          <v-list-item-action>
            <UiDotMenu :actions="listItemActions" :payload="item" @removeActor="removeActor" />
          </v-list-item-action>
        </v-list-item>
      </v-expansion-panel-header>
      <v-expansion-panel-content>
        Show this content
      </v-expansion-panel-content>
    </v-expansion-panel>
  </div>
</v-expansion-panels>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:09:55