Vue3.0 六大亮点:
Performance:性能比Vue2.x快 2.2 倍。Tree shaking support:按需编译,体积比Vue2.x更小。Composition API:组合API(类似React Hooks)。Better TypeScript support:更好的TS支持。Custom Renderer API:暴露了自定义渲染API。Fragment,Teleport(Protal),Suspense:更先进的组件。
Vue3.0 是如何变快的。
diff 方法优化:
Vue2.x中虚拟dom是进行全量的对比。Vue3.0新增了静态标记(PatchFlag)。在与上次虚拟节点进行对比时候,只对比带有
patch flag的节点。并且可以通过
flag的信息得知当前节点要对比的具体内容。
hoistStatic 静态提升:
Vue2.x中无论元素是否参与更新,每次都会重新创建。Vue3.0中对于不参与更新的元素,只会被创建一次,之后会在每次渲染的时候被不停的复用。
cacheHandlers 事件侦听器缓存
- 默认情况下
onClick会被视为动态绑定,所以每次都会去追踪它的变化。但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可。
SSR 渲染
当有大量静态内容的时候,这些内容会被当做纯字符串推进一个
buffer里面,即使存在动态的绑定,会通过模板插值嵌入进去。这样比虚拟dom来渲染的快上很多。当静态内容达到一定量级时候,会用
_createStaticVNode方法在客户端生成一个static node,这些静态node,会被直接innerHTML,就不需要创建对象,然后根据对象渲染。
组合API
setup函数是组合API入口函数。
1 | import { ref } from 'vue' |
组合 API 中定义变量或者函数必须 return 暴露给外界;定义方法不必定义到 methods中, 直接在组合 API 中定义即可。
Ref 只能监听简单类型的变化,不建议监听复杂类型(数组/对象等)的变化。
Reactive 可以监听复杂类型的变化。
1 |
|
组合 API 本质:
在 setup 中注册的变量或函数,会自动注册到 vue2.x 中的 data 或 methods 中。
注意点:
执行
setup函数,是在beforeCreate钩子之前完成的。在
setup函数中,无法使用data和methods。在
setup函数中,this指向undefined。setup函数只能是同步的不能是异步的。
Reactive
什么是 Reactive。
Reactive是Vue3.0中提供的实现响应式数据的方法。在
Vue2.0中响应式数据是通过defineProperty实现,在Vue3.0中响应式数据通过ES6的Propxy实现。
Reactive 注意点:
Reactive函数是对象(json或arr)。在创建响应式数据时,传递的不是对象,则无法更新视图。
如果给
Reactive传递其他对象:默认情况下修改对象,界面不会自动更新。
如果想更新,可以通过重新赋值的方式。
1 |
|
Ref
什么是 Ref。
Ref是用来实现响应式数据的方法。由于
Reactive传入一个对象,导致在开发中如果只想让某个变量实现响应式时会比较麻烦,因此Vue3.0提供了Ref方法,实现对简单值的监听。
Ref 本质:
Ref底层的本质还是Reactive。
系统会自动根据给 Ref 传入的值将它转化为 ref(xx) –> reactive({value: xx})
ref 注意点:
在
Vue中使用Ref的值,不用通过value获取。在
JS中使用Ref的值必须通过value获取。
ref 与 reactive 区别
如果在
template中使用Ref类型的数据,Vue会自动帮我们添加.value。如果在
template中使用Reactive类型的数据,Vue不会自动帮我们添加.value。
如何决定是否需要自动添加 .vlue
Vue解析数据之前,会自动判断这个数据是否是Ref类型的;如果是,就自动添加.value,如果不是就不自动添加.value。
如何判断当前的数据是否是 Ref 类型
- 通过当前数据的
__v_ref来判断的。如果有这个私有属性,并且取值为true,就代表是一个Ref类型的数据。
如何自行判断是 Ref,还是 Reactive
- 通过
isRef和isReactive。
1 |
|
递归监听
默认情况下,无论是通过 Ref 还是 Reactive 都是递归监听。
递归监听存在的问题:
- 如果数据量较大时,非常消耗性能。
创建递归监听,如:
1 | <template> |
监听到每一层数据变化, 界面 UI 更新数据。
非递归监听
非递归监听:只能监听第一层, 不能监听其他层;即只有第一层包装成 proxy。
创建非递归监听,使用 shallowReactive 和 shallowRef。
注意点:
如果是通过
shallowReactive创建数据,只要第一层数据变化,就会更新界面UI第二层,第三层等等数据;如果第一层数据不更新,界面UI不会更新。如果是通过
shallowRef创建数据,Vue监听的是.value的变化,并不是第一层数据的变化。如果是通过
shallowRef创建数据,想监听第n层数据,并主动更新UI界面,这时使用triggerRef方法。Vue3.0只提供了triggerRef方法,没有提供triggerReactive方法;因此如果使用triggerReactive类型的数据,无法主动触发更新界面。
1 | <template> |
shallowRef 的本质
shallowRef 底层调用 shallowReactive,即: shallowRef(18) --> shallowReactive({value: 18})。
如果是通过 shallowRef 创建的数据,它监听的是 .value 的变化。因为底层本质上 .value 才是第一层。
1 | import {reactive} from 'vue' |
toRaw
例子:
1 | <template> |
修改名字数据发生改变,UI 没有更新,即不是响应式数据。如果先变成响应式使用 Ref 或者 Reactive。
1 | <template> |
从上述得知,state 与 obj 是引用关系,state 引用了 obj。
如果直接修改 obj,是无法触发界面更新。
只有通过包装之后的对象修改,才会触发界面更新。
从 Reactive 中获取原始数据
1 | <template> |
Ref 或 Reactive 数据类型,每次修改都会被追踪,UI 界面都会被更新,这样非常消耗性能。如果有一些不需要追踪,不需要更新 UI 界面,这时就可以通过 toRaw 方法拿到原始数据,对原始数据进行修改,就不会被追踪,不会更新 UI 界面,性能提高。
从 Ref 中获取原始数据
1 | <template> |
从 Ref 中获取原始数据必须添加 .value,因为 Ref 底层是使用 Reactive。
markRaw
如果原始值永远不想被追踪变化,使用 markRaw。
例子:
1 | <template> |
toRef
和 Ref 一样,都是创建响应式数据。
使用 Ref 打印输出值:
1 | <template> |
结论:
如果使用 Ref 将某一个对象中的属性变成响应式的数据,修改响应式数据是不会影响到原始数据。
如果响应式数据通过 Ref 创建,修改了数据并会触发 UI 界面更新。
相当于 Ref 是复制一份原始值。
使用 roRef 打印输出值:
1 | <template> |
结论:
如果使用 toRef 将某一个对象中的属性变成响应式的数据,修改响应式数据会影响到原始数据。
如果响应式数据通过 toRef 创建,修改了数据并不会触发 UI 界面更新。
toRef 的本质是引用原始值。
应用场景:
- 如果让响应式数据和以前的数据关联起来,并且更新响应式数据之后并不想更新 UI 界面,就可以使用 toRef。
roRefs
如果数据是多个字段,使用 toRef 就必须写多个字段重新赋值:
1 | <template> |
上述可以通过 toRefs 简化,底层逻辑还是通过 toRef 实现。
1 | <template> |
customRef
理解为自定义 Ref。
返回一个 Ref 对象,可以显式的控制以来追踪和触发相应。
1 | <template> |
具体查看 Vue3.0 官方文档API。
Ref 获取元素
在 Vue2.x 中,可以通过给元素添加 ref=’xxx’,然后在代码中通过 refs.xxx 方式获取元素。
在 Vue3.0 中,也可以通过 ref 获取元素,使用写法不同:
1 |
|
readonly家族
- readonly:用于创建一个只读的数据,并且是递归只读。
1 |
|
结论:
- 修改响应式数据,修改后的数据没变化,UI 界面数据没变化。
const 和 readonly区别:
const:赋值保护,不能给变量重新赋值
readonly:属性保护,不能给属性重新赋值
shallowReadonly:用于创建一个第一层只读的数据。
1 |
|
结论:
修改响应式数据,修改后的数据第一层没发生变化,第二层数据发生变化,并且 UI 界面没更新。
isReadonly:用于判断是否是 Readonly。
1 |
|
Vue3响应式数据本质
Vue2.x 是通过 defineProperty 实现响应式数据。
Vue3.0 是通过 Proxy 实现响应式数据。
模拟:
1 |
|
实现 shallowReactive
1 |
|
实现 shallowRef
1 |
|
实现 Reactive
1 |
|
实现 Ref
1 |
|