1. v-if和v-for哪个优先级更高?如果同时出现,怎么优化得到更好的性能
源码中找答案:complier/codegen/index.js
测试文件
测试文件
<!DOCTYPE html>
<htm>
<head>
<titl>Vue事件处理</titl>
</head>
<body>
<div id="demo">
<h1>v-for 和 v-if谁的优先级高? 应该如何正确使用避免性能问题?</h1>
<p v-for="child in children" v-if="isFolder">{{child.title}}</p>
</div>
<script src="assets/vue.js"></script>
<script>
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>
</htm>
结果分析
两者同级时,渲染函数如下
(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,再进行判断
两者不同级时
(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)}
})
先判断在执行循环_l
结论
-
v-for的优先级高于v-if, 测试代码如上,需要设置同级和不同级的场景,且源码中在complier/codegen/index.js下有优先级定义 -
如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能 -
要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环。最终提供给模板的就是需要渲染的
2. Vue组件的data为什么必须是个函数而Vue的根实例没有限制?
源码中找答案 函数每次执行都会返回全新data对象实例
测试代码
<!DOCTYPE html>
<htm>
<head>
<titl>Vue事件处理</titl>
</head>
<body>
<div id="demo">
<h1>Vue组件data为什么必须是个函数?</h1>
<comp></comp>
<comp></comp>
<p>{{counter}}</p>
</div>
<script src="assets/vue.js"></script>
<script>
Vue.component('comp', {
template: '<div @click="counter++">{{counter}}</div>',
data: {counter: 0}
})
const app = new Vue({
el:'#demo',
});
console.log(app.$options.render);
</script>
</body>
</htm>
> 程序无法通过vue检测
结论
Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,那么状态更新会影响所有组件,这是不合理的。采用函数形式定义,在initData时会将其作为工厂函数返回全新的data对象,有效规避多实例之间状态污染问题。 而在Vue根实例创建过程中则不存在限制,也是因为根实例只有一个,不需要担心这种情况
源码中会检测data的形式,决定具体的执行方式 合并选项时,会创建实例,只有根实例有实例,可以有效躲过data选项校验;普通选项不存在实例,无法躲过校验的if逻辑
3. vue中key的作用和工作原理
源码中找答案:
src\core\vdom\patch.js - updateChildren()
测试代码
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<head>
<titl>Vue事件处理</titl>
</head>
<body>
<div id="demo">
<p v-for="item in items">{{item}}</p>
</div>
<script src="../../dist/vue.js"></script>
<script>
const app = new Vue({
el: '#demo',
data: {items: ['a', 'b', 'c', 'd', 'e']},
mounted() {
setTimeout(() => {
this.items.splice(2, 0, 'f')
}, 2000);
}
});
</script>
</body>
</html>
图解
使用key
A B C D E
A B F C D E
B C D E
B F C D E
C D E
F C D E
C D
F C D
C
F C
调试分析过程
没有key时,值为undefiend,则两个标签相同,但值不同,vue源码会认为相同
结论
1、key的作用主要是为了高效的更新虚拟DOM, 其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同的元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
2、另外,若不设置key还可能在列表更新时一份一些隐藏bug 3、vue中在使用相同标签名元素的过度切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果
|