Vue 3 工程化实践:多页面路由配置 + Pinia 状态管理完全指南

在 Vue 3 项目开发中,多页面路由 是构建单页应用(SPA)的核心骨架,而 Pinia 状态管理 则是解决组件间数据共享的利器。本文将从实战角度出发,一步步带你配置首页、列表页、详情页的路由,实现页面导航与参数传递,并结合 Pinia 管理用户登录状态、用户信息,同时实现状态持久化,配合清晰的图解,让你轻松掌握 Vue 3 开发的核心技能。

一、开发多页面应用:Vue Router 4 实战

Vue Router 4 是 Vue 3 的官方路由管理器,通过它我们可以轻松实现页面间的切换、参数传递等功能。

1.1 安装与基础配置

首先,在 Vue 3 项目中安装 Vue Router 4:

bash 复制代码
npm install vue-router@4

接下来,创建路由配置文件 src/router/index.js

bash 复制代码
import { createRouter, createWebHistory } from 'vue-router'
// 引入页面组件
import Home from '@/views/Home.vue'
import List from '@/views/List.vue'
import Detail from '@/views/Detail.vue'

// 定义路由规则
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home // 首页
  },
  {
    path: '/list',
    name: 'List',
    component: List // 列表页
  },
  {
    path: '/detail/:id', // 动态路由,:id 为参数占位符
    name: 'Detail',
    component: Detail // 详情页
  }
]

// 创建路由实例
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL), // 使用 HTML5 History 模式
  routes
})

export default router

然后在 main.js 中注册路由:

bash 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 引入路由配置

const app = createApp(App)
app.use(router) // 注册路由
app.mount('#app')

最后,在 App.vue 中添加路由出口 <router-view>

html 复制代码
<template>
  <div id="app">
    <!-- 路由出口,匹配到的页面组件会渲染在这里 -->
    <router-view></router-view>
  </div>
</template>

1.2 配置首页、列表页、详情页组件

我们先创建三个基础页面组件:

1.2.1 首页 (src/views/Home.vue)
html 复制代码
<template>
  <div class="home">
    <h1>首页</h1>
    <p>欢迎来到 Vue 3 多页面应用!</p>
    <!-- 使用 router-link 进行声明式导航 -->
    <router-link to="/list">跳转到列表页</router-link>
  </div>
</template>

<style scoped>
.home { padding: 20px; }
</style>
1.2.2 列表页 (src/views/List.vue)
html 复制代码
<template>
  <div class="list">
    <h1>列表页</h1>
    <ul>
      <!-- 模拟列表数据 -->
      <li v-for="item in list" :key="item.id">
        <!-- 跳转到详情页,传递 id 参数 -->
        <router-link :to="`/detail/${item.id}`">{{ item.title }}</router-link>
      </li>
    </ul>
    <br>
    <router-link to="/">返回首页</router-link>
  </div>
</template>

<script setup>
import { ref } from 'vue'

// 模拟列表数据
const list = ref([
  { id: 1, title: '文章一:Vue Router 入门' },
  { id: 2, title: '文章二:Pinia 状态管理' },
  { id: 3, title: '文章三:Vue 3 组合式 API' }
])
</script>

<style scoped>
.list { padding: 20px; }
li { margin: 10px 0; }
</style>
1.2.3 详情页 (src/views/Detail.vue)
html 复制代码
<template>
  <div class="detail">
    <h1>详情页</h1>
    <p>当前文章 ID:{{ articleId }}</p>
    <p>文章标题:{{ articleTitle }}</p>
    <br>
    <!-- 编程式导航返回列表页 -->
    <button @click="goBack">返回列表页</button>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router' // 引入路由钩子

const route = useRoute() // 获取当前路由信息
const router = useRouter() // 获取路由实例,用于编程式导航

const articleId = ref('')
const articleTitle = ref('')

// 模拟文章数据
const articles = {
  1: '文章一:Vue Router 入门',
  2: '文章二:Pinia 状态管理',
  3: '文章三:Vue 3 组合式 API'
}

onMounted(() => {
  // 接收动态路由参数 :id
  articleId.value = route.params.id
  articleTitle.value = articles[articleId.value] || '文章不存在'
})

// 编程式导航返回列表页
const goBack = () => {
  router.push('/list')
}
</script>

<style scoped>
.detail { padding: 20px; }
</style>

1.3 页面导航与参数传递详解

1.3.1 两种导航方式
  • 声明式导航 :使用 <router-link> 组件,通过 to 属性指定目标路径,适合在模板中直接使用。
  • 编程式导航 :使用 useRouter 钩子获取路由实例,调用 router.push()router.replace() 等方法,适合在逻辑代码中使用。
1.3.2 两种参数传递方式

表格

方式 写法 接收方式 刷新页面 示例
动态路由参数 path: '/detail/:id',跳转:/detail/1 route.params.id 参数保留 详情页 ID
Query 参数 跳转:/detail?id=1 route.query.id 参数保留 搜索关键词

注意 :如果使用 name 配合 params 跳转(如 router.push({ name: 'Detail', params: { id: 1 } })),刷新页面后参数会丢失,建议优先使用动态路由参数或 Query 参数。

1.4 路由导航流程图解

二、Pinia 状态管理:用户登录与持久化

Pinia 是 Vue 3 的官方状态管理库,相比 Vuex 更简洁、更符合组合式 API 的设计理念,支持 TypeScript,且 DevTools 支持更好。

2.1 Pinia 安装与注册

首先安装 Pinia 和持久化插件(用于状态刷新不丢失):

bash 复制代码
npm install pinia
npm install pinia-plugin-persistedstate

然后在 main.js 中注册 Pinia 和持久化插件:

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia' // 引入 Pinia
import piniaPersistedstate from 'pinia-plugin-persistedstate' // 引入持久化插件

const app = createApp(App)
const pinia = createPinia() // 创建 Pinia 实例
pinia.use(piniaPersistedstate) // 注册持久化插件

app.use(router)
app.use(pinia) // 注册 Pinia
app.mount('#app')

2.2 创建 User Store(用户状态管理)

创建 src/store/user.js,用于管理登录状态和用户信息:

javascript 复制代码
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

// 定义 User Store
export const useUserStore = defineStore('user', () => {
  // 1. State:响应式数据
  const token = ref('') // 登录 Token
  const userInfo = ref({}) // 用户信息

  // 2. Getters:计算属性(可选,用于派生状态)
  const isLoggedIn = computed(() => !!token.value) // 是否登录

  // 3. Actions:修改状态的方法
  // 登录:保存 Token 和用户信息
  const login = (newToken, newUserInfo) => {
    token.value = newToken
    userInfo.value = newUserInfo
  }

  // 登出:清空状态
  const logout = () => {
    token.value = ''
    userInfo.value = {}
  }

  // 更新用户信息
  const updateUserInfo = (newInfo) => {
    userInfo.value = { ...userInfo.value, ...newInfo }
  }

  // 返回 state、getters、actions
  return {
    token,
    userInfo,
    isLoggedIn,
    login,
    logout,
    updateUserInfo
  }
}, {
  // 4. 持久化配置
  persist: {
    key: 'user-store', // 存储在 localStorage 中的 key
    storage: localStorage, // 存储方式:localStorage 或 sessionStorage
    paths: ['token', 'userInfo'] // 指定需要持久化的 state,默认全部
  }
})

2.3 在组件中使用 User Store

我们修改之前的页面,加入登录、显示用户信息、登出功能:

2.3.1 新增登录页 (src/views/Login.vue)

先在路由配置中添加登录页路由:

javascript 复制代码
// src/router/index.js
const routes = [
  // ... 之前的路由
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue') // 路由懒加载
  }
]

然后创建登录页组件:

html 复制代码
<template>
  <div class="login">
    <h1>登录页</h1>
    <form @submit.prevent="handleLogin">
      <div>
        <label>用户名:</label>
        <input v-model="username" placeholder="请输入用户名" required />
      </div>
      <div>
        <label>密码:</label>
        <input v-model="password" type="password" placeholder="请输入密码" required />
      </div>
      <button type="submit">登录</button>
    </form>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/store/user' // 引入 User Store

const router = useRouter()
const userStore = useUserStore() // 获取 Store 实例

const username = ref('')
const password = ref('')

// 模拟登录
const handleLogin = () => {
  // 假设登录成功,返回 Token 和用户信息
  const mockToken = 'mock-token-123456'
  const mockUserInfo = {
    id: 1,
    username: username.value,
    avatar: 'https://via.placeholder.com/50'
  }

  // 调用 Store 的 login 方法
  userStore.login(mockToken, mockUserInfo)
  // 登录成功后跳转到首页
  router.push('/')
}
</script>

<style scoped>
.login { padding: 20px; max-width: 300px; margin: 0 auto; }
div { margin: 10px 0; }
input { width: 100%; padding: 8px; box-sizing: border-box; }
button { width: 100%; padding: 10px; background: #42b883; color: white; border: none; cursor: pointer; }
</style>
2.3.2 修改首页 (src/views/Home.vue),显示用户信息
html 复制代码
<template>
  <div class="home">
    <h1>首页</h1>
    <!-- 根据登录状态显示不同内容 -->
    <div v-if="userStore.isLoggedIn">
      <p>欢迎你,{{ userStore.userInfo.username }}!</p>
      <img :src="userStore.userInfo.avatar" alt="头像" style="width: 50px; height: 50px; border-radius: 50%;" />
      <br><br>
      <button @click="handleLogout">登出</button>
    </div>
    <div v-else>
      <p>你还未登录,请先登录。</p>
      <router-link to="/login">去登录</router-link>
    </div>
    <br><br>
    <router-link to="/list">跳转到列表页</router-link>
  </div>
</template>

<script setup>
import { useUserStore } from '@/store/user'
import { useRouter } from 'vue-router'

const userStore = useUserStore()
const router = useRouter()

// 登出
const handleLogout = () => {
  userStore.logout()
  router.push('/login')
}
</script>

<style scoped>
.home { padding: 20px; }
</style>

2.4 Pinia 状态管理流程图解

三、总结与最佳实践

3.1 路由配置最佳实践

  1. 路由懒加载 :使用 () => import('@/views/xxx.vue') 实现路由懒加载,减小首屏包体积。
  2. 动态路由参数 :优先使用动态路由参数(如 /detail/:id)传递关键数据,刷新页面不丢失。
  3. 路由守卫 :可添加全局前置守卫 router.beforeEach 实现登录拦截(如未登录跳转到登录页)。

3.2 Pinia 使用最佳实践

  1. 模块化 Store :按功能划分 Store(如 user.jscart.js),避免单个 Store 过大。
  2. 组合式 API 写法 :使用 defineStore 的函数式写法(而非对象式),更符合 Vue 3 的设计理念。
  3. 持久化插件 :合理使用 pinia-plugin-persistedstate,只持久化必要的 state(如 Token、用户信息),避免存储敏感数据。
相关推荐
lxh01132 小时前
电话号码的字母组合
java·javascript·算法
小李子呢02112 小时前
为什么会有react和vue这些框架的出现
前端·vue.js·react.js
军训猫猫头2 小时前
7.带输入参数的线程启动 C# + WPF 完整示例
开发语言·前端·c#·.net·wpf
CodeSheep2 小时前
同事偷偷给我介绍私活,说1万报酬全给我,结果甲方私下告诉我说,同事在当中白拿了2万,我觉得被耍了,媳妇却让我要知足,说我一点不亏
前端·后端·程序员
Betelgeuse762 小时前
告别传统 ModelForm:用 React 与 DRF 打造现代化项目管理表单
前端·react.js·django·前端框架
IT_陈寒2 小时前
SpringBoot这个"自动配置"差点让我加班到凌晨
前端·人工智能·后端
遗憾随她而去.2 小时前
react学习(一)
javascript·学习·react.js
恋恋风尘hhh2 小时前
文字点选验证码前端安全研究:以网易易盾(dun.163)为例
前端·安全
鹏程十八少2 小时前
1.2026金三银四 Android Glide 23连问终极拆解:生命周期、三级缓存、Bitmap复用,大厂面试官到底想听什么?
android·前端·面试