从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读取数据,保证页面刷新后用户状态不丢失;setUserlogout方法中同步修改localStorage,确保状态与本地存储一致。

2. Store的使用方式

通过useUserStore()获取Store实例,直接访问state中的数据(如userStore.username),调用actions中的方法(如userStore.setUser())修改状态,无需像Vuex那样通过commit/dispatch,API更简洁。

3. 路由与状态的联动

  • 登录成功:调用setUser保存状态 → 路由跳转到首页;
  • 退出登录:调用logout清空状态 → 路由跳转到登录页。

四、进阶优化建议

  1. 路由守卫:添加全局路由守卫,未登录用户禁止访问首页(判断userStore.token是否存在);
  2. 接口对接:将硬编码的用户名密码验证替换为后端接口请求,使用真实的token;
  3. TypeScript支持:为Store添加类型定义,提升代码可读性和可维护性;
  4. 状态解构:使用storeToRefs解构Store中的状态,保证响应式(如const { username } = storeToRefs(userStore));
  5. 样式优化:结合UI框架(如Element Plus)美化登录页和首页,提升用户体验。

五、总结

本文通过一个简单的登录-首页场景,完整实现了Vue3 + Vue Router + Pinia的集成方案。Pinia的扁平化设计和极简API让状态管理更简单,结合Vue Router实现了页面跳转与状态联动,同时通过localStorage实现了状态持久化。

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

posted @ 2026-06-11 10:24  橙糯CiiiiiX  阅读(41)  评论(2)    收藏  举报