Vue3组合式API实战:构建高效可复用的用户认证模块
引言:为什么选择组合式API
在Vue3中,组合式API(Composition API)彻底改变了我们组织和复用代码的方式。与Options API相比,它提供了更灵活的逻辑组织和更好的类型推断支持。本文将带你通过构建一个完整的用户认证模块,深入理解组合式API的强大之处。
项目初始化与基础配置
首先创建一个新的Vue3项目并安装必要依赖:
npm init vue@latest vue-auth-demo
cd vue-auth-demo
npm install axios vue-router pinia
我们将使用Pinia作为状态管理库,axios处理HTTP请求,vue-router管理路由。
核心:创建useAuth组合式函数
在src/composables
目录下创建useAuth.js
:
import { ref } from 'vue'
import axios from 'axios'
import { useRouter } from 'vue-router'
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null,
token: localStorage.getItem('token') || null
}),
// ...
})
export default function useAuth() {
const router = useRouter()
const authStore = useAuthStore()
const isLoading = ref(false)
const error = ref(null)
const login = async (credentials) => {
try {
isLoading.value = true
const response = await axios.post('/api/auth/login', credentials)
authStore.token = response.data.token
authStore.user = response.data.user
localStorage.setItem('token', response.data.token)
router.push('/dashboard')
} catch (err) {
error.value = err.response?.data?.message || '登录失败'
} finally {
isLoading.value = false
}
}
const logout = () => {
authStore.token = null
authStore.user = null
localStorage.removeItem('token')
router.push('/login')
}
return {
login,
logout,
isLoading,
error,
user: computed(() => authStore.user),
isAuthenticated: computed(() => !!authStore.token)
}
}
这个组合式函数封装了所有认证相关的逻辑,包括登录、登出、用户状态管理等。
路由守卫实现
在src/router/index.js
中配置路由守卫:
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '@/composables/useAuth'
const routes = [
{
path: '/dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { requiresAuth: true }
},
// 其他路由...
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to) => {
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.token) {
return '/login'
}
})
export default router
在组件中使用
登录组件示例Login.vue
:
<script setup>
import { ref } from 'vue'
import useAuth from '@/composables/useAuth'
const { login, isLoading, error } = useAuth()
const credentials = ref({
email: '',
password: ''
})
</script>
<template>
<form @submit.prevent="login(credentials)">
<div v-if="error" class="error">{{ error }}</div>
<input v-model="credentials.email" type="email" placeholder="邮箱">
<input v-model="credentials.password" type="password" placeholder="密码">
<button :disabled="isLoading">
{{ isLoading ? '登录中...' : '登录' }}
</button>
</form>
</template>
高级技巧:刷新令牌处理
扩展useAuth
函数,添加自动刷新令牌逻辑:
// 在useAuth.js中添加
const refreshToken = async () => {
try {
const response = await axios.post('/api/auth/refresh', null, {
headers: {
Authorization: `Bearer ${authStore.token}`
}
})
authStore.token = response.data.token
localStorage.setItem('token', response.data.token)
return true
} catch {
logout()
return false
}
}
// 添加axios拦截器
axios.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
const refreshed = await refreshToken()
if (refreshed) {
originalRequest.headers.Authorization = `Bearer ${authStore.token}`
return axios(originalRequest)
}
}
return Promise.reject(error)
}
)
总结与最佳实践
通过组合式API,我们实现了:
- 逻辑关注点分离,认证相关代码集中管理
- 高度可复用的认证逻辑,可在任何组件中轻松使用
- 类型友好的代码结构,便于维护和扩展
- 与Pinia状态管理无缝集成
建议将类似的业务逻辑都封装为组合式函数,可以显著提高代码的可维护性和复用性。