1.Vue3.0设计目标
- 更小
- 更快
- 加强TS支持
- 加强AP设计一致性
- 提高自身可维护性
- 开放更多底层功能
2.如何更快?
- Object.defineProperty->Proxy
- Virtual Dom重构
- 更多编译优化
- slot默认编译函数
- Momomorphic vnode factory
- Compiler-geenerated flags for vnode.children types
Virtual DOM重构
传统Virtual DOM的性能瓶颈
-
数据变更之后,新的Virtual DOM和旧的Virtual DOM进行patch算法比较,并算出二者之间的差异,将差异进行修.但是传统Virtual DOM,进行算法比对时颗粒度是组件,每个组件作为一个颗粒.虽然Vue能够保证触发更新的组件最小化,但是单个组件内部依然需要遍历该组件的整个Virtual DOM树.
-
传统Virtual DOM的性能跟模版大小正相关,跟动态节点的数量无关.模版或者组件有多大,那么在进行数据更新时损耗的性能就有多大,但实际上,这种方式利用率很低.比如发生改变的地方只有message插值的部分,整体结构不变,但是数据更新的时候,比对整个template结构,这样就存在性能损耗.
-
所以在一些组件整个模版内只有少量动态节点的情况下,传统方法遍历存在性能的浪费.
-
JSX和手写的render function是完全动态的,过度的灵活性导致运行时可以用于优化的信息不足.
Vue3.0Virtual DOM
动静结合:每次触发更新不再以组件为单位进行遍历,找到动态变化的部分,更新时只比对可以变化的部分,减少性能损耗.将vdom更新性能由与模版整体大小相关提升为与动态内容的数量相关.
三种类型
最简单的情况
- 节点结构完全不会改变
- 只有一个动态节点
<template>
<div id="content">
<p class="text">A</p>
<p class="text">B</p>
<p class="text">{{ message }}</p> Diff <p> textCintent
<p class="text">C</p>
</div>
</template>
这个时候没有必要比较结构顺序
节点结构变化v-if
- v-if外部: 只有v-if是动态节点
- v-if内部: 只有{{ message }}是动态节点
<template>
<div> - Check <p v-if="ok">
- Diff <span> textContent
<p class="text">A</p>
<p v-if="ok">
<span>B</span>
<span>{{ message }} </span>
</p>
</div>
</template
把模版切分成两部分,各部分相对静态.
节点结构变化v-for
- v-for外部: 只有v-for是动态节点(fragment)
- 每个v-for循环内部:只有{{ item.message}}是动态节点.
<template>
<div> - Diff <p v-for> children
- Diff <span> textContent
- Repeat n times
<p class="text">A</p>
<p v-for="item of list">
<span>B</span>
<span>{{ item.message }}</span>
</p>
</div>
</template>
区块树Block tree
- 将模版基于动态节点指令切割为嵌套的区块
- 每个区块内部的节点结构是固定的
- 每个区块只需要以一个Array追踪自身包含的动态节点
3.Composition API
- 1.逻辑组合和复用
- 2.类型推导:使用TS重构.基于函数的API对类型推导很友好.
- 3.打包尺寸:每个函数都可作为named ES export被单独引入,对tree-shaking很友好;其次所有函数名和setup函数内部的变量都能被压缩,所以能有更好的压缩效率.
vue2.x对逻辑复用方案
- Mixins和HOC都存在模版数据来源不清晰的问题.
- 并且mixin的属性,方法的命名以及HOC的props注入也可能会产生命名空间冲突的问题.
- 最后,由于HOC和Renderless Components都需要额外的组件实例来做逻辑封装,会导致,无谓的性能开销.
setup()函数
i.初始化时机
setup()是在组件实例被创建时,初始化了props之后调用,处于created前.这个时候我们能接收初始props作为参数.
import { Comonent, Vue, Prop } from 'vue-property-decorator';
@Component({
setup(props) {
console.log('setup', props.test)
return {}
}
})
export default class Hooks extends Vue {
@Prop({ default: 'hello' })
test: string
beforeCreate () {
console.log('beforeCreate')
}
created () {
cosnole.log('created')
}
}
// 打印顺序 beforeCreate->setup hello->created
setup()返回一个对象,而这个对象上的属性则会直接暴露给模版渲染上下文.
ii.reactivity api
走的是value增强的路线,它要做的是如何从一个响应式的值中,衍生出普通的值以及view
在setup()内部,Vue则为我们提供了一系列响应式的API,比如ref,它返回一个Ref包装对象,并在view层引用的时候自动展开.
而我们通过计算产生的值,即使不进行类型声明,也能直接拿到其类型进行推导,因为它是依耐Ref进行计算的.
props类型推导
关于Props类型推导,在TS中,必须在createComponent函数来定义组件.
import { createComponent } from '@vue/composition-api';
const MyComponent = createComponent({
props: {
msg: String
},
setup(props) {
props.msg
return {}
}
})
props选项并不是必须的,假如你不需要运行时的props类型检查,你可以直接在TS类型层面进行声明.
import { createComponet } from '@vue/composition-api';
interface Props {
msg: string
}
export default createComponent({
props: ['msg'],
setup(props: Props, { root }) {
const { $createElement: h } = root;
return () => h('div', props.msg)
}
})