
Object.defineProperty 拦截对象属性读取/设置,数组通过原型方法劫持;无法直接监听新增/删除属性,需 Vue.set/ Vue.deleteProxy 拦截对象/数组/Map/Set 等结构,配合 track/trigger 精细依赖收集与更新// Vue2 思路(简化):
function defineReactive(obj, key) {
let val = obj[key]
Object.defineProperty(obj, key, {
get() { /* 依赖收集 */ return val },
set(nv) { if (nv !== val) { val = nv; /* 派发更新 */ } }
})
}
// Vue3 思路(简化):
const reactive = (target) => new Proxy(target, {
get(t, k, r) { /* track(t,k) */ return Reflect.get(t, k, r) },
set(t, k, v, r) { const ok = Reflect.set(t, k, v, r); /* trigger(t,k) */ return ok }
})reactive(对象代理)、ref(值容器)、computed(派生)、watch/watchEffect(副作用)、shallowRef/shallowReactive、markRaw/toRawVue.set,可直接新增属性并触发更新ref 在模板自动解包,脚本需 .value细节对比:
beforeCreate/created/mounted/updated/destroyed 等setup 为入口,onMounted/onUpdated/onUnmounted 等组合式钩子Vue2 → Vue3 对照:
- beforeCreate/created → setup(初始化)
- beforeMount/mounted → onBeforeMount/onMounted
- beforeUpdate/updated → onBeforeUpdate/onUpdated
- beforeDestroy/destroyed → onBeforeUnmount/onUnmounted
- activated/deactivated → onActivated/onDeactivated(KeepAlive)new Vue({ el, render }),Vue3 使用 createApp(App).mount('#app')指令钩子映射:
bind → beforeMount
inserted → mounted
update → updated
componentUpdated → updated(或结合 onUpdated)
unbind → unmountedv-model 语法糖=value+inputmodelValue + update:modelValue,支持多 v-model:propVue.use/ Vue.mixin/ Vue.componentapp.use/ app.mixin/ app.componentslots,无需 slot-scopebind→beforeMount、inserted→mounted)多模型 v-model 示例:
<Child v-model:visible="show" v-model:title="title" />// 子组件
const props = defineProps<{ visible: boolean; title: string }>()
const emit = defineEmits<{ (e:'update:visible', v:boolean):void; (e:'update:title', v:string):void }>()@vue/compat(迁移构建)在 Vue3 上运行 Vue2 代码,观察兼容警告并逐项修复Vue.set/delete,直接修改对象属性即可响应reactive,基础类型用 refcreated 初始化逻辑迁入 setup;副作用统一收敛到 onMounted/onUnmounted 与 watch兼容构建使用:
// vue.config.js 或构建配置中启用 @vue/compat
module.exports = { configureWebpack: { resolve: { alias: { 'vue': '@vue/compat' } } } }在运行时观察兼容警告,逐项替换到 Vue3 API。
Vue2:
export default {
data() { return { count: 0 } },
computed: { double() { return this.count * 2 } },
created() { this.init() },
methods: { init() {}, inc() { this.count++ } }
}Vue3:
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
const double = computed(() => count.value * 2)
const inc = () => { count.value++ }
onMounted(() => init())
function init() {}
return { count, double, inc }
}
}过滤器迁移示例: Vue2:
<span>{{ price | currency }}</span>Vue3:
<script setup>
const currency = (n:number) => new Intl.NumberFormat('zh-CN', { style:'currency', currency:'CNY' }).format(n)
</script>
<span>{{ currency(price) }}</span>Mixin → Composable: Vue2 Mixin:
export const userMixin = { created(){ this.fetchUser() }, methods:{ fetchUser(){ /*...*/ } } }Vue3 Composable:
import { ref, onMounted } from 'vue'
export function useUser(){ const user = ref(null); onMounted(async()=>{ user.value = await fetchUser() }); return { user } }unplugin-auto-import/unplugin-vue-components 按需引入Vuex → Pinia 映射:
state → state()
getters → getters
mutations/actions → actions(无需区分)
modules → 多 store + 组合式复用v-once/v-memo:降低重复绑定成本编译优化说明:
微基准建议:
app.xxx,插件通过 app.useemits 显式声明事件,校验参数v-model 改造为 modelValue/update:modelValue,必要时支持多 v-model:proponMounted)Router 迁移提示:
beforeRouteEnter)迁移为 v4 组合式 onBeforeRouteUpdate 或全局守卫;动态路由改用 useRoute/useRoutersetup 访问 this(无实例):用返回对象或 getCurrentInstanceref,对象用 reactive;避免对 reactive 顶层整体替换toRef;需要深度时再加 { deep: true }modelValue 与 update:modelValue 协议Object.defineProperty 拦截对象属性读取/设置,数组通过原型方法劫持;无法直接监听新增/删除属性,需 Vue.set/ Vue.deleteProxy 拦截对象/数组/Map/Set 等结构,配合 track/trigger 精细依赖收集与更新// Vue2 思路(简化):
function defineReactive(obj, key) {
let val = obj[key]
Object.defineProperty(obj, key, {
get() { /* 依赖收集 */ return val },
set(nv) { if (nv !== val) { val = nv; /* 派发更新 */ } }
})
}
// Vue3 思路(简化):
const reactive = (target) => new Proxy(target, {
get(t, k, r) { /* track(t,k) */ return Reflect.get(t, k, r) },
set(t, k, v, r) { const ok = Reflect.set(t, k, v, r); /* trigger(t,k) */ return ok }
})reactive(对象代理)、ref(值容器)、computed(派生)、watch/watchEffect(副作用)、shallowRef/shallowReactive、markRaw/toRawVue.set,可直接新增属性并触发更新ref 在模板自动解包,脚本需 .value细节对比:
beforeCreate/created/mounted/updated/destroyed 等setup 为入口,onMounted/onUpdated/onUnmounted 等组合式钩子Vue2 → Vue3 对照:
- beforeCreate/created → setup(初始化)
- beforeMount/mounted → onBeforeMount/onMounted
- beforeUpdate/updated → onBeforeUpdate/onUpdated
- beforeDestroy/destroyed → onBeforeUnmount/onUnmounted
- activated/deactivated → onActivated/onDeactivated(KeepAlive)new Vue({ el, render }),Vue3 使用 createApp(App).mount('#app')指令钩子映射:
bind → beforeMount
inserted → mounted
update → updated
componentUpdated → updated(或结合 onUpdated)
unbind → unmountedv-model 语法糖=value+inputmodelValue + update:modelValue,支持多 v-model:propVue.use/ Vue.mixin/ Vue.componentapp.use/ app.mixin/ app.componentslots,无需 slot-scopebind→beforeMount、inserted→mounted)多模型 v-model 示例:
<Child v-model:visible="show" v-model:title="title" />// 子组件
const props = defineProps<{ visible: boolean; title: string }>()
const emit = defineEmits<{ (e:'update:visible', v:boolean):void; (e:'update:title', v:string):void }>()@vue/compat(迁移构建)在 Vue3 上运行 Vue2 代码,观察兼容警告并逐项修复Vue.set/delete,直接修改对象属性即可响应reactive,基础类型用 refcreated 初始化逻辑迁入 setup;副作用统一收敛到 onMounted/onUnmounted 与 watch兼容构建使用:
// vue.config.js 或构建配置中启用 @vue/compat
module.exports = { configureWebpack: { resolve: { alias: { 'vue': '@vue/compat' } } } }在运行时观察兼容警告,逐项替换到 Vue3 API。
Vue2:
export default {
data() { return { count: 0 } },
computed: { double() { return this.count * 2 } },
created() { this.init() },
methods: { init() {}, inc() { this.count++ } }
}Vue3:
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
const double = computed(() => count.value * 2)
const inc = () => { count.value++ }
onMounted(() => init())
function init() {}
return { count, double, inc }
}
}过滤器迁移示例: Vue2:
<span>{{ price | currency }}</span>Vue3:
<script setup>
const currency = (n:number) => new Intl.NumberFormat('zh-CN', { style:'currency', currency:'CNY' }).format(n)
</script>
<span>{{ currency(price) }}</span>Mixin → Composable: Vue2 Mixin:
export const userMixin = { created(){ this.fetchUser() }, methods:{ fetchUser(){ /*...*/ } } }Vue3 Composable:
import { ref, onMounted } from 'vue'
export function useUser(){ const user = ref(null); onMounted(async()=>{ user.value = await fetchUser() }); return { user } }unplugin-auto-import/unplugin-vue-components 按需引入Vuex → Pinia 映射:
state → state()
getters → getters
mutations/actions → actions(无需区分)
modules → 多 store + 组合式复用v-once/v-memo:降低重复绑定成本编译优化说明:
微基准建议:
app.xxx,插件通过 app.useemits 显式声明事件,校验参数v-model 改造为 modelValue/update:modelValue,必要时支持多 v-model:proponMounted)Router 迁移提示:
beforeRouteEnter)迁移为 v4 组合式 onBeforeRouteUpdate 或全局守卫;动态路由改用 useRoute/useRoutersetup 访问 this(无实例):用返回对象或 getCurrentInstanceref,对象用 reactive;避免对 reactive 顶层整体替换toRef;需要深度时再加 { deep: true }modelValue 与 update:modelValue 协议Object.defineProperty 拦截对象属性读取/设置,数组通过原型方法劫持;无法直接监听新增/删除属性,需 Vue.set/ Vue.deleteProxy 拦截对象/数组/Map/Set 等结构,配合 track/trigger 精细依赖收集与更新// Vue2 思路(简化):
function defineReactive(obj, key) {
let val = obj[key]
Object.defineProperty(obj, key, {
get() { /* 依赖收集 */ return val },
set(nv) { if (nv !== val) { val = nv; /* 派发更新 */ } }
})
}
// Vue3 思路(简化):
const reactive = (target) => new Proxy(target, {
get(t, k, r) { /* track(t,k) */ return Reflect.get(t, k, r) },
set(t, k, v, r) { const ok = Reflect.set(t, k, v, r); /* trigger(t,k) */ return ok }
})reactive(对象代理)、ref(值容器)、computed(派生)、watch/watchEffect(副作用)、shallowRef/shallowReactive、markRaw/toRawVue.set,可直接新增属性并触发更新ref 在模板自动解包,脚本需 .value细节对比:
beforeCreate/created/mounted/updated/destroyed 等setup 为入口,onMounted/onUpdated/onUnmounted 等组合式钩子Vue2 → Vue3 对照:
- beforeCreate/created → setup(初始化)
- beforeMount/mounted → onBeforeMount/onMounted
- beforeUpdate/updated → onBeforeUpdate/onUpdated
- beforeDestroy/destroyed → onBeforeUnmount/onUnmounted
- activated/deactivated → onActivated/onDeactivated(KeepAlive)new Vue({ el, render }),Vue3 使用 createApp(App).mount('#app')指令钩子映射:
bind → beforeMount
inserted → mounted
update → updated
componentUpdated → updated(或结合 onUpdated)
unbind → unmountedv-model 语法糖=value+inputmodelValue + update:modelValue,支持多 v-model:propVue.use/ Vue.mixin/ Vue.componentapp.use/ app.mixin/ app.componentslots,无需 slot-scopebind→beforeMount、inserted→mounted)多模型 v-model 示例:
<Child v-model:visible="show" v-model:title="title" />// 子组件
const props = defineProps<{ visible: boolean; title: string }>()
const emit = defineEmits<{ (e:'update:visible', v:boolean):void; (e:'update:title', v:string):void }>()@vue/compat(迁移构建)在 Vue3 上运行 Vue2 代码,观察兼容警告并逐项修复Vue.set/delete,直接修改对象属性即可响应reactive,基础类型用 refcreated 初始化逻辑迁入 setup;副作用统一收敛到 onMounted/onUnmounted 与 watch兼容构建使用:
// vue.config.js 或构建配置中启用 @vue/compat
module.exports = { configureWebpack: { resolve: { alias: { 'vue': '@vue/compat' } } } }在运行时观察兼容警告,逐项替换到 Vue3 API。
Vue2:
export default {
data() { return { count: 0 } },
computed: { double() { return this.count * 2 } },
created() { this.init() },
methods: { init() {}, inc() { this.count++ } }
}Vue3:
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
const double = computed(() => count.value * 2)
const inc = () => { count.value++ }
onMounted(() => init())
function init() {}
return { count, double, inc }
}
}过滤器迁移示例: Vue2:
<span>{{ price | currency }}</span>Vue3:
<script setup>
const currency = (n:number) => new Intl.NumberFormat('zh-CN', { style:'currency', currency:'CNY' }).format(n)
</script>
<span>{{ currency(price) }}</span>Mixin → Composable: Vue2 Mixin:
export const userMixin = { created(){ this.fetchUser() }, methods:{ fetchUser(){ /*...*/ } } }Vue3 Composable:
import { ref, onMounted } from 'vue'
export function useUser(){ const user = ref(null); onMounted(async()=>{ user.value = await fetchUser() }); return { user } }unplugin-auto-import/unplugin-vue-components 按需引入Vuex → Pinia 映射:
state → state()
getters → getters
mutations/actions → actions(无需区分)
modules → 多 store + 组合式复用v-once/v-memo:降低重复绑定成本编译优化说明:
微基准建议:
app.xxx,插件通过 app.useemits 显式声明事件,校验参数v-model 改造为 modelValue/update:modelValue,必要时支持多 v-model:proponMounted)Router 迁移提示:
beforeRouteEnter)迁移为 v4 组合式 onBeforeRouteUpdate 或全局守卫;动态路由改用 useRoute/useRoutersetup 访问 this(无实例):用返回对象或 getCurrentInstanceref,对象用 reactive;避免对 reactive 顶层整体替换toRef;需要深度时再加 { deep: true }modelValue 与 update:modelValue 协议