
在 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 路由配置最佳实践
- 路由懒加载 :使用
() => import('@/views/xxx.vue')实现路由懒加载,减小首屏包体积。 - 动态路由参数 :优先使用动态路由参数(如
/detail/:id)传递关键数据,刷新页面不丢失。 - 路由守卫 :可添加全局前置守卫
router.beforeEach实现登录拦截(如未登录跳转到登录页)。
3.2 Pinia 使用最佳实践
- 模块化 Store :按功能划分 Store(如
user.js、cart.js),避免单个 Store 过大。 - 组合式 API 写法 :使用
defineStore的函数式写法(而非对象式),更符合 Vue 3 的设计理念。 - 持久化插件 :合理使用
pinia-plugin-persistedstate,只持久化必要的 state(如 Token、用户信息),避免存储敏感数据。