更新方向
1. 框架核心
Vue2 是响应式原理基于 Object.defineProperty 方法重定义对象的 getter
与 setter,vue3 则基于 Proxy 代理对象,拦截对象属性的访问与赋值过程。差异在于,前者并不能对诸如数组长度变化、增删元素操作、对象新增属性进行感知,在 vue 层面不得不重写一些数组方法(push、pop、unshift、shift 等),动态添加响应式属性,也要使用 $set方法等。
而 Proxy 则完美地从根上解决了这些问题,不过对于不支持 Proxy 对象的浏览器(如IE),如果要使用 vue3 依然要进行降级兼容
1. Object.defineProperty
// 假设我们在 data 函数中返回的数据为 initData
const initData = { value: 1 };
// 基于 initData 创建响应式对象 data
const data = {};
Object.keys(initData).forEach(key => {
Object.defineProperty(data, key, {
get() {
// 此处依赖收集
console.log('访问了', key);
return initData[key];
},
set(v) {
// 此处执行回调更新
console.log('访问了', key);
initData[key] = v;
}
});
});
// 从这里可以看出,initData 动态添加的属性,并不能被观测到,这也是 Vue.$set 存在的原因。
2. Proxy
const initData = { value: 1 };
const proxy = new Proxy(initData, {
get(target, key) {
// 此处依赖收集
console.log('访问了', key);
return target[key];
},
set(target, key, value) {
// 此处执行回调更新
console.log('修改了', key);
return Reflect.set(target, key, value);
}
});
// Proxy 可以观测到动态添加的属性
vue3 新特性
1.异步组件需要使用 defineAsyncComponent 创建
全局注册
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComp.vue')
)
app.component('async-component', AsyncComp)
局部声明
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComp.vue')
)
...
export default {
components: { 'async-comp': AsyncComp }
}
1.自定义指令更新
自定义指令的钩子
// vue2
bind - 指令绑定到元素后发生。只发生一次。
inserted - 元素插入父 DOM 后发生。
update - 当元素更新,但子元素尚未更新时,将调用此钩子。
componentUpdated - 一旦组件和子级被更新,就会调用这个钩子。
unbind - 一旦指令被移除,就会调用这个钩子。也只调用一次。.
// vue3
bind → beforeMount
inserted → mounted
beforeUpdate:新的!这是在元素本身更新之前调用的,很像组件生命周期钩子。
update → 移除!有太多的相似之处要更新,所以这是多余的,请改用 updated。
componentUpdated → updated
beforeUnmount:新的!与组件生命周期钩子类似,它将在卸载元素之前调用。
unbind -> unmounted
2.函数式组件
// vue2 Functional.vue
<template>
<div>{{ msg }} </div>
</template>
<script>
export default {
functional: true,
props: ['msg']
}
</script>
// vue3 Functional.js
import { h } from 'vue'
export default function Functional(props, context) {
return h('div',context.attrs,props.msg)
}
Functional.props = ['msg']
3.组合 API–setup 函数
组件创建前执行的初始化函数,默认参数包含 props 和 context。context 可以理解为
组件实例挂载之前的上下文(虽然这么理解,但不是实例本身,这点要清楚),所以实例上
的 attrs,slots,emit 可以在 context 上访问到
基于 setup 方法的生命周期钩子对应更新
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeUnmount -> onBeforeUnmount
unmounted -> onUnmounted
errorCaptured -> onErrorCaptured // 错误上报钩子,仅做了解
renderTracked -> onRenderTracked // { key, target, type } 仅做了解
renderTriggered -> onRenderTriggered // { key, target, type
4.跨组件传递数据
// 常规组件中
provide() {
return {
state: this.state,
constant: '常量'
}
}
// setup 方法中
import { provide, readonly, inject } from 'vue'
provide(key, reactiveValue)
// 禁止子组件对 reactiveValue 进行修改的话
provide(key, readonly(reactiveValue))
// 子组件使用数据
{
inject: [key],
}
// 或使用组合 API
inject('state');
简化:单文件组件 < script setup>
defineProps,defineEmits 直接在< script setup>中使用,无须导入。
useSlots 和 useAttrs 是 真 实 的 运 行 时 函 数 , 它 会 返 回与 setupContext.slots 和 setupContext.attrs 等价的值,同样也能在普通的组合式 API中使用
// 在<script setup>内部的顶层变量,均能直接用于模板部分,
// 省略了 setup 函数及其返回值
<template>
<span @click="increment">{{count}}</span>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => {
count.value++
}
</script>

本文对比了Vue2和Vue3的响应式原理,Vue2基于Object.defineProperty,Vue3则采用Proxy实现更全面的响应式。Vue3引入了异步组件、自定义指令更新的新钩子、函数式组件的改进以及setup函数和组合API。同时,展示了如何在Vue3中处理跨组件数据传递的简化方式。
224

被折叠的 条评论
为什么被折叠?



