本文将对Vue2、Vue3中的常见面试题进行详细剖析,部分附带源码
-
v-if和v-for哪个优先级更高?如果两个同时出现,应该怎么优化得到更好的性能?
Vue2
测试代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for、v-if</title>
</head>
<body>
<div id="demo">
<p v-for="list of lists" v-if="list.show">{{list.name}}</p>
<template v-if="lists && lists.length">
<p v-for="list of lists">{{list.name}}</p>
</template>
</div>
<script src="../../dist/vue.js"></script>
<script>
const app = new Vue({
el: '#demo',
data() {
return {
lists: [{
name: 'one',
show: true
}, {
name: 'two',
show: false
}]
};
}
});
console.log(app.$options.render);
</script>
</body>
</html>
两者同级时,渲染函数如下:
ƒ anonymous(
) {
with(this){return _c('div',{attrs:{"id":"demo"}},_l((lists),function(list){return (list.show)?_c('p',[_v(_s(list.name))]):_e()}),0)}
}
_l中包含了条件判断
两者不同级时,渲染函数如下:
ƒ anonymous(
) {
with(this){return _c('div',{attrs:{"id":"demo"}},[(lists && lists.length)?_l((lists),function(list){return _c('p',[_v(_s(list.name))])}):_e()],2)}
}
先判断条件再看是否执行_l
结论:
1、v-for优先于v-if被解析
// compiler/gencode/index.js 61行
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)
} else {}
2、如果同时出现,每次渲染都会先执行循环再判断条件,浪费性能
3、避免同时使用v-for和v-if,如果需要使用,外层进行v-if判断,内部进行v-for循环,或者将需要遍历的数据提前通过计算属性进行过滤
Vue3
测试代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for、v-if</title>
</head>
<body>
<div id="demo">
<div v-for="list of lists" v-if="list.show">
<p>{{list.name}} === {{list.show}}</p>
</div>
</div>
<script src="../dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
const app = createApp({
data() {
return {
lists: [{
name: 'one',
show: true
}, {
name: 'two',
show: false
}]
};
}
}).mount('#demo');
</script>
</body>
</html>
两者同级时,渲染函数如下:
(function anonymous(
) {
const _Vue = Vue
return function render(_ctx, _cache) {
with (_ctx) {
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue
return (list.show)
? (_openBlock(true), _createBlock(_Fragment, { key: 0 }, _renderList(lists, (list) => {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", null, _toDisplayString(list.name) + " === " + _toDisplayString(list.show), 1 /* TEXT */)
]))
}), 256 /* UNKEYED_FRAGMENT */))
: _createCommentVNode("v-if", true)
}
}
})
两者同级时,先判断条件再进行遍历渲染,这样由于对象还不存在,所以同级的时候渲染空白或报错(对象不存在)
两者不同级时,渲染函数如下:
(function anonymous(
) {
const _Vue = Vue
const { createCommentVNode: _createCommentVNode } = _Vue
const _hoisted_1 = { key: 0 }
return function render(_ctx, _cache) {
with (_ctx) {
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(true), _createBlock(_Fragment, null, _renderList(lists, (list) => {
return (_openBlock(), _createBlock("div", null, [
(list.show)
? (_openBlock(), _createBlock("p", _hoisted_1, _toDisplayString(list.name) + " === " + _toDisplayString(list.show), 1 /* TEXT */))
: _createCommentVNode("v-if", true)
]))
}), 256 /* UNKEYED_FRAGMENT */))
}
}
})
两者不同级的时候正常遍历数组,然后进行条件判断渲染
结论
1、Vue3中禁止将v-for和v-if同级,不能正常渲染,弥补了Vue2中可同级的性能问题
2、如果真需要遍历时使用v-if判断,解决方案可参考Vue2
-
vue组件data为什么必须是个函数而Vue的根实例没有此限制?
源码:src/code/instance/state.js initData()
-
vue中key的作用和工作原理
-
怎么理解vue中的diff算法?
-
对vue组件化的理解
-
对vue的设计原则的理解
-
谈谈对MVC、MVP和MVVM的理解
-
vue性能优化方案
-
vue3新特性
-
vuex使用及理解
-
vue中组件之间的通信方式
-
vue-router中如何保护指定路由的安全?
-
nextTick实现原理及作用
-
vue响应式原理