做个测试如下 vue2示例
<!DOCTYPE html>
<html>
<head>
<title>Vue事件处理</title>
</head>
<body>
<div id="demo">
<h1>v-for和v-if谁的优先级高?应该如何正确使用避免性能问题?</h1>
<p v-for="child in children" v-if="isFolder">{{child.title}}</p>
<!-- <template v-if="isFolder">
<p v-for="child in children">{{child.title}}</p>
</template> -->
</div>
<script src="../dist/vue2.js"></script>
<script>
// 创建实例 vue2
const app = new Vue({
el: "#demo",
data() {
return {
children: [{ title: "foo" }, { title: "bar" }],
};
},
computed: {
isFolder() {
return this.children && this.children.length > 0;
},
},
});
console.log(app.$options.render);
</script>
</body>
</html>
两者同级时,渲染函数如下:
(function anonymous(
) {
with(this){return _c('div',{attrs:{"id":"demo"}},[_c('h1',[_v("v-for和v-if谁的优先
级高?应该如何正确使用避免性能问题?")]),_v(" "),
_l((children),function(child){return (isFolder)?_c('p',
[_v(_s(child.title))]):_e()})],2)}
})
_l
是对children的循环,判断条件是isFolder
可见他是包含在循环里的所以v-for是比v-if的优先级高,其实缺点也是很明显的放在一起每次循环都要去判断是浪费性能的,我们看看vue2的源码
源码v-for的优先级也是高于v-if的
_l包含了
isFolder
的条件判断
(function anonymous(
) {
with(this){return _c('div',{attrs:{"id":"demo"}},[_c('h1',[_v("v-for和v-if谁的优先
级高?应该如何正确使用避免性能问题?")]),_v(" "),
(isFolder)?_l((children),function(child){return _c('p',
[_v(_s(child.title))])}):_e()],2)}
})
isFolder
条件用template包裹后,条件在前面而循环在后面
同理我们看看vue3的
<!DOCTYPE html>
<html>
<head>
<title>Vue事件处理</title>
</head>
<body>
<div id="demo">
<h1>v-for和v-if谁的优先级高?应该如何正确使用避免性能问题?</h1>
<p v-for="child in children" v-if="isFolder">{{child.title}}</p>
<!-- <template v-if="isFolder">
<p v-for="child in children">{{child.title}}</p>
</template> -->
</div>
<script src="../dist/vue3.js"></script>
<script>
// vue3
const app = Vue.createApp({
template: "",
data() {
return {
children: [{ title: "foo" }, { title: "bar" }],
};
},
computed: {
isFolder() {
return this.children && this.children.length > 0;
},
},
});
app.mount("#demo");
console.log(app._component.render);
</script>
</body>
</html>
两者同级时,渲染函数如下:
(function anonymous(
) {
const _Vue = Vue
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
const _hoisted_1 = /*#__PURE__*/_createElementVNode("h1", null, "v-for和v-if谁的优先级高?应该如何正确使用避免性能问题?", -1 /* HOISTED */)
return function render(_ctx, _cache) {
with (_ctx) {
const { createElementVNode: _createElementVNode, renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, toDisplayString: _toDisplayString, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), _createElementBlock(_Fragment, null, [
_hoisted_1,
isFolder
? (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(children, (child) => {
return (_openBlock(), _createElementBlock("p", null, _toDisplayString(child.title), 1 /* TEXT */))
}), 256 /* UNKEYED_FRAGMENT */))
: _createCommentVNode("v-if", true),
_createCommentVNode(" <template v-if="isFolder">\n <p v-for="child in children">{{child.title}}</p>\n </template> ")
], 64 /* STABLE_FRAGMENT */))
}
}
})
显然这次的渲染函数isFolder
放在了循环前面所以这次的v-if是优先于v-for
结论:
- vue2
- 显然v-for优先于v-if被解析(把你是怎么知道的告诉面试官)
- 如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能
- 要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环
- 如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项
- vue3
- 显然v-if优先于for被解析(把你是怎么知道的告诉面试官)
这里补充下_l
和renderList
关系
从vue3源码找到
renderList
是针对不同类型进行遍历再将其返回
如有大佬的建议,可以点评