vue3新特性理论——纸上谈兵
几天前you大大发布消息说vue3已经处在cr阶段了,也就是说,新加的功能已经确定,接下来就是查改bug了。前不久公司人员分享了一些关于vue3相关的知识,刚好我也对vue3很感兴趣并且之前就进行了了解,所以在这里记录一下。这篇文章主要以理论为主,代码实践请移步:首先来说说you大大最为自豪的改进:Composition APIyou大大说以前在2点几的版本中我们使用mixin来混入公用方法或者其
几天前you大大发布消息说vue3已经处在cr阶段了,也就是说,新加的功能已经确定,接下来就是查改bug了。
前不久公司人员分享了一些关于vue3相关的知识,刚好我也对vue3很感兴趣并且之前就进行了了解,所以在这里记录一下。
这篇文章主要以理论为主,代码实践请移步:vue3新特性实践——南征北战
首先来说说you大大最为自豪的改进:Composition API
you大大说以前在2点几的版本中我们使用mixin来混入公用方法或者其它内容,这样做混入的对象来源不明,相同功能代码陈列杂乱,修改起来上翻下翻,对开发者造成困扰。
而使用Composition API,来源明确、相同功能的代码块在一起,修改的时候只需要专注一个地方,更易于维护。
以前我们在代码里都是使用this来访问属性,比如this.foo()
this.obj
this.$watch
,这样vue对外暴露的东西太多,引入第三方组件安全问题无法保障,造成困扰。vue3之后我们将不再使用this,api以模块的方式引入,函数的方式使用。
接下来我们一起来看一下Composition API的实现,我们把源码fork下来,发现vue3的代码结构变了好多有木有!它的文件入口呢?它的核心代码呢?
原来全都在packages里面了,一个代码部分在一个文件夹里面。公共部分在compiler-core、ssr编译相关在compiler-ssr、与dom编译相关的在compiler-dom…
我们先去找ref
这个API,顺藤摸瓜,在reactivity文件夹下的ref.ts
里。不要被一堆的重载函数迷惑眼睛,我们直接看实现它的函数:
function createRef(rawValue: unknown, shallow = false) {
if (isRef(rawValue)) {
return rawValue
}
let value = shallow ? rawValue : convert(rawValue)
const r = {
__v_isRef: true,
get value() {
track(r, TrackOpTypes.GET, 'value')
return value
},
set value(newVal) {
if (hasChanged(toRaw(newVal), rawValue)) {
rawValue = newVal
value = shallow ? newVal : convert(newVal)
trigger(
r,
TriggerOpTypes.SET,
'value',
__DEV__ ? { newValue: newVal } : void 0
)
}
}
}
return r
}
createRef返回一个__v_isRef属性为true并进行get、set操作的对象,分别调了track
trigger
方法。
track方法收集依赖,
export function track(target: object, type: TrackOpTypes, key: unknown) {
if (!shouldTrack || activeEffect === undefined) {
return
}
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
if (!dep.has(activeEffect)) {
dep.add(activeEffect)
activeEffect.deps.push(dep)
if (__DEV__ && activeEffect.options.onTrack) {
activeEffect.options.onTrack({
effect: activeEffect,
target,
type,
key
})
}
}
}
trigger方法根据映射关系执行对应cb。
然后我们来看toRefs
,toRefs循环每个对象属性,Proxy会对每个属性读写操作拦截。
export function toRefs<T extends object>(object: T): ToRefs<T> {
if (__DEV__ && !isProxy(object)) {
console.warn(`toRefs() expects a reactive object but received a plain one.`)
}
const ret: any = {}
for (const key in object) {
ret[key] = toRef(object, key)
}
return ret
}
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K
): Ref<T[K]> {
return {
__v_isRef: true,
get value(): any {
return object[key]
},
set value(newVal) {
object[key] = newVal
}
} as any
}
因为vue3使用Proxy拦截对象,所以不需要像以前那样使用Object.definepropty挨个定义对象了,Object.definepropty去定义的缺点就是每次创建组件实例的时候开销比较大。
Fragment
以前我们在template中根节点只能有一个元素标签,vue3以后将支持多个同级标签共存。
<tempalate>
<div>haha</div>
<div>hehe</div>
</tempalte>
组件递归操作相比之前会减少很多无用代码,这样一来,我们做一些无尽列表就可以优化很多。
内部做的性能优化
-
Tree shaking 没有用的代码不打包
-
内部模块可以直接拿出来单独引用(按需引入)
-
之前vdom是不管动态静态节点全部一股脑diff。vue3做了静态分析。
-
Ssr编译策略改变,能静态化的就静态字符串化(静态代码部分直接字符串拼接)重写了渲染器
-
之前使用this访问属性,而暴露在this上的属性是用object.definepropty去定义,所以每次创建组建实例的时候开销比较大。vie3直接用proxy拦截。
-
渲染的时候最大化利用node异步状态。精准处理了服务器异步并发问题。
动静比越大优势越大
在vue3中,我们可能不能像往常一样写ts装饰器,ts 装饰器对vue3代码可能会有影响。
更多推荐
所有评论(0)