Vue开发中如何在同一元素上同时使用v-for与v-if?
同一元素使用
v-for和v-if的正确方案 永远不要将v-for和v-if直接绑定在同一个DOM元素上,两个指令的执行优先级在不同Vue版本中存在差异,同元素使用要么造成无意义的性能损耗,要么直接抛出运行时错误:
- Vue2中
v-for优先级高于v-if,会先遍历全量列表,再对每一项执行判断逻辑,列表量大时性能浪费明显 - Vue3中
v-if优先级高于v-for,如果判断条件依赖v-for遍历的项变量,会直接报「变量未定义」的错误
根据实际业务场景,可以选择以下三种合规实现方式:
场景1:需要过滤循环项(判断逻辑依赖遍历的每一项值)
这也是遍历action做条件判断最常见的场景,优先用计算属性提前过滤数据源,只保留需要渲染的列表项再做循环,性能最优:
<script setup> import { computed } from 'vue' const props = defineProps(['actionList']) // 提前过滤出符合展示条件的action const visibleActions = computed(() => { return props.actionList.filter(action => { // 这里写针对单个action的判断逻辑,比如是否可见、是否有权限等 return action.visible && action.permission }) }) </script> <template> <div class="action-group"> <!-- 只遍历过滤后需要渲染的项,不需要再在元素上写v-if --> <button v-for="action in visibleActions" :key="action.id" @click="action.handler" > {{ action.label }} </button> </div> </template>
场景2:需要控制整个循环列表的显示/隐藏(判断逻辑和遍历项无关)
把v-if绑定到v-for的外层父容器上,判断条件不满足时不会执行循环逻辑:
<template> <!-- v-if放在外层,控制整个操作区的展示 --> <div class="action-group" v-if="showActionGroup"> <button v-for="action in actionList" :key="action.id" @click="action.handler" > {{ action.label }} </button> </div> </template>
如果不想额外增加一层DOM节点,可以用<template>标签作为v-if的挂载容器,渲染时不会生成真实DOM:
<template> <template v-if="showActionGroup"> <div class="action-group"> <button v-for="action in actionList" :key="action.id"> {{ action.label }} </button> </div> </template> </template>
场景3:简单逻辑下的轻量实现
如果只是临时写简单逻辑、不想额外定义计算属性,可以把v-for绑定到<template>标签上,在内部真实渲染的元素上写v-if判断。注意这种写法仍然会遍历全量列表,仅适合列表长度很小的场景:
<template> <div class="action-group"> <template v-for="action in actionList" :key="action.id"> <button v-if="action.visible" @click="action.handler"> {{ action.label }} </button> </template> </div> </template>
内容的提问来源于stack exchange,提问作者Prayush Jain
相关产品推荐
相关产品推荐

