v-if和v-for哪个优先级更高【Vue从源码找答案(一)】
v-if 和 v-for 哪个优先级更高?
来自 eslint-plugin-vue 的两种提醒
当使用v-for
v-if
写在同层的时候,会可能收到来自eslint-plugin-vue
的两种提醒
[vue/no-use-v-if-with-v-for] This 'v-if' should be moved to the wrapper element.eslint-plugin-vue
v-if 应该移动外层元素
[vue/no-use-v-if-with-v-for] The 'list' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.eslint-plugin-vue
v-for 列表内容的判断应该通过 computed 返回 filtered 数组代替,不能混合使用 'v-for' 和 'v-if'
//这种写法是不推荐的
<li v-for="item in list" v-if="item.type==='cat'" :key="item.id">{{item.name}}</li>
写在同层
为什么会有这两种提醒呢,这就跟Vue
对v-for
和v-if
的执行时序有关
先来做个测试
<template>
<div id="app">
<!-- <ul v-if="isRenderList">
<li v-for="item in list" :key="item.id">{{item.name}}</li>
</ul> -->
<ul>
<li v-if="isRenderList" v-for="item in list" :key="item.id">{{item.name}}</li>
</ul>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
isRenderList: true,
list: [
{ id: 1, type: "cat", name: "喵喵1" },
{ id: 2, type: "cat", name: "喵喵2" },
{ id: 3, type: "dog", name: "汪汪1" },
{ id: 4, type: "dog", name: "汪汪2" },
{ id: 5, type: "cat", name: "喵喵1" },
{ id: 6, type: "cat", name: "喵喵1" },
{ id: 7, type: "cat", name: "喵喵1" },
{ id: 8, type: "cat", name: "喵喵1" },
{ id: 9, type: "cat", name: "喵喵1" }
]
};
},
beforeCreate() {
console.log(this.$options.render);
}
};
</script>
template 中的内容最终都会处理成 render 函数
我们来看 beforeCreate 的时候打印的 render 函数长啥样的
两者同级的时候渲染函数如下
// _vm._l 是渲染列表相关的函数
render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c("div", { attrs: { id: "app" } }, [
_c(
"ul",
_vm._l(_vm.list, function(item) {
return _vm.isRenderList
? _c("li", { key: item.id }, [_vm._v(_vm._s(item.name))])
: _vm._e()
}),
0
)
])
}
可见 v-for 和 v-if 同级的时候,v-for 的优先级更高,在渲染函数中的处理先进行 list 的循环渲染,内层再判断是否渲染
两者不同级的时候渲染函数如下:
render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c("div", { attrs: { id: "app" } }, [
_vm.isRenderList
? _c(
"ul",
_vm._l(_vm.list, function(item) {
return _c("li", { key: item.id }, [_vm._v(_vm._s(item.name))])
}),
0
)
: _vm._e()
])
}
而当 v-if 与 v-for 不同级的时候会先进行 _vm.isRenderList 判断再进 _vm._l 渲染
由上面可知
Vue 会解析 v-for 再解析 v-if
两者同时出现的时候,内层每一层都会进行判断,性能欠佳
eslint-plugin-vue 给出优化的提示
在外层进行 v-if 判断,然后在内部进行v-for循环
如果在内层出现条件判断,则可以使用计算属性返回一个筛选过的数组
computed: {
catList() {
return this.list.filter(item => {
return item.type === "cat";
});
}
}
本文使用 mdnice 排版