个人中心
个人中心分为三个部分,基本资料UserProfile.vue
,更换头像UserAvatar.vue
和重置密码UserPassword.vue
,它们是三个嵌套在首页下的二级路由页
1.基本资料
基本资料页(user/UserProfile.vue)有如下需求:
- 静态布局
- 对用户昵称和用户邮箱配置校验规则
- 实现提交修改功能
静态结构和校验
- deekseek搜索词prompt如下:
请基于 elementPlus 和 Vue3 的语法,生成组件代码
要求:
一、表单结构要求
1. 组件中包含一个el-form表单,有四行内容,前三行是输入框,第四行是按钮
2. 第一行 label 登录名称,输入框禁用不可输入状态
3. 第二行 label 用户昵称,输入框可输入
4. 第三行 label 用户邮箱,输入框可输入
5. 第四行按钮,提交修改
二、校验需求
给昵称 和 邮箱添加校验
1. 昵称 nickname 必须是2-10位的非空字符串
2. 邮箱 email 符合邮箱格式即可,且不能为空
- 完整代码和注释
//UserProfile.vu
<script setup>
import { useUserStore } from '@/stores'
import { ref } from 'vue'
//读取存在本地的user
// {id: 51452, username: "bear3", nickname: "", email: "", user_pic: null}
const {
user: { username, nickname, email, id }
} = useUserStore()
//step1:准备表单数据对象,用于双向绑定表单项的值
const userInfo = ref({ username, nickname, email, id })
// step2:准备校验规则的rules对象
const rules = {
nickname: [//昵称的校验规则:非空+正则
{ required: true, message: '请输入用户昵称', trigger: 'blur' },
{
pattern: /^\S{2,10}$/,
message: '昵称必须是2-10位的非空字符串',
trigger: 'blur'
}
],
email: [//邮箱的校验规则:非空+邮箱格式
{ required: true, message: '请输入用户邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
]
}
</script>
<template>
<page-container title="基本资料">
<el-row>
<el-col :span="12">
<!-- :model和:rules分别动态绑定userinfo和rules -->
<el-form :model="userInfo" :rules="rules" ref="formRef" label-width="100px" size="large">
<!-- 登录名称不用校验 -->
<el-form-item label="登录名称">
<el-input v-model="userInfo.username" disabled></el-input>
</el-form-item>
<!-- 用户昵称的校验:step3-配置props以示生效的是nickname规则 -->
<el-form-item label="用户昵称" prop="nickname">
<!-- step4:v-model动态绑定指定校验规则为rules中的nickname规则 -->
<el-input v-model="userInfo.nickname"></el-input>
<!-- 用户邮箱的校验:同上,略 -->
</el-form-item>
<el-form-item label="用户邮箱" prop="email">
<el-input v-model="userInfo.email"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">提交修改</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</page-container>
</template>
封装接口
//api/user.js
/*个人中心-基本资料*/
// 更新个人信息
export const userUpdateInfoService = ({ id, username, nickname }) => {
return request.put('/my/userinfo', { id, username, nickname })
}
页面调用
import { useUserStore, getUser } from '@/stores'
import { userUpdateInfoService } from '@/api/user'
const formRef = ref()
const onSubmit = async () => {
// 提交前预校验表单,返回布尔值
const valid = await formRef.value.validate()
if (valid) {//校验通过,发起修改用户信息的请求
await userUpdateInfoService(userInfo.value)//发起修改用户信息的请求
await getUser()//刷新用户信息
ElMessage.success('修改成功')
}
}
<el-button type="primary" @click="onSubmit">提交修改</el-button>
2.更换头像
更换头像页(user/UserAvatar.vue)有如下需求:
- 静态布局
- 选择更换的头像
- 实现新头像的上传
静态结构
<script setup>
import { ref } from 'vue'
import { Plus, Upload } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores'
const userStore = useUserStore()
const imgUrl = ref(userStore.user.user_pic)
const onUploadFile = (file) => {
console.log(file)
}
</script>
<template>
<page-container title="更换头像">
<el-row>
<el-col :span="12">
<el-upload ref="uploadRef" class="avatar-uploader" :auto-upload="false" :show-file-list="false"
:on-change="onUploadFile">
<img v-if="imgUrl" :src="imgUrl" class="avatar" />
<!-- <img v-else src="@/assets/avatar.jpg" width="278" /> -->
<img v-else width="278"
src="https://img2.baidu.com/it/u=2527990145,2068681281&fm=253&fmt=auto&app=138&f=PNG?w=500&h=500">
</el-upload>
<br />
<el-button type="primary" :icon="Plus" size="large">
选择图片
</el-button>
<el-button type="success" :icon="Upload" size="large">
上传头像
</el-button>
</el-col>
</el-row>
</page-container>
</template>
<style lang="scss" scoped>
.avatar-uploader {
:deep() {
.avatar {
width: 278px;
height: 278px;
display: block;
}
.el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 278px;
height: 278px;
text-align: center;
}
}
}
</style>
选择预览图片
const uploadRef = ref()// 拿到上传组件的实例
const imgUrl = ref(userStore.user.user_pic)// 头像地址
const onUploadFile = (file) => {// 文件上传前的回调函数
// 创建一个FileReader对象
const reader = new FileReader()
// 将文件读取为DataURL
reader.readAsDataURL(file.raw)
// 当文件读取完成后触发的事件处理函数
reader.onload = () => {
// 将读取到的文件内容赋值给imgUrl的value属性
imgUrl.value = reader.result
}
}
<!-- 点击选择图片时,会触发input的click事件, 这里通过js手动触发点击事件 -->
<el-button @click="uploadRef.$el.querySelector('input').click()" type="primary" :icon="Plus"
size="large">选择图片</el-button>
上传头像
- 封装接口
/*个人中心-更换头像*/
// 上传头像
export const userUploadAvatarService = ({ avatar }) => {
return request.patch('/my/update/avatar', { avatar })
}
- 页面调用
import { userUploadAvatarService } from '@/api/user'
import { useUserStore } from '@/stores'
// 点击事件: 更换头像
const onUpdateAvatar = async () => {
await userUploadAvatarService(imgUrl.value)// 调用上传头像的接口
await userStore.getUser()// 重新获取用户信息, 更新头像
ElMessage({ type: 'success', message: '更换头像成功' })
}
<el-button type="success" :icon="Upload" size="large" @click="onUpdateAvatar">
上传头像
</el-button>
3.重置密码
重置密码页(user/UserPassword.vue)有如下需求:
- 静态布局
- 三个文本框的校验
- 修改密码功能的实现
- 重置表单的实现
静态结构和校验
- deepseek搜索词prompt:
请基于 elementPlus 和 Vue3 的语法,生成组件代码
要求:
一、表单结构要求
1. 组件中包含一个el-form表单,有四行内容,前三行是表单输入框,第四行是两个按钮
2. 第一行 label 原密码
3. 第二行 label 新密码
4. 第三行 label 确认密码
5. 第四行两个按钮,修改密码 和 重置
二、form绑定字段如下:
const pwdForm = ref({
old_pwd: '',
new_pwd: '',
re_pwd: ''
})
三、校验需求
所有字段,都是 6-15位 非空
自定义校验1:原密码 和 新密码不能一样
自定义校验2:新密码 和 确认密码必须一样
- 获得的静态页面如下:
<script setup>
import { ref } from 'vue'
const pwdForm = ref({// 定义一个响应式对象pwdForm,用于存储表单数据
old_pwd: '',
new_pwd: '',
re_pwd: ''
})
const checkOldSame = (rule, value, cb) => {
// 判断新密码是否与旧密码相同
if (value === pwdForm.value.old_pwd) {
// 如果新密码与旧密码相同,则调用回调函数并传入错误信息
cb(new Error('原密码和新密码不能一样!'))
} else {
// 如果新密码与旧密码不同,则直接调用回调函数
cb()
}
}
const checkNewSame = (rule, value, cb) => {
// 判断输入的值是否与pwdForm中的new_pwd字段值不同
if (value !== pwdForm.value.new_pwd) {
// 如果不同,则回调cb并传入错误信息
cb(new Error('新密码和确认再次输入的新密码不一样!'))
} else {
// 如果相同,则直接调用cb,不传入任何参数
cb()
}
}
/*校验规则的四个步骤:略 */
const rules = {
old_pwd: [// 原密码校验:非空+长度校验
{ required: true, message: '请输入密码', trigger: 'blur' },
{
pattern: /^\S{6,15}$/,
message: '密码长度必须是6-15位的非空字符串',
trigger: 'blur'
}
],
new_pwd: [// 新密码校验:非空+长度校验+与旧密码不同(自定义校验规则)
{ required: true, message: '请输入新密码', trigger: 'blur' },
{
pattern: /^\S{6,15}$/,
message: '密码长度必须是6-15位的非空字符串',
trigger: 'blur'
},
{ validator: checkOldSame, trigger: 'blur' }
],
re_pwd: [// 确认新密码校验:非空+长度校验+与新密码相同(自定义校验规则)
{ required: true, message: '请再次确认新密码', trigger: 'blur' },
{
pattern: /^\S{6,15}$/,
message: '密码长度必须是6-15位的非空字符串',
trigger: 'blur'
},
{ validator: checkNewSame, trigger: 'blur' }
]
}
</script>
<template>
<page-container title="重置密码">
<el-row>
<el-col :span="12">
<el-form :model="pwdForm" :rules="rules" ref="formRef" label-width="100px" size="large">
<el-form-item label="原密码" prop="old_pwd">
<el-input v-model="pwdForm.old_pwd" type="password"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="new_pwd">
<el-input v-model="pwdForm.new_pwd" type="password"></el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="re_pwd">
<el-input v-model="pwdForm.re_pwd" type="password"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="onSubmit" type="primary">修改密码</el-button>
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</page-container>
</template>
封装接口
/*个人中心-修改密码*/
// 修改密码
export const userUpdatePassService = ({ old_pwd, new_pwd, re_pwd }) => {
return request.patch('/my/updatepwd', { old_pwd, new_pwd, re_pwd })
}
页面调用
await userUpdatePassService(pwdForm.value)
// 显示成功消息
ElMessage({ type: 'success', message: '更换密码成功' })
// 清空token
userStore.setToken('')
// 清空用户信息
userStore.setUser({})
// 重定向到登录页面
router.push('/login')
}
}
//点击重置表单
const onReset = () => {
formRef.value.resetFields()// 重置表单字段
}
<el-button @click="onSubmit" type="primary">修改密码</el-button>
<el-button @click="onReset">重置</el-button>