Vue 3 深度解析:Composition API、Pinia状态管理与路由守卫实战
一、Vue 3带来的革命性变化
Vue 3自2020年发布以来,已经成为现代前端开发的首选框架之一。相较于Vue 2,Vue 3在性能、开发体验和可维护性方面都有显著提升。本文将重点介绍Vue 3最核心的三大特性:Composition API、Pinia状态管理和Vue Router路由守卫,通过实战示例带你掌握这些技术的精髓。
Vue 3的主要改进
-
性能提升:重写了虚拟DOM,更新速度提升1.3-2倍
-
Tree-shaking支持:打包体积减少41%
-
Composition API:更好的逻辑组织和代码复用
-
更好的TypeScript支持:代码提示更完善
-
新的响应式系统:基于Proxy实现,性能更优
二、Composition API深度解析
1. 为什么需要Composition API?
Options API在组件逻辑复杂时存在几个问题:
-
相关逻辑分散在不同选项中(data、methods、computed等)
-
代码复用困难(mixins存在命名冲突等问题)
-
类型推断不够友好
Composition API通过将相关逻辑组织在一起,解决了这些问题。
2. 基础用法示例
<script setup>
import { ref, computed, onMounted } from 'vue'// 响应式状态
const count = ref(0)
const doubleCount = computed(() => count.value * 2)// 方法
function increment() {count.value++
}// 生命周期钩子
onMounted(() => {console.log('组件已挂载')
})
</script><template><button @click="increment">点击次数: {{ count }}, 双倍: {{ doubleCount }}</button>
</template>
3. 逻辑复用:自定义组合函数
// useCounter.js
import { ref } from 'vue'export function useCounter(initialValue = 0) {const count = ref(initialValue)function increment() {count.value++}function decrement() {count.value--}function reset() {count.value = initialValue}return {count,increment,decrement,reset}
}// 在组件中使用
<script setup>
import { useCounter } from './useCounter'const { count, increment } = useCounter(10)
</script>
4. 与Options API对比
特性 | Options API | Composition API |
---|---|---|
代码组织 | 按选项类型分组 | 按逻辑功能分组 |
类型支持 | 一般 | 优秀 |
逻辑复用 | Mixins/作用域插槽 | 自定义组合函数 |
学习曲线 | 平缓 | 较陡峭 |
适合场景 | 简单组件 | 复杂逻辑/大型应用 |
三、Pinia:下一代Vue状态管理
1. Pinia vs Vuex
Pinia是Vue官方推荐的状态管理库,相比Vuex有诸多优势:
-
更简单的API,去掉mutations概念
-
完整的TypeScript支持
-
模块化设计,无需嵌套模块
-
更轻量,打包体积更小
-
支持Composition API和Options API
2. 核心概念与基本使用
安装Pinia
npm install pinia
创建Store
// stores/counter.js
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => ({count: 0}),actions: {increment() {this.count++},async fetchData() {const response = await fetch('/api/data')this.data = await response.json()}},getters: {doubleCount: (state) => state.count * 2}
})
在组件中使用
<script setup>
import { useCounterStore } from '@/stores/counter'const counter = useCounterStore()
</script><template><div>当前计数: {{ counter.count }}</div><div>双倍计数: {{ counter.doubleCount }}</div><button @click="counter.increment()">增加</button>
</template>
3. 高级特性
状态持久化
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)// 在store中启用
export const useUserStore = defineStore('user', {state: () => ({user: null}),persist: true
})
模块化组织
// stores/index.js
import { useUserStore } from './user'
import { useCartStore } from './cart'
import { useProductStore } from './product'export default {user: useUserStore,cart: useCartStore,product: useProductStore
}// 组件中使用
import stores from '@/stores'const userStore = stores.user()
const cartStore = stores.cart()
四、Vue Router路由守卫实战
1. 路由守卫类型
Vue Router提供了多种路由守卫,用于控制导航:
-
全局守卫
-
beforeEach
-
beforeResolve
-
afterEach
-
-
路由独享守卫
-
beforeEnter
-
-
组件内守卫
-
beforeRouteEnter
-
beforeRouteUpdate
-
beforeRouteLeave
-
2. 典型应用场景
认证检查
// router.js
import { createRouter } from 'vue-router'const router = createRouter({// ...路由配置
})router.beforeEach(async (to, from) => {const isAuthenticated = await checkAuth()// 需要登录但未登录if (to.meta.requiresAuth && !isAuthenticated) {return {path: '/login',query: { redirect: to.fullPath }}}// 已登录但访问登录页if (to.path === '/login' && isAuthenticated) {return { path: '/' }}
})
权限控制
router.beforeEach(async (to, from) => {const userRole = await getUserRole()const requiredRoles = to.meta.roles || []if (requiredRoles.length && !requiredRoles.includes(userRole)) {return { path: '/403' } // 无权限页面}
})
页面访问统计
router.afterEach((to, from) => {trackPageView(to.fullPath)
})
3. 组合式API中使用路由守卫
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'// 当前路由变化但组件被复用时调用
onBeforeRouteUpdate(async (to, from) => {if (to.params.id !== from.params.id) {await fetchData(to.params.id)}
})// 离开当前路由前调用
onBeforeRouteLeave((to, from) => {if (formHasChanges.value) {return confirm('您有未保存的更改,确定要离开吗?')}
})
</script>
五、三大特性整合实战
1. 用户认证系统实现
认证Store
// stores/auth.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import router from '@/router'export const useAuthStore = defineStore('auth', () => {const user = ref(null)const token = ref(localStorage.getItem('token'))async function login(credentials) {const response = await fetch('/api/login', {method: 'POST',body: JSON.stringify(credentials)})const data = await response.json()user.value = data.usertoken.value = data.tokenlocalStorage.setItem('token', data.token)router.push('/dashboard')}function logout() {user.value = nulltoken.value = nulllocalStorage.removeItem('token')router.push('/login')}return { user, token, login, logout }
})
路由配置
// router.js
import { createRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'const router = createRouter({routes: [{path: '/',component: () => import('@/views/Home.vue'),meta: { requiresAuth: true }},{path: '/login',component: () => import('@/views/Login.vue'),meta: { guestOnly: true }}]
})router.beforeEach((to) => {const auth = useAuthStore()if (to.meta.requiresAuth && !auth.token) {return { path: '/login', query: { redirect: to.fullPath } }}if (to.meta.guestOnly && auth.token) {return { path: '/' }}
})
登录组件
<script setup>
import { ref } from 'vue'
import { useAuthStore } from '@/stores/auth'const auth = useAuthStore()
const form = ref({email: '',password: ''
})async function handleSubmit() {try {await auth.login(form.value)} catch (error) {alert('登录失败: ' + error.message)}
}
</script><template><form @submit.prevent="handleSubmit"><input v-model="form.email" type="email" placeholder="邮箱"><input v-model="form.password" type="password" placeholder="密码"><button type="submit">登录</button></form>
</template>
六、性能优化与最佳实践
1. Composition API优化技巧
-
使用
computed
缓存计算结果 -
将复杂逻辑拆分为多个组合函数
-
使用
watchEffect
和watch
时注意清理副作用 -
对于大型组件,考虑使用
<script setup>
语法糖
2. Pinia状态管理最佳实践
-
按功能而非数据类型组织store
-
避免在store中直接操作DOM
-
使用getters派生状态,减少重复计算
-
对于复杂业务逻辑,使用actions封装
-
合理使用状态持久化
3. 路由守卫注意事项
-
避免在守卫中执行耗时同步操作
-
对于异步操作,确保返回Promise或使用async/await
-
考虑使用路由元信息(meta)来配置守卫行为
-
全局守卫中避免频繁的状态访问,可缓存必要数据
七、常见问题与解决方案
1. Composition API相关问题
Q: 如何在setup中访问this?
A: 在setup中不需要也不应该使用this,所有组件实例的访问都应通过参数或Composition API函数实现。
Q: 如何复用组件逻辑?
A: 将可复用逻辑提取为组合函数,返回需要暴露的响应式数据和方法。
2. Pinia使用问题
Q: 什么时候应该使用Pinia?
A: 当需要在多个组件间共享状态,或者状态逻辑比较复杂时使用。对于简单的父子组件通信,props和emit可能更合适。
Q: 如何调试Pinia状态?
A: 安装Vue Devtools,它提供了专门的Pinia面板用于状态调试。
3. 路由守卫问题
Q: 导航守卫中如何获取组件实例?
A: 在beforeRouteEnter
中可以通过next回调访问:
beforeRouteEnter(to, from, next) {next(vm => {// 通过vm访问组件实例})
}
Q: 如何处理取消的导航?
A: 返回false或导航到其他路由,确保守卫函数有明确的返回值。
八、总结
Vue 3通过Composition API、Pinia和增强的Vue Router,为开发者提供了更强大、更灵活的工具集:
-
Composition API 改变了我们组织组件逻辑的方式,使代码更易于维护和复用
-
Pinia 作为新一代状态管理方案,简化了全局状态管理,提供了更好的开发体验
-
路由守卫 系统为应用提供了完善的导航控制能力
掌握这三大特性,你将能够构建更复杂、更健壮的Vue 3应用程序。随着Vue生态的不断发展,这些技术也将继续演进,建议持续关注官方文档和社区动态。