Vue3 相比 Vue2 的主要变化:
- 1、生命周期:
- 组合式API用setup()替代beforeCreate/created
- 卸载阶段重命名为onBeforeUnmount/onUnmounted
- 新增调试钩子onRenderTracked/onRenderTriggered
- 2、状态管理:
- 官方推荐从Vuex转向Pinia
- Pinia简化结构,移除mutations,支持直接修改state
- 更好的TypeScript支持
- 3、API风格差异:
- 选项式API按选项类型组织代码
- 组合式API按功能逻辑组织,支持更好的复用
- 组合式API无需this,响应式数据通过ref/reactive创建
- 组合式API提供更完善的TypeScript支持
建议新项目优先采用组合式API+Pinia的组合,能获得更好的开发体验和代码维护性。
表格总结:vue3的生命周期比之前有哪些变化
以下是 Vue 3 与 Vue 2 生命周期的主要变化总结:
| 分类 | Vue 2 生命周期 | Vue 3 生命周期(Composition API) | Vue 3 生命周期(Options API) | 主要变化说明 |
|---|---|---|---|---|
| 创建阶段 | beforeCreate |
使用 setup() 替代(无需显式定义) |
保留,与 Vue 2 一致 | beforeCreate 和 created 被 setup() 替代 |
created |
在 setup() 中执行 |
保留,与 Vue 2 一致 | 组合式 API 中逻辑直接在 setup() 中编写 |
|
| 挂载阶段 | beforeMount |
onBeforeMount |
保留,与 Vue 2 一致 | 命名改为 onBeforeMount(组合式 API) |
mounted |
onMounted |
保留,与 Vue 2 一致 | 命名改为 onMounted(组合式 API) |
|
| 更新阶段 | beforeUpdate |
onBeforeUpdate |
保留,与 Vue 2 一致 | 命名改为 onBeforeUpdate(组合式 API) |
updated |
onUpdated |
保留,与 Vue 2 一致 | 命名改为 onUpdated(组合式 API) |
|
| 卸载阶段 | beforeDestroy |
onBeforeUnmount |
改为 beforeUnmount |
生命周期名称更准确(强调"卸载") |
destroyed |
onUnmounted |
改为 unmounted |
生命周期名称更准确(强调"卸载") | |
| 新增调试钩子 | 无 | onRenderTracked |
无(仅组合式 API) | 用于调试响应式依赖追踪 |
| 无 | onRenderTriggered |
无(仅组合式 API) | 用于调试响应式触发更新 | |
| 错误处理 | errorCaptured |
onErrorCaptured |
保留,与 Vue 2 一致 | 命名改为 onErrorCaptured(组合式 API) |
| 无 | onActivated(KeepAlive) |
保留,与 Vue 2 一致 | 同 Vue 2,用于 <KeepAlive> 缓存组件 |
|
| 无 | onDeactivated(KeepAlive) |
保留,与 Vue 2 一致 | 同 Vue 2,用于 <KeepAlive> 缓存组件 |
|
| 服务端渲染 | serverPrefetch |
onServerPrefetch |
保留,与 Vue 2 一致 | 命名改为 onServerPrefetch(组合式 API) |
核心变化总结:
-
组合式 API 引入
-
beforeCreate和created被setup()函数替代。 -
其他生命周期需通过
onXxx形式导入并调用(如onMounted)。
-
-
命名规范化
-
卸载阶段生命周期名称更准确:
beforeDestroy→onBeforeUnmount,destroyed→onUnmounted。 -
所有组合式 API 生命周期均以
on开头。
-
-
新增调试钩子
-
onRenderTracked:跟踪虚拟 DOM 重新渲染时的依赖。 -
onRenderTriggered:跟踪触发虚拟 DOM 重新渲染的依赖变化。
-
-
Options API 保留但微调
- 在 Vue 3 的 Options API 中,生命周期名称与 Vue 2 基本相同,仅卸载阶段名称变化(
beforeDestroy→beforeUnmount,destroyed→unmounted)。
- 在 Vue 3 的 Options API 中,生命周期名称与 Vue 2 基本相同,仅卸载阶段名称变化(
使用示例对比:
javascript
// Vue 2(Options API)
export default {
mounted() {
console.log('组件已挂载');
},
beforeDestroy() {
console.log('组件即将销毁');
}
};
// Vue 3(Composition API)
import { onMounted, onBeforeUnmount } from 'vue';
export default {
setup() {
onMounted(() => {
console.log('组件已挂载');
});
onBeforeUnmount(() => {
console.log('组件即将卸载');
});
}
};
注意事项:
-
在
setup()中,this不再指向组件实例,所有生命周期函数需通过导入使用。 -
组合式 API 的生命周期函数可多次调用,便于按逻辑组织代码。
总体而言,Vue 3 在保持向后兼容(Options API)的同时,通过组合式 API 提供了更灵活的生命周期管理方式,并优化了命名语义和调试能力。
状态管理的变化
以下是 Vue 3 状态管理的主要变化总结:
核心状态管理对比:Vuex 4 → Pinia
| 特性 | Vuex 4 | Pinia(Vue 3 官方推荐) | 变化说明 |
|---|---|---|---|
| 官方状态 | Vue 2/3 通用,但非 Vue 3 "首选" | Vue 3 官方推荐的状态管理库 | Pinia 成为 Vue 生态的默认状态管理方案 |
| 设计理念 | 基于 Flux 架构,强调严格结构 | 更轻量、更直观,类似 Composition API | 更符合 Vue 3 的组合式 API 设计理念 |
| 核心概念 | State, Getters, Mutations, Actions, Modules | State, Getters, Actions(无 Mutations) | 移除了 mutations,actions 可同步/异步 |
| TypeScript 支持 | 需要额外配置 | 一流的 TypeScript 支持,类型推断完整 | 类型安全大幅提升 |
| 模块化 | 需要嵌套的 modules | 每个 store 都是独立的,通过组合使用 | 扁平化结构,无需命名空间 |
| 使用方式 | 通过 mapState, mapGetters 等辅助函数 |
直接导入 store 或使用 computed |
更直接的访问方式,与 Composition API 集成更好 |
| API 风格 | Options API 风格 | Composition API 风格 | 更接近 Vue 3 的编程模式 |
| 开发体验 | 需要定义 mutation 来修改 state | 可直接修改 state(也支持 actions) | 减少了样板代码,更灵活 |
| 大小 | ~10KB | ~6KB | 体积更小 |
Composition API 带来的状态管理变化
1. 组件内状态管理的变化
javascript
// Vue 2 Options API
export default {
data() {
return {
count: 0,
user: { name: '', age: 0 }
}
},
computed: {
doubleCount() {
return this.count * 2
}
},
methods: {
increment() {
this.count++
}
}
}
// Vue 3 Composition API
import { ref, reactive, computed } from 'vue'
export default {
setup() {
// 响应式状态
const count = ref(0)
const user = reactive({ name: '', age: 0 })
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 方法
const increment = () => {
count.value++
}
return { count, user, doubleCount, increment }
}
}
2. 全局状态管理的演进
javascript
// Vuex 4(Vue 3 兼容,但非首选)
import { createStore } from 'vuex'
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => commit('increment'), 1000)
}
},
modules: {
user: { /* ... */ }
}
})
// Pinia(Vue 3 官方推荐)
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
// 状态
state: () => ({ count: 0 }),
// 计算属性
getters: {
doubleCount: (state) => state.count * 2
},
// 动作(同步/异步均可)
actions: {
increment() {
this.count++ // 直接修改 state,无需 mutation
},
async incrementAsync() {
await new Promise(resolve => setTimeout(resolve, 1000))
this.count++
}
}
})
// 组件中使用
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
counterStore.increment() // 直接调用
新的状态管理模式
1. 组合式函数(Composables)
javascript
// useCounter.js - 可复用的状态逻辑
import { ref, computed } from 'vue'
export function useCounter() {
const count = ref(0)
const double = computed(() => count.value * 2)
const increment = () => count.value++
return { count, double, increment }
}
// 组件中使用
import { useCounter } from './useCounter'
const { count, double, increment } = useCounter()
2. Provide/Inject 的强化
javascript
// Vue 3 提供更灵活的依赖注入
import { provide, inject, ref } from 'vue'
// 父组件
const theme = ref('dark')
provide('theme', theme) // 提供响应式数据
// 子组件
const theme = inject('theme', 'light') // 注入,有默认值
3. 响应式 API 的变化
javascript
// Vue 2 的限制
data() {
return {
user: {
name: 'John',
// 新增属性需要 Vue.set
}
}
}
// Vue 3 更灵活
const user = reactive({ name: 'John' })
user.age = 25 // 直接添加,自动响应式
状态管理的变化总结
| 方面 | Vue 2 | Vue 3 | 优势 |
|---|---|---|---|
| 官方推荐 | Vuex | Pinia | 更简单、更轻量、更好的 TS 支持 |
| 状态定义 | data() 选项 |
ref() / reactive() |
更灵活,可在函数外定义 |
| 状态共享 | Vuex store | Composables / Pinia | 多种选择,更模块化 |
| 类型安全 | 有限支持 | 一流的 TypeScript 支持 | 更好的开发体验 |
| 代码组织 | 按选项组织 | 按功能组织 | 更好的逻辑复用 |
| 响应式系统 | Object.defineProperty | Proxy | 支持数组索引/对象属性直接添加 |
| 异步处理 | Actions(需 mutations) | 直接处理(Pinia Actions) | 更简单直观 |
迁移建议
-
新项目 :直接使用 Pinia + Composition API
-
现有 Vuex 项目:
-
小型项目:可逐步迁移到 Pinia
-
大型项目:Vuex 4 仍可正常使用,无强制迁移必要
-
-
状态逻辑复用 :优先使用 Composables 而非 mixins
选择指南
-
简单共享状态:Provide/Inject 或 Composables
-
中等复杂度:Pinia(推荐)
-
遗留项目:Vuex 4(兼容 Vue 3)
-
需要严格架构:Pinia 已足够,Vuex 仅在需要特定模式时使用
Vue 3 的状态管理更加灵活和模块化,特别是 Pinia 的引入大大简化了全局状态管理,同时 Composition API 使得组件内状态管理更加清晰和可复用。
Vue 组合式 API 与选项式 API 主要区别
核心对比表格
| 方面 | 选项式 API (Options API) | 组合式 API (Composition API) |
|---|---|---|
| 代码组织 | 按选项类型组织(data、methods、computed) | 按功能/逻辑组织 |
| 逻辑复用 | Mixins(存在命名冲突、来源不清晰问题) | 组合式函数(Composables) |
| 响应式 | 通过 data() 返回响应式对象 |
使用 ref()、reactive() 显式创建 |
this 使用 |
大量使用 this 访问数据和方法 |
无 this,直接访问变量和函数 |
| TypeScript 支持 | 需要类型推断,支持有限 | 一流的 TypeScript 支持 |
| 学习曲线 | 更直观,适合新手 | 需要理解响应式原理,有一定门槛 |
详细对比
1. 代码组织结构
javascript
// 📦 选项式 API - 按选项类型组织
export default {
// 数据
data() {
return {
count: 0,
searchQuery: '',
filteredList: []
}
},
// 计算属性
computed: {
doubleCount() {
return this.count * 2
}
},
// 方法
methods: {
increment() {
this.count++
},
search() {
// 搜索逻辑...
}
},
// 生命周期
mounted() {
this.fetchData()
}
}
// 🎯 组合式 API - 按功能/逻辑组织
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
// 计数器功能
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => count.value++
// 搜索功能
const searchQuery = ref('')
const filteredList = ref([])
const search = () => {
// 搜索逻辑...
}
// 生命周期
onMounted(() => {
fetchData()
})
return {
// 计数器相关
count,
doubleCount,
increment,
// 搜索相关
searchQuery,
filteredList,
search
}
}
}
2. 逻辑复用方式
javascript
// 🔄 选项式 API - Mixins(存在问题)
// mixin.js
export default {
data() {
return {
mixinData: 'from mixin'
}
},
methods: {
mixinMethod() {
console.log('mixin method')
}
}
}
// 组件中使用
import myMixin from './mixin.js'
export default {
mixins: [myMixin],
methods: {
// 可能覆盖 mixin 的方法,或与 mixin 命名冲突
myMethod() { /* ... */ }
}
}
// ✅ 组合式 API - Composables
// useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const double = computed(() => count.value * 2)
const increment = () => count.value++
return { count, double, increment }
}
// 组件中使用
import { useCounter } from './useCounter.js'
export default {
setup() {
// 清晰知道功能来源,无命名冲突
const { count, double, increment } = useCounter(10)
const { count: otherCount } = useCounter(5) // 可重命名
return { count, double, increment }
}
}
3. 响应式数据声明
javascript
// 🔄 选项式 API
export default {
data() {
return {
user: {
name: 'John',
age: 25
},
items: []
}
},
methods: {
addItem() {
// Vue 2 中需要使用 Vue.set 或 $set
this.$set(this.user, 'newProp', 'value')
// 或者
this.items[0] = 'new item' // 非响应式!
}
}
}
// ✅ 组合式 API
import { ref, reactive } from 'vue'
export default {
setup() {
const user = reactive({
name: 'John',
age: 25
})
const items = ref([])
const addItem = () => {
// Vue 3 Proxy 支持动态添加属性
user.newProp = 'value' // 响应式!
items.value[0] = 'new item' // 响应式!
}
return { user, items, addItem }
}
}
4. this 的使用差异
javascript
// 🔄 选项式 API - 依赖 this
export default {
data() {
return { count: 0 }
},
computed: {
message() {
return `Count is: ${this.count}`
}
},
methods: {
showCount() {
console.log(this.message)
}
}
}
// ✅ 组合式 API - 无 this
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const message = computed(() => {
return `Count is: ${count.value}` // 直接访问变量
})
const showCount = () => {
console.log(message.value) // 直接访问计算属性
}
return { count, message, showCount }
}
}
5. TypeScript 支持
typescript
// 🔄 选项式 API - 有限的类型推断
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
count: 0, // 类型推断为 number
user: { name: '', age: 0 }
}
},
methods: {
// 需要显式声明参数和返回值类型
updateUser(name: string, age: number): void {
this.user.name = name
this.user.age = age
}
}
})
// ✅ 组合式 API - 优秀的类型支持
import { ref, reactive } from 'vue'
interface User {
name: string
age: number
email?: string
}
export default {
setup() {
// 完整的类型推断
const count = ref(0) // Ref<number>
// 明确的类型定义
const user = reactive<User>({
name: 'John',
age: 25
})
// 函数类型自动推断
const updateUser = (name: string, age: number) => {
user.name = name
user.age = age
}
return { count, user, updateUser }
}
}
6. 组件示例对比
vue
<!-- 📦 选项式 API 组件 -->
<template>
<div>
<p>{{ count }}</p>
<p>{{ message }}</p>
<button @click="increment">增加</button>
<input v-model="searchText" @input="search" />
<ul>
<li v-for="item in filteredItems" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
searchText: '',
items: [],
filteredItems: []
}
},
computed: {
message() {
return `当前计数: ${this.count}`
}
},
methods: {
increment() {
this.count++
},
search() {
this.filteredItems = this.items.filter(item =>
item.name.includes(this.searchText)
)
}
},
mounted() {
this.fetchItems()
},
methods: {
async fetchItems() {
this.items = await api.getItems()
this.filteredItems = this.items
}
}
}
</script>
<!-- 🎯 组合式 API 组件 -->
<template>
<div>
<p>{{ count }}</p>
<p>{{ message }}</p>
<button @click="increment">增加</button>
<input v-model="searchText" @input="search" />
<ul>
<li v-for="item in filteredItems" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
// 计数器功能
const count = ref(0)
const message = computed(() => `当前计数: ${count.value}`)
const increment = () => count.value++
// 搜索功能
const searchText = ref('')
const items = ref([])
const filteredItems = ref([])
const search = () => {
filteredItems.value = items.value.filter(item =>
item.name.includes(searchText.value)
)
}
const fetchItems = async () => {
items.value = await api.getItems()
filteredItems.value = items.value
}
// 生命周期
onMounted(fetchItems)
</script>
选择建议
适合选项式 API 的情况:
-
新手学习:更直观,概念清晰
-
小型项目:结构简单,无需复杂状态管理
-
传统 Vue 项目:维护现有代码
-
需要快速原型:简单组件快速开发
适合组合式 API 的情况:
-
大型项目:更好的代码组织和维护
-
逻辑复用需求高:多个组件共享相同逻辑
-
TypeScript 项目:需要更好的类型安全
-
复杂组件:单个组件包含多个功能
-
团队技术栈较新:成员熟悉现代 JavaScript
实际项目中的混合使用:
javascript
// 可以在同一个项目中混合使用
export default {
// 选项式 API
data() {
return {
legacyData: 'old data'
}
},
// 组合式 API
setup() {
const newData = ref('new data')
return { newData }
},
// 选项式 API 中可以访问 setup 返回的数据
computed: {
combinedData() {
return this.legacyData + ' ' + this.newData
}
}
}
总结
| 决策因素 | 推荐选择 |
|---|---|
| 项目规模小、简单 | 选项式 API |
| 大型、复杂应用 | 组合式 API |
| 需要良好 TypeScript 支持 | 组合式 API |
| 团队成员熟悉函数式编程 | 组合式 API |
| 维护旧项目或团队习惯传统方式 | 选项式 API |
| 新项目、新技术栈 | 组合式 API |
Vue 3 同时支持两种 API 风格,可根据项目需求和团队习惯灵活选择。对于新项目,推荐优先考虑组合式 API,特别是对于中大型项目。