此题考查常识,文档中曾有详细说明v2|v3;也是一个很好的实践题目,项目中经常会遇到,能够看出面试者应用能力。
- 先给出结论
- 为什么是这样的
- 它们能放一起吗
- 如果不能,那应该怎样
- 总结
-
在
Vue 2
中,v-for
优先于v-if
被解析;但在Vue 3
中,则完全相反,v-if
的优先级高于v-for
。 -
我曾经做过实验,把它们放在一起,输出的渲染函数中可以看出会先执行循环再判断条件
-
实践中也不应该把它们放一起,因为哪怕我们只渲染列表中一小部分元素,也得在每次重渲染的时候遍历整个列表。
-
通常有两种情况下导致我们这样做:
-
为了过滤列表中的项目 (比如
v-for="user in users" v-if="user.isActive"
)。此时定义一个计算属性 (比如activeUsers
),让其返回过滤后的列表即可。 -
为了避免渲染本应该被隐藏的列表 (比如
v-for="user in users" v-if="shouldShowUsers"
)。此时把v-if
移动至容器元素上 (比如ul
、ol
)即可。
-
-
文档中明确指出永远不要把
v-if
和v-for
同时用在同一个元素上,显然这是一个重要的注意事项。 -
看过源码里面关于代码生成的部分,
在 Vue 2
中做个测试,test.html
两者同级时,渲染函数如下:
ƒ 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)}
}
在 Vue 3
中做个测试,test-v3.html
两者同级时,渲染函数如下:
(function anonymous(
) {
const _Vue = Vue
return function render(_ctx, _cache) {
with (_ctx) {
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, toDisplayString: _toDisplayString, createCommentVNode: _createCommentVNode } = _Vue
return shouldShowUsers
? (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(items, (item) => {
return (_openBlock(), _createElementBlock("div", { key: item.id }, _toDisplayString(item.name), 1 /* TEXT */))
}), 128 /* KEYED_FRAGMENT */))
: _createCommentVNode("v-if", true)
}
}
})
源码中找答案:
Vue 2
:compiler/codegen/index.js
Vue 3
:compiler-core/src/codegen.ts