v-for 和 v-if 能一起使用吗?
结论:v-for 和 v-if 不能一起使用
原因
在 Vue2 中,v-for 的 优先级高于 v-if,而 Vue3 中 v-if 的 优先级高于 v-for。
Vue2 时期,由于 v-for 的 优先级高于 v-if 所以会先执行循环再判断条件。哪怕只有其中的一部分元素需要渲染,也会在重新渲染的时候去遍历整个列表,此时就会造成性能的浪费。
而到了 Vue3 中,v-if 的优先级高于 v-for,当 v-if 执行时,他调用的变量还不存在,就会导致异常。
源码
js
function genNode(node: CodegenNode | symbol | string, context: CodegenContext) {
if (isString(node)) {
context.push(node)
return
}
if (isSymbol(node)) {
context.push(context.helper(node))
return
}
switch (node.type) {
case NodeTypes.ELEMENT:
case NodeTypes.IF:
case NodeTypes.FOR:
__DEV__ &&
assert(
node.codegenNode != null,
`Codegen node is missing for element/if/for node. ` +
`Apply appropriate transforms first.`
)
genNode(node.codegenNode!, context)
break
...
可以看到,在 Vue3 中,生成代码时,v-if 的优先级高于 v-for。
js
export function genElement(el: ASTElement, state: CodegenState): string {
if (el.parent) {
el.pre = el.pre || el.parent.pre
}
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el, state)
} else if (el.once && !el.onceProcessed) {
return genOnce(el, state)
} else if (el.for && !el.forProcessed) {
return genFor(el, state)
} else if (el.if && !el.ifProcessed) {
return genIf(el, state)
} else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
return genChildren(el, state) || 'void 0'
} else if (el.tag === 'slot') {
return genSlot(el, state)
...
Vue2 中,v-for 的优先级高于 v-if。
同时使用
在 Vue3 中,当二者同时使用时,渲染函数如下:
js
ƒ anonymous(
) {
with(this){return _c('div',{attrs:{"id":"app"}},_l((items),function(item){return (item.isActive)?_c('div',{key:item.id},[_v("\n "+_s(item.name)+"\n ")]):_e()}),0)}
}
由于 v-if 的优先级高于 v-for,会先进行 v-if 的判断,也即会先获取 item.isActive,此时并未执行 v-for,所以将会报错。