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.js、cart.js),避免单个 Store 过大。
  2. 组合式 API 写法 :使用 defineStore 的函数式写法(而非对象式),更符合 Vue 3 的设计理念。
  3. 持久化插件 :合理使用 pinia-plugin-persistedstate,只持久化必要的 state(如 Token、用户信息),避免存储敏感数据。
相关推荐
梦帮科技2 分钟前
Web 漏洞攻防深度:WAF 规则逃逸技术(畸形分块传输、双重编码)与对抗加固
linux·前端·网络安全·ssl·web
兰亭妙微UI设计公司9 分钟前
兰亭妙微软件界面设计公司的解锁按钮设计10大密码
开发语言·前端·javascript
迪幻32 分钟前
封装自己的 npm 依赖并存储到个人 GitHub
前端·npm·github
u0111026751 小时前
WebP 转成 PNG 后为什么更大?图片格式转换不等于压缩
前端·javascript·vue.js
万少1 小时前
Qoder sonus模型 20分钟,复刻 马斯克 飞天汽车
前端·后端·算法
seconp1 小时前
基于Spring Boot和Vue 3的智慧旅游网站:住宿预订、行程规划与千问接入
vue.js·spring boot·毕业设计·软件工程·课程设计·旅游·毕设
java1234_小锋1 小时前
【技术专题】HTML5 网页技术 - HTML5 列表标签
前端·html·html5
强二小哥帅1 小时前
Kotlin 协程复习笔记
前端
不可能片场1 小时前
工程实践 原子替换改了 ctime 怎么修
前端·electron
暧暧内含光1 小时前
HTTP 文件传输体系全解:从协议标头、OSS 架构到流媒体分片
前端