前言:Vue3大事件项目是一个基于Vue3的PC端项目,本系列文章我将总结我在这个项目中学到的知识点,写项目笔记。如果你正好在学或巩固Vue3,希望本系列文章可以帮助到你。

【Vue3大事件 | 项目笔记】第二天
今日完结:
- 用Pinia构建用户仓库并持久化
- 请求工具设计
- 路由的设计和配置
- 登录注册页结构渲染
今日收获:
1.用Pinia持久化
当用户输入信息时,若希望输入的内容在页面刷新后不丢失,且该信息需要在多个组件 / 页面中共享,我们可以用 Pinia 管理这些输入状态,并通过 Pinia 持久化插件(如 pinia-plugin-persistedstate)将状态同步到浏览器本地存储(localStorage/sessionStorage),从而实现数据的持久化保存。
步骤:
1.安装插件
javascript
pnpm add pinia-plugin-persistedstate -D
2.使用 main.js
javascript
import persist from 'pinia-plugin-persistedstate'
...
app.use(createPinia().use(persist))
3.配置 stores/user.js
javascript
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 用户模块
export const useUserStore = defineStore(
'big-user',
...
{
persist: true // 持久化
}
)
2.掌握仓库统一导出
引入一个仓库书写方式: import { useUserStore } from ./stores/modules/user.js ,写起来很长,同时不同仓库路径不一致,导致很麻烦。为解决不同 Pinia 仓库导入路径不统一、书写麻烦的问题,我们可以把所有仓库文件集中放在 stores/modules 目录管理,同时在 stores/index.js 中统一导出这些仓库,这样业务组件只需从 ./stores 这一个路径导入,无需记忆各仓库的具体路径。
在stores中的index.js文件里面配置
javascript
export * from './modules/user'
//等同于 import {useUserStore} from './modules/user'
// export {userCountStore}
3.学会请求工具的设计
像我们平时写的分散代码,具有每个接口请求都需重复编写 baseURL、超时时间、token 携带、错误处理等逻辑,项目接口越多,重复代码量越大;若需修改鉴权规则(如 token 字段名变更)、调整超时时间,或更换提示组件(如从 ElMessage 换为其他组件),需逐个修改所有接口请求代码等问题。这时我们可以进行请求工具的统一设计。
请求工具的设计核心优势:复用通用请求逻辑、统一全局请求规则、降低维护成本、提升扩展性和用户体验。

新建 utils/request.js 封装 axios 模块
javascript
import axios from 'axios'
import { useUserStore } from '@/stores'
import { ElMessage } from 'element-plus'
import router from '@/router'
const baseURL = 'http://big-event-vue-api-t.itheima.net'
const instance = axios.create({
// TODO 1. 基础地址,超时时间
baseURL,
timeout: 10000
})
instance.interceptors.request.use(
(config) => {
// TODO 2. 携带token
const userStore = useUserStore()
if (userStore.token) {
config.headers.Authorization = userStore.token
}
return config
},
(err) => Promise.reject(err)
)
instance.interceptors.response.use(
(res) => {
// TODO 4. 摘取核心响应数据
if (res.data.code === 0) {
return res
}
// TODO 3. 处理业务失败
ElMessage.error(res.data.message || '服务异常')
return Promise.reject(res.data)
},
(err) => {
// TODO 5. 处理401错误
if (err.response?.status === 401) {
router.push('/login')
}
ElMessage.error(err.response.data.message || '服务异常')
return Promise.reject(err)
}
)
export default instance
export { baseURL }
4.用Element进行注册登录静态结构渲染
和纯手写 HTML 搭建页面结构的方式相比,这里的静态结构渲染依托 Element Plus组件库实现:组件库已预制好 el-row(行)、el-col(列)、el-form(表单)等通用 UI 组件的结构和样式,直接调用即可,无需从零编写布局和表单的基础代码,大幅提升页面开发效率。

javascript
<script setup>
import { User, Lock } from '@element-plus/icons-vue'
import { ref } from 'vue'
const isRegister = ref(true)
</script>
<template>
<el-row class="login-page">
<el-col :span="12" class="bg"></el-col>
<el-col :span="6" :offset="3" class="form">
<el-form ref="form" size="large" autocomplete="off" v-if="isRegister">
<el-form-item>
<h1>注册</h1>
</el-form-item>
....
</el-form>
...
<el-form ref="form" size="large" autocomplete="off" v-else>
<el-form-item>
<h1>登录</h1>
</el-form-item>
...
</el-form>
</el-col>
</el-row>
</template>
5.表单校验
同时element也提供了用户进行登录和注册时的表单校验。
(1) el-form => :model="ruleForm"
绑定的整个 form 的数据对象 { xxxx, xxxx, xxxx }
javascript
const formModel = ref({
username: '',
...
})
<el-form :model="formModel" >
(2) el-form => :rules="rules"
绑定的整个 rules 规则对象 { xxxx, xxxx, xxxx }
javascript
<el-input
v-model="formModel.username"
:prefix-icon="User"
placeholder="请输入用户名"
></el-input>
(3) 表单元素 => v-model="ruleForm.xxx"
给表单元素,绑定 form 的子属性
javascript
<el-form :rules="rules" >
const rules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 10, message: '用户名必须是5-10位的字符', trigger: 'blur' }
],
}
(4) prop 配置生效的是哪个校验规则
javascript
<el-form-item prop="username">
<el-input
v-model="formModel.username"
:prefix-icon="User"
placeholder="请输入用户名"
></el-input>
</el-form-item>
这样就实现了用户在进行用户名填写的时候,必须遵循"用户名必须是5-10位的字符,不能为空"的规则。
注册前的预校验
注册前的预校验,是指用户在提交注册表单(如点击 "注册" 按钮)前,前端对输入的信息(用户名、手机号、邮箱、密码等)进行即时的规则验证,而非直接提交到后端。
好处:减少无效的后端请求,降低服务器压力,提升用户体验,即时反馈错误。
步骤:
1.通过 ref 获取到 表单组件
javascript
const form = ref()
<el-form ref="form">
2.通过 ref 获取到 表单组件
javascript
<el-button
@click="register"
class="button"
type="primary"
auto-insert-space
>
注册
</el-button>
const register = async () => {
await form.value.validate() //预校验
console.log('开始注册请求')
}
杂项知识点:
注册和登录切换问题
在注册 / 登录表单通过 v-if 切换时,用户已填写的 "用户名""密码" 等表单内容会残留(切换后仍显示在另一表单中);为解决该问题,我们可以监听切换条件(如 isRegister)的变化,在切换触发时,调用表单重置方法清空已输入的内容,保证两个表单的数据互不干扰。
javascript
watch(isRegister,()=>{
formModel.value = {
username: '',
password: '',
repassword: ''
}
})
Pinia存储和localStorage直接存储区别
Pinia存储和localStorage直接存储本质最终都实现数据持久化,但两者两种完全不同的状态管理方式。
核心区别:Pinia是Vue专属的响应式内存状态管理库,支持任意JS类型,数据变更组件自动更新,适合跨组件共享的复杂状态(持久化需插件);localStorage是浏览器本地存储API,仅存字符串、无响应式,需手动序列化/反序列化,适合简单数据的持久化,无需跨组件共享时更轻便。
总结:
今天了解到了Element组件库里面的很多知识,也学会了很多优化代码的逻辑。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!
