Vue 2 vs Vue 3 详细知识构图
一、核心架构差异
1. 响应式系统
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 实现方式 | Object.defineProperty() | Proxy |
| 限制 | 不能监测对象属性添加/删除 | 完整拦截对象操作 |
| 数组监听 | 需要特殊处理 | 自动支持 |
| 性能 | 初始化时遍历所有属性 | 懒代理,按需拦截 |
| 深层对象 | 递归定义getter/setter | 仅在访问时代理 |
2. 组件API风格
Vue 2: Options API (选项式)
├─ data()
├─ computed
├─ methods
├─ watch
├─ lifecycle hooks
└─ 代码分散在不同选项中
Vue 3: Composition API (组合式) ✓ 推荐
├─ setup()
├─ ref() / reactive()
├─ computed()
├─ watch()
├─ 生命周期hooks
└─ 代码按功能逻辑组织
二、语法对比速查表
创建应用
Vue 2:
new Vue({
el: '#app',
template: '<App/>',
components: { App }
})
Vue 3:
createApp(App).mount('#app')
数据响应式
Vue 2:
export default {
data() {
return {
count: 0,
user: { name: 'Tom' }
}
}
}
Vue 3 (Composition API):
import { ref, reactive } from 'vue'
export default {
setup() {
const count = ref(0) // 基础类型用ref
const user = reactive({ // 对象用reactive
name: 'Tom'
})
return { count, user }
}
}
计算属性
Vue 2:
computed: {
fullName() {
return this.firstName + this.lastName
}
}
Vue 3:
import { computed } from 'vue'
const fullName = computed(() =>
firstName.value + lastName.value
)
方法
Vue 2:
methods: {
handleClick() {
this.count++
}
}
Vue 3:
const handleClick = () => {
count.value++
}
监听器
Vue 2:
watch: {
count(newVal, oldVal) {
console.log('count changed:', newVal)
},
'user.name': {
handler(newVal) { },
deep: true
}
}
Vue 3:
import { watch } from 'vue'
watch(count, (newVal, oldVal) => {
console.log('count changed:', newVal)
})
watch(() => user.name, (newVal) => { })
// watchEffect (自动追踪依赖)
watchEffect(() => {
console.log(count.value) // 依赖自动收集
})
生命周期钩子
| Vue 2 | Vue 3 |
|---|---|
beforeCreate | 无 (用setup代替) |
created | 无 (用setup代替) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
使用方式:
// Vue 2
export default {
mounted() { }
}
// Vue 3
import { onMounted } from 'vue'
onMounted(() => { })
三、模板语法
v-model
Vue 2 (组件):
// 子组件
props: ['value'],
methods: {
handleChange(val) {
this.$emit('input', val)
}
}
// 父组件
<MyInput v-model="count" />
Vue 3:
// 子组件
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
// 父组件
<MyInput v-model="count" />
// 等同于
<MyInput :modelValue="count" @update:modelValue="count = $event" />
// 多个v-model
<MyInput v-model:title="title" v-model:content="content" />
动态组件
Vue 2:
<component :is="currentComponent" />
Vue 3:
<Suspense>
<component :is="currentComponent" />
<template #fallback>
Loading...
</template>
</Suspense>
Slots (插槽)
Vue 2:
<!-- 父组件 -->
<MyComponent>
<template slot="header">Header</template>
<template slot="default">Content</template>
</MyComponent>
<!-- 子组件 -->
<slot name="header"></slot>
<slot></slot>
Vue 3:
<!-- 父组件 -->
<MyComponent>
<template #header>Header</template>
<template #default>Content</template>
</MyComponent>
<!-- 子组件 -->
<slot name="header"></slot>
<slot></slot>
四、组件通信
Props & Emits
Vue 2:
props: {
count: {
type: Number,
required: true,
default: 0
}
},
methods: {
handleClick() {
this.$emit('update', this.count + 1)
}
}
Vue 3:
const props = defineProps({
count: {
type: Number,
default: 0
}
})
const emit = defineEmits(['update'])
const handleClick = () => {
emit('update', props.count + 1)
}
上下文 Context
Vue 2:
methods: {
handleClick() {
this.$parent.count++
this.$root.globalMethod()
this.$slots
this.$scopedSlots
}
}
Vue 3:
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
// instance.parent
// instance.root
// instance.slots
// instance.emit
五、常用特性对比
Provide / Inject
Vue 2:
// 父组件
provide: {
count: this.count
}
// 子组件
inject: ['count']
Vue 3:
import { provide, inject } from 'vue'
// 父组件
provide('count', ref(0))
// 子组件
const count = inject('count')
自定义指令
Vue 2:
directives: {
focus: {
bind(el) { el.focus() },
update(el) { }
}
}
Vue 3:
const vFocus = {
mounted(el) { el.focus() },
updated(el) { }
}
// 使用
<input v-focus />
混入 Mixins
Vue 2:
const myMixin = {
data() { return { msg: 'hello' } },
methods: { hello() {} }
}
export default {
mixins: [myMixin]
}
Vue 3 (推荐 Composable):
// 可组合函数
export function useMyComposable() {
const msg = ref('hello')
const hello = () => {}
return { msg, hello }
}
export default {
setup() {
const { msg, hello } = useMyComposable()
return { msg, hello }
}
}
六、性能优化
动态导入
Vue 2:
components: {
MyComponent: () => import('./MyComponent.vue')
}
Vue 3:
import { defineAsyncComponent } from 'vue'
const MyComponent = defineAsyncComponent(
() => import('./MyComponent.vue')
)
性能改进
- ⚡ Proxy响应式更快
- ⚡ Tree-shaking支持,包体积更小
- ⚡ 虚拟滚动更优化
- ⚡ 编译器性能提升
七、学习策略
Vue 2 → Vue 3 迁移路线
├─ 第一步:理解Composition API
│ ├─ ref vs reactive
│ ├─ computed vs watch
│ └─ 生命周期钩子
├─ 第二步:掌握新特性
│ ├─ defineProps/defineEmits
│ ├─ defineExpose
│ └─ 脚本语法糖 (<script setup>)
└─ 第三步:重构项目
├─ Mixins → Composables
├─ Options API → Composition API
└─ 迁移状态管理
八、快速记忆要点
| Vue 2 | Vue 3 | 记忆点 |
|---|---|---|
this.data | ref.value | ref需要.value |
computed: {} | computed(fn) | 计算属性变函数 |
watch: {} | watch(dep, fn) | 监听变显式化 |
methods: {} | const fn = () => {} | 方法变常规函数 |
beforeCreate/created | setup() | 声明周期提前 |
$emit('event') | emit('event') | 事件需显式声明 |