Vue3 相比 Vue2 的主要变化(生命周期、状态管理、API风格)

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 一致 beforeCreatecreatedsetup() 替代
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)

核心变化总结:

  1. 组合式 API 引入

    • beforeCreatecreatedsetup() 函数替代。

    • 其他生命周期需通过 onXxx 形式导入并调用(如 onMounted)。

  2. 命名规范化

    • 卸载阶段生命周期名称更准确:beforeDestroyonBeforeUnmountdestroyedonUnmounted

    • 所有组合式 API 生命周期均以 on 开头。

  3. 新增调试钩子

    • onRenderTracked:跟踪虚拟 DOM 重新渲染时的依赖。

    • onRenderTriggered:跟踪触发虚拟 DOM 重新渲染的依赖变化。

  4. Options API 保留但微调

    • 在 Vue 3 的 Options API 中,生命周期名称与 Vue 2 基本相同,仅卸载阶段名称变化(beforeDestroybeforeUnmountdestroyedunmounted)。

使用示例对比:

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) 更简单直观

迁移建议

  1. 新项目 :直接使用 Pinia + Composition API

  2. 现有 Vuex 项目

    • 小型项目:可逐步迁移到 Pinia

    • 大型项目:Vuex 4 仍可正常使用,无强制迁移必要

  3. 状态逻辑复用 :优先使用 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 的情况:

  1. 新手学习:更直观,概念清晰

  2. 小型项目:结构简单,无需复杂状态管理

  3. 传统 Vue 项目:维护现有代码

  4. 需要快速原型:简单组件快速开发


适合组合式 API 的情况:

  1. 大型项目:更好的代码组织和维护

  2. 逻辑复用需求高:多个组件共享相同逻辑

  3. TypeScript 项目:需要更好的类型安全

  4. 复杂组件:单个组件包含多个功能

  5. 团队技术栈较新:成员熟悉现代 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,特别是对于中大型项目。

相关推荐
老华带你飞2 小时前
校务管理|基于springboot 校务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring
JosieBook2 小时前
【部署】Spring Boot + Vue框架项目生产环境部署完整方案
vue.js·spring boot·后端
哆啦A梦15883 小时前
商城后台管理系统 04,商品添加-清空列表
javascript·vue.js·elementui
哆啦A梦15883 小时前
商城后台管理系统 06,类目选择实现
javascript·vue.js·elementui
少年张二狗4 小时前
Vue + Element-UI 图片上传实现拖拽排序功能
前端·vue.js·ui
哆啦A梦15884 小时前
【vue实战】商城后台管理系统 01 项目介绍
前端·javascript·vue.js
一字白首4 小时前
Vue Router 进阶,声明式 / 编程式导航 + 重定向 + 404 + 路由模式
前端·javascript·vue.js
GIS好难学5 小时前
0帧起手《Vue零基础教程》,从前端框架到GIS开发系列课程
前端·vue.js·前端框架
LYFlied5 小时前
Vue Vapor模式与AI时代前端发展的思考:虚拟DOM与框架的未来
前端·vue.js·人工智能·前端框架