从0到1:Vue3 + Router + Pinia 实现状态管理与登录鉴权
在Vue3项目开发中,路由管理(Vue Router)和状态管理(Pinia)是两大核心模块。前者负责页面跳转与路由守卫,后者解决组件间数据共享问题。今天学了搭建一个集成Vue Router和Pinia的Vue3项目,实现登录验证、用户状态持久化与退出登录功能。
一、核心技术选型
1. Vue3
作为前端主流框架,Vue3的组合式API(Composition API)相比Options API更灵活,支持按需引入API,大幅降低组件耦合度。
2. Vue Router
Vue官方路由管理器,负责页面路由跳转、路由拦截等核心功能,是单页应用(SPA)的基础。
3. Pinia
Vue3官方推荐的状态管理库,替代了传统的Vuex。相比Vuex,Pinia具有以下优势:
- 扁平化结构:无需嵌套模块,多个独立Store直接管理不同维度的状态,耦合度更低;
- 极简API:去掉了Vuex的mutations,直接通过actions修改状态,代码更简洁;
- 完整TS支持:天生适配TypeScript,类型提示更友好;
- 兼容Vue2/Vue3:跨版本兼容,迁移成本低。
二、项目搭建步骤
1. 创建Vue3项目并安装依赖
首先通过Vite快速创建Vue3项目,再安装Vue Router和Pinia依赖:
# 创建Vite项目
npm create vite
# 进入项目目录
cd 你的项目名称
# 安装基础依赖
npm install
# 安装Vue Router
npm install vue-router
# 安装Pinia
npm install pinia
2. 配置Vue Router(基础路由搭建)
先完成路由的基础配置,创建登录页(Login.vue)和首页(Home.vue),并配置路由规则:
(1)创建路由文件 src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Login from '../views/Login.vue'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
redirect: '/login' // 默认跳转到登录页
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/home',
name: 'Home',
component: Home
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
3. 配置Pinia(用户状态管理)
Pinia的核心是Store,我们创建一个用户Store来管理登录状态(用户名、token),并实现状态持久化(结合localStorage)。
(1)创建用户Store src/stores/user.js
Store包含三部分核心内容:
state:存储核心数据(用户名、token);actions:修改state的方法(设置用户信息、退出登录);- 持久化:通过localStorage将数据保存到本地,防止页面刷新丢失。
import { defineStore } from 'pinia'
// 定义并导出用户Store
export const useUserStore = defineStore('user', {
// 状态:初始化时从localStorage读取数据,实现持久化
state: () => ({
token: localStorage.getItem('token') || '',
username: localStorage.getItem('username') || ''
}),
// 动作:修改状态的方法(支持异步)
actions: {
// 设置用户信息
setUser(username, token) {
this.username = username
this.token = token
// 同步到localStorage
localStorage.setItem('username', username)
localStorage.setItem('token', token)
},
// 退出登录:清空状态和本地存储
logout() {
this.username = ''
this.token = ''
localStorage.removeItem('username')
localStorage.removeItem('token')
}
}
})
(2)在main.js中注册Pinia
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
const app = createApp(App)
// 创建Pinia实例并注册
const pinia = createPinia()
app.use(pinia)
// 注册路由
app.use(router)
app.mount('#app')
4. 实现登录功能(Login.vue)
在登录页面引入用户Store,验证用户名密码后,调用Store的setUser方法保存用户状态,并跳转到首页。
<template>
<div class="login-container">
<h3>用户登录</h3>
<div class="form-item">
<label>用户名:</label>
<input v-model="username" type="text" placeholder="请输入用户名" />
</div>
<div class="form-item">
<label>密码:</label>
<input v-model="password" type="password" placeholder="请输入密码" />
</div>
<button @click="handleLogin">登录</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '../stores/user'
// 响应式数据
const username = ref('')
const password = ref('')
// 路由实例
const router = useRouter()
// 用户Store实例
const userStore = useUserStore()
// 登录处理函数
const handleLogin = () => {
// 简单的密码验证(实际项目中需对接后端接口)
if (username.value === 'w' && password.value === '1') {
// 调用Store方法保存用户状态
userStore.setUser(username.value, 'fake-token')
// 跳转到首页
router.push('/home')
} else {
alert('用户名或密码错误')
}
}
</script>
<style scoped>
.login-container {
width: 400px;
margin: 100px auto;
padding: 20px;
border: 1px solid #eee;
border-radius: 8px;
}
.form-item {
margin-bottom: 16px;
display: flex;
align-items: center;
}
.form-item label {
width: 80px;
}
.form-item input {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
width: 100%;
padding: 10px;
background: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
5. 实现首页与退出登录(Home.vue)
在首页展示当前登录用户信息,并实现退出登录功能(清空状态+跳转登录页)。
<template>
<div class="home-container">
<div class="header">
<h2>微头条首页</h2>
<div class="user-info">欢迎,{{ userStore.username }}</div>
<button @click="logout">退出登录</button>
</div>
<div class="content">
<p>首页内容区域...</p>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import { useUserStore } from '../stores/user'
// 路由实例
const router = useRouter()
// 用户Store实例
const userStore = useUserStore()
// 退出登录
const logout = () => {
// 调用Store的退出方法
userStore.logout()
// 跳转到登录页
router.push('/login')
}
</script>
<style scoped>
.home-container {
width: 1000px;
margin: 0 auto;
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
margin-bottom: 20px;
}
.user-info {
color: #666;
}
button {
padding: 8px 16px;
background: #ff4444;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
三、核心逻辑解析
1. 状态持久化
在user.js的state中,初始化时从localStorage读取数据,保证页面刷新后用户状态不丢失;setUser和logout方法中同步修改localStorage,确保状态与本地存储一致。
2. Store的使用方式
通过useUserStore()获取Store实例,直接访问state中的数据(如userStore.username),调用actions中的方法(如userStore.setUser())修改状态,无需像Vuex那样通过commit/dispatch,API更简洁。
3. 路由与状态的联动
- 登录成功:调用
setUser保存状态 → 路由跳转到首页; - 退出登录:调用
logout清空状态 → 路由跳转到登录页。
四、进阶优化建议
- 路由守卫:添加全局路由守卫,未登录用户禁止访问首页(判断
userStore.token是否存在); - 接口对接:将硬编码的用户名密码验证替换为后端接口请求,使用真实的token;
- TypeScript支持:为Store添加类型定义,提升代码可读性和可维护性;
- 状态解构:使用
storeToRefs解构Store中的状态,保证响应式(如const { username } = storeToRefs(userStore)); - 样式优化:结合UI框架(如Element Plus)美化登录页和首页,提升用户体验。
五、总结
本文通过一个简单的登录-首页场景,完整实现了Vue3 + Vue Router + Pinia的集成方案。Pinia的扁平化设计和极简API让状态管理更简单,结合Vue Router实现了页面跳转与状态联动,同时通过localStorage实现了状态持久化。

(05春还发布了一个假新闻并点赞到250!)

浙公网安备 33010602011771号