Vue3项目练习详细步骤(第五部分:用户模块的功能)

news2025/1/11 20:29:31

顶部导航栏个人信息显示

接口文档

接口请求与绑定 

导航栏下拉菜单功能

路由实现

退出登录和路由跳转实现

基本资料修改

页面结构

 接口文档

 接口请求与绑定 

修改头像

页面结构 

头像回显

头像上传

 接口文档

重置密码

页面结构

接口文档

接口请求与绑定

 

顶部导航栏个人信息显示

        在Layout.vue中,页面加载完就发送请求,获取个人信息展示,并存储到pinia中,因为将来在个人中心中修改信息的时候还需要使用 。

 接口文档

接口请求与绑定 

在stores目录下新建userInfo.js并定义Store用于将数据存储到pinia中

import { defineStore } from "pinia"
import {ref} from 'vue'

export const useUserInfoStore = defineStore('userInfo',()=>{
    //1.定义用户信息
    const info = ref({})
    //2.定义修改用户信息的方法
    const setInfo = (newInfo)=>{
        info.value = newInfo
    }
    //3.定义清空用户信息的方法
    const removeInfo = ()=>{
        info.value={}
    }

    return{info,setInfo,removeInfo}
},{
    persist:true
})

在user.js中提供获取个人信息的函数

//获取个人信息
export const userInfoGetService = ()=>{
    return request.get('/user/userInfo');
}

 在Layout.vue中获取个人信息,并存储到pinia中

//导入接口函数
import {userInfoGetService} from '@/api/user.js'
//导入pinia
import {useUserInfoStore} from '@/stores/userInfo.js'
const userInfoStore = useUserInfoStore();
import {ref} from 'vue'

//获取个人信息
const getUserInf = async ()=>{
    let result = await userInfoGetService();
    if(result.code === 0){
        //成功
        //存储pinia
        userInfoStore.info =result.data;
    }else{
        //失败
        alert('获取信息失败')
    }
}

getUserInf()

 Layout.vue的顶部导航栏中,绑定展示昵称和头像

<div>用户:<strong>{{ userInfoStore.info.nickname ? userInfoStore.info.nickname : userInfoStore.info.usrename }}</strong></div>

<el-avatar :src="userInfoStore.info.userPic ? userInfoStore.info.userPic : avatar" />

保存后刷新页面可以看到用户名称和头像正常显示 

 

导航栏下拉菜单功能

 在el-dropdown中有四个子条目

  • 基本资料
  • 更换头像
  • 重置密码
  • 退出登录

其中其三个起到路由功能,跟左侧菜单中【个人中心】下面的二级菜单是同样的功能,退出登录需要删除本地pinia中存储的token以及userInfo

路由实现

 在el-dropdown标签上绑定command事件,当有条目被点击后,会触发这个事件

<el-dropdown placement="bottom-end" @command="handleCommand">

在el-dropdown-item标签上添加command属性,属性值和路由表中/user/xxx保持一致

<el-dropdown-item command="info" :icon="User">基本资料</el-dropdown-item>
<el-dropdown-item command="avatar" :icon="Crop">更换头像</el-dropdown-item>
<el-dropdown-item command="password" :icon="EditPen">重置密码</el-dropdown-item>
<el-dropdown-item command="logout" :icon="SwitchButton">退出登录</el-dropdown-item>

退出登录和路由跳转实现

定义并编写handleCommand函数

import {useRouter} from 'vue-router'
const router = useRouter();
import {ElMessage,ElMessageBox} from 'element-plus'
import { useTokenStore } from '@/stores/token.js'
const tokenStore = useTokenStore()
const handleCommand = (command) => {
    if (command === 'logout') {
        //退出登录
        ElMessageBox.confirm(
            '是否退出登录',
            '提示',
            {
                confirmButtonText: '确认',
                cancelButtonText: '取消',
                type: 'warning',
            }
        )
            .then(async () => {
                //用户点击了确认
                //清空pinia中的token和个人信息
                userInfoStore.info={}
                tokenStore.token=''
                //跳转到登录页
                router.push('/login')
                ElMessage.success('成功退出登录')
            })
            .catch(() => {
                //用户点击了取消
                ElMessage({
                    type: 'info',
                    message: '取消退出',
                })
            })
    } else {
        //路由
        router.push('/user/' + command)
    }
}

 保存后刷新既可以完成跳转和退出登录

 

基本资料修改

页面结构

在UserInfo.vue文件中完成用户资料修改的页面结构组件

<script setup>
import { ref } from 'vue'
const userInfo = ref({
    id: 0,
    username: 'zhangsan',
    nickname: 'zs',
    email: 'zs@163.com',
})
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>
    <el-card class="page-container">
        <template #header>
            <div class="header">
                <span>基本资料</span>
            </div>
        </template>
        <el-row>
            <el-col :span="12">
                <el-form :model="userInfo" :rules="rules" label-width="100px" size="large">
                    <el-form-item label="登录名称">
                        <el-input v-model="userInfo.username" disabled></el-input>
                    </el-form-item>
                    <el-form-item label="用户昵称" prop="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>
    </el-card>
</template>

个人信息之前已经存储到了pinia中,只需要从pinia中获取个人信息,替换模板数据即可

import { ref } from 'vue'
//导入Store
import { useUserInfoStore } from '@/stores/userInfo.js';
const userInfoStore = useUserInfoStore()
//数据模型
const userInfo = ref({...userInfoStore.info}) //...用于展开可迭代对象 拆出其中的每个元素

 接口文档

 

 接口请求与绑定 

 在src/api/user.js中提供修改基本资料的函数

//修改个人信息
export const userInfoUpdateService = (userInfo)=>{
    return request.put('/user/update',userInfo)
}

在UserInfo.vue文件中提供updateUserInfo请求函数

//修改用户信息
import {userInfoUpdateService} from '@/api/user.js'
import { ElMessage } from 'element-plus';
const updateUserInfo = async ()=>{
    let result = await userInfoUpdateService(userInfo.value)
    ElMessage.success(result.message? result.message:'修改成功')
    //更新pinia中的数据
    userInfoStore.info.nickname=userInfo.value.nickname
    userInfoStore.info.email = userInfo.value.email
}

 给修改按钮绑定单击事件

<el-button type="primary" @click="updateUserInfo">提交修改</el-button>

 保存刷新后能正常完成用户信息的数据回显和更新

修改头像

页面结构 

在UserAvatar.vue文件中完成用户资料修改的页面结构组件

<script setup>
import { Plus, Upload } from '@element-plus/icons-vue'
import {ref} from 'vue'
import avatar from '@/assets/default.png'
const uploadRef = ref()

//用户头像地址
const imgUrl= avatar

</script>

<template>
    <el-card class="page-container">
        <template #header>
            <div class="header">
                <span>更换头像</span>
            </div>
        </template>
        <el-row>
            <el-col :span="12">
                <el-upload 
                    ref="uploadRef"
                    class="avatar-uploader" 
                    :show-file-list="false"
                    >
                    <img v-if="imgUrl" :src="imgUrl" class="avatar" />
                    <img v-else src="avatar" width="278" />
                </el-upload>
                <br />
                <el-button type="primary" :icon="Plus" size="large"  @click="uploadRef.$el.querySelector('input').click()">
                    选择图片
                </el-button>
                <el-button type="success" :icon="Upload" size="large">
                    上传头像
                </el-button>
            </el-col>
        </el-row>
    </el-card>
</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>

头像回显

 从pinia中读取用户的头像数据

//读取用户信息
//导入Store
import {useUserInfoStore} from '@/stores/userInfo.js'
const userInfoStore = useUserInfoStore()
//用户头像地址
const imgUrl=ref(userInfoStore.info.userPic)

img标签上绑定图片地址(三元运输符判断)

<img v-if="imgUrl" :src="imgUrl" class="avatar" />
<img v-else :src="avatar" width="278" />

 保存刷新查看头像回显

 

头像上传

  • action: 服务器接口路径
  • headers: 设置请求头,需要携带token
  • on-success: 上传成功的回调函数
  • name: 上传图片的字段名称

 为el-upload指定属性值

                <el-upload 
                    ref="uploadRef"
                    class="avatar-uploader" 
                    :show-file-list="false"
                    :auto-upload="true"
                    action="/api/upload"
                    name="'file'"
                    :headers="{'Authorization':tokenStore.token}"
                    :on-success="uploadSuccess"
                    >

 提供上传成功的回调函数

//导入tokenStore
import {useTokenStore} from '@/stores/token.js'

const tokenStore = useTokenStore();
//头像上传成功回调函数
const uploadSuccess = (result)=>{
    //回显图片
    imgUrl.value = result.data
}

 接口文档

 接口请求与绑定

在user.js中提供修改头像的函数

//修改头像
export const userAvatarUpdateService=(avatarUrl)=>{
    let params = new URLSearchParams();
    params.append('avatarUrl',avatarUrl)
    return request.patch('/user/updateAvatar',params)
}

在UserAvatar.vue文件中提供updateAvatar函数,完成头像更新  

//调用接口,更新头像url
import {userAvatarUpdateService} from '@/api/user.js'
//导入Element-Plus提示框组件
import {ElMessage} from 'element-plus'
const updateAvatar = async ()=>{
    let result = await userAvatarUpdateService(imgUrl.value)
    if(result.code === 0){
        //成功
        ElMessage.success(result.message? result.message:'修改成功')
        //更新pinia中的数据
        userInfoStore.info.userPic=imgUrl.value
    }else{
        ElMessage.error('修改失败')
    }

}

 在【上传头像】按钮绑定单击事件

<el-button type="success" :icon="Upload" size="large" @click="updateAvatar">
上传头像
</el-button>

如果是用的网络存储服务器那么到这一步修改头像就完成了!

练习项目后端使用的是本地文件存储,所以没有用到网络url,传入本地文件地址后端会报如下错误

 

点击上传由于这里练习项目没有网络服务器 数据是上传到本地的所以浏览器会拦截本地文件加载导致不能造成数据回显,但是目录下是有图片成功上传到的。

后续继续完成项目建议修改src中的值为模拟的固定网络图片url地址:https://ts1.cn.mm.bing.net/th/id/R-C.4bdc8f7f0e0201905fe400fb5156b7c7?rik=MVFo1SU7cYgFqg&riu=http%3A%2F%2Fwww.spasvo.com%2Fckfinder%2Fuserfiles%2Fimages%2F2020061536450116.jpg&ehk=r7Pp%2FX3wIOhP%2FcuW0ITLAHeD0sZPNatsyfpC3XWOM0s%3D&risl=&pid=ImgRaw&r=0

  如果自己有网络服务器可以使用网络服务器的图片url

 

重置密码

页面结构

在UserResetPassword.vue文件中完成重置密码的页面的结构组件 

<script setup>
import { ref } from 'vue'
const password = ref({
"old_pwd":"",
"new_pwd":"",
"re_pwd":""
})
const rules = {
    oldPassword: [
        { required: true, message: '请输入原密码', trigger: 'blur' },
        {
            pattern: /^\S{5,12}$/,
            message: '密码必须是5-12位的非空字符串',
            trigger: 'blur'
        }
    ],
    newPassword: [
        { required: true, message: '请输入新密码', trigger: 'blur' },
        {
            pattern: /^\S{5,12}$/,
            message: '密码必须是5-12位的非空字符串',
            trigger: 'blur'
        }
    ],
    rePassword: [
        { required: true, message: '请输入确认新密码', trigger: 'blur' },
        {
            pattern: /^\S{5,12}$/,
            message: '密码必须是5-12位的非空字符串',
            trigger: 'blur'
        }
    ]

}
</script>
<template>
    <el-card class="page-container">
        <template #header>
            <div class="header">
                <span>重置密码</span>
            </div>
        </template>
        <el-row>
            <el-col :span="12">
                <el-form :model="password" :rules="rules" label-width="100px" size="large">
                    <el-form-item label="原密码" prop="oldPassword">
                        <el-input type="password" placeholder="请输入原密码" show-password v-model="password.old_pwd"></el-input>
                    </el-form-item>
                    <el-form-item label="新密码" prop="newPassword">
                        <el-input type="password" placeholder="请输入新密码" show-password v-model="password.new_pwd"></el-input>
                    </el-form-item>
                    <el-form-item label="确认新密码" prop="rePassword">
                        <el-input type="password" placeholder="请输入确认密码" show-password v-model="password.re_pwd"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary">修改密码</el-button>
                        <el-button type="primary">重置</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </el-card>
</template>

 定义清空数据模型的函数

在重置按钮处绑定清空文本框数据的单击事件

<el-button type="primary" @click="clearData()">重置</el-button>

接口文档

接口请求与绑定

  在src/api/user.js中提供重置密码的函数

//重置密码
export const userPasswordUpdateService = (password) => {
    return request.patch('/user/updatePwd',password)
}

 在UserResetPassword.vue文件中提供userPasswordUpdate请求函数

//导入路由
import {useRouter} from 'vue-router'
const router = useRouter();
//导入element提示框组件
import { ElMessage,ElMessageBox } from 'element-plus';
//导入userPasswordUpdateService函数
import {userPasswordUpdateService} from '@/api/user.js'

const userPasswordUpdate = async() => {
    ElMessageBox.confirm(
        '确认是否重置密码,重置之后将退出登录',
        '提示',
        {
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning',
        }
    )
        .then(async () => {
            //用户点击了确认
            let result = userPasswordUpdateService(password.value)
            if(result.code ===0){
                //成功
                //跳转到登录页
                router.push('/login')
                ElMessage.success(result.message?result.message:'重置成功')
                ElMessage.success('退出登录')
            }else{
                ElMessage.error('操作失败')
            }
        })
        .catch(() => {
            //用户点击了取消
            ElMessage({
                type: 'info',
                message: '取消重置',
            })
        })
}

 在修改密码按钮处绑定该函数单击事件

<el-button type="primary" @click="userPasswordUpdate()">修改密码</el-button>

 保存后查看效果

项目练习完结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1718671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决MYSQL5.7版本only_full_group_by报错解决方法

问题 出现this is incompatible with sql_modeonly_full_group_by这个语句就说明启动了only_full_group_by规则了 介绍only_full_group_by规则&#xff1a; 这种情况可能是5.7版本的规则比较严格&#xff0c;当启用“only_full_group_by”模式时&#xff0c;MySQL会对执行GROU…

AdroitFisherman模块安装日志(2024/5/31)

安装指令 pip install AdroitFisherman-0.0.29.tar.gz -v 安装条件 1:Microsoft Visual Studio Build Tools 2:python 3.10.x 显示输出 Using pip 24.0 from C:\Users\12952\AppData\Local\Programs\Python\Python310\lib\site-packages\pip (python 3.10) Processing c:\u…

ChatGPT AI专题资料合集【65GB】

介绍 ChatGPT & AI专题资料合集【65GB】 &#x1f381;【七七云享】资源仓库&#xff0c;海量资源&#xff0c;无偿分享√

SpringMVC框架学习笔记(三):url请求风格-Rest 以及 SpringMVC 映射获取到各种类型数据

1 Rest 基本介绍 1.1 基本说明 REST&#xff1a;即 Representational State Transfer。(资源)表现层状态转化。是目前流行的请求方 式。它结构清晰, 很多网站采用 HTTP 协议里面&#xff0c;四个表示操作方式的动词&#xff1a;GET、POST、PUT、DELETE。它们分别对应四种基本…

音视频开发14 FFmpeg 视频 相关格式分析 -- H264 NALU格式分析

H264简介-也叫做 AVC H.264&#xff0c;在MPEG的标准⾥是MPEG-4的⼀个组成部分–MPEG-4 Part 10&#xff0c;⼜叫Advanced Video Codec&#xff0c;因此常常称为MPEG-4 AVC或直接叫AVC。 原始数据YUV,RGB为什么要压缩-知道就行 在⾳视频传输过程中&#xff0c;视频⽂件的传输…

flume-ng-sql | 支持JDK8+ | 支持Flume 1.11.0 | 使用 Kotlin 编写

文章目录 简介用法 简介 flume-ng-sql-source 作者已经停止维护了&#xff0c;并且已经不支持新版Flume&#xff0c;我们决定开启这一项目 flume-ng-sql。 用法 像 flume-ng-sql-source 一样将 flume-ng-sql 发行的 Jar 包导入lib下&#xff0c;必要时需要添加自己 MySQL 版本…

Mybatis 查询TypeHandler使用,转译查询数据(逗号分隔转List)

创建自定义的Hanndler /*** Package: com.datalyg.common.core.handler* ClassName: CommaSeparatedStringTypeHandler* Author: dujiayu* Description: 用于mybatis 解析逗号拼接字符串* Date: 2024/5/29 10:03* Version: 1.0*/ public class CommaSeparatedStringTypeHandle…

在PostGIS中检查孤线(Find isolated lines in PostGIS)

场景 在PostGIS中有一张线要素表,需要检查该表中的孤线,并且进行自动纠正的计算。 其中孤线定义为两端端点都不在任何其他线的顶点上。 本文介绍在PostGIS中的线要素点,通过函数计算指定线要素表中的孤线,并计算最接近的纠偏位置。 In PostGIS, there is a table of line …

MMrotate报错AttributeError: ‘NoneType‘ object has no attribute ‘shape‘

使用MMrotate训练自定义数据集报错&#xff1a; AttributeError: ‘NoneType’ object has no attribute ‘shape’ 2024-05-31 17:48:06,121 - mmrotate - INFO - workflow: [(train, 1)], max: 12 epochs 2024-05-31 17:48:06,121 - mmrotate - INFO - Checkpoints will be …

nacos连接异常did not find the Leader node;

目录 问题描述解决过程持久化节点真的是存在数据库吗&#xff1f; 问题描述 我搭建的是nacos伪集群&#xff0c;然后主要想着看看集群情况下&#xff0c;临时节点和持久节点的区别。 如果使用临时节点项目能够正常起来&#xff0c;一旦添加ephemeral: false项目就起不来了。 …

【linux】自定义快捷命令/脚本

linux自定义快捷命令 场景自定义命令自定义脚本 场景 深度学习经常要切换到自己环境&#xff0c;conda activate mmagic&#xff0c;但是又不想每次重复打这么多字&#xff0c;想使用快捷命令直接切换。 自定义命令 使用别名&#xff08;alias&#xff09;或自定义脚本来创建…

打造你的首个QT 5计算器应用

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;QT 5的力量与我们的计算器 二、QT 5基础&#xff1a;理解UI设计与文件…

Go微服务: 基于Docker搭建Kong网关环境

概述 在当今的微服务架构中&#xff0c;API网关扮演着至关重要的角色&#xff0c;它作为系统的统一入口负责处理所有内外部请求&#xff0c;实现路由转发、负载均衡、安全控制、限流熔断等多种功能Kong&#xff0c;作为一个开源、高性能、可扩展的API网关&#xff0c;凭借其强…

vscode 远程连接出现问题

终端太小了&#xff0c; 因为终端中有换行符&#xff0c;如果 终端太小会出现问题

【AI+知识库问答】沉浸式体验了解 AI知识库问答fastGPT

之前写过一篇文章 【AI本地知识库】个人整理的几种常见本地知识库技术方案 &#xff0c; 由于当时主要是针对AI本地知识库&#xff0c; 所以没列fastGPT。 最近经常刷到fastGPT&#xff0c;这里单独水一篇。 FastGPT 是一个基于 LLM 大语言模型的知识库问答系统&#xff0c;…

基于Cloudflare/CloudDNS/GitHub使用免费域名部署NewBing的AI服务

部署前准备&#xff1a; Cloudflare 账号 https://dash.cloudflare.com/login CloudDNS 账号 https://www.cloudns.net/ GitHub 账号 https://github.com/Harry-zklcdc/go-proxy-bingai Cloudflare 部署 Worker CloudDNS 获取免费二级域名 GitHub New Bing Ai 项目 https://git…

C++ 快排算法

今天看到一种清爽的快速算法&#xff0c;复习一下~ 快速排序算法的平均时间复杂度是O(n log n)&#xff0c;最坏情况下的时间复杂度是O(n^2)。 快速排序的最佳情况是每次分割都平均分配元素&#xff0c;这种情况下时间复杂度可降至O(n log n)。 快速排序的基本步骤如下&#…

qwen-moe

一、定义 qwen-moe 代码讲解&#xff0c; 代码qwen-moe与Mixtral-moe 一样&#xff0c; 专家模块qwen-moe 开源教程Mixture of Experts (MoE) 模型在Transformer结构中如何实现&#xff0c;Gate的实现一般采用什么函数&#xff1f; Sparse MoE的优势有哪些&#xff1f;MoE是如…

【智能算法】三角拓扑聚合优化算法(TTAO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年&#xff0c;S Zhao受到数学相似三角形拓扑结构启发&#xff0c;提出了三角拓扑聚合优化算法&#xff08;Triangulation Topology Aggregation Optimizer, TTAO&#xff09;。 2.算…

Unity中的MVC框架

基本概念 MVC全名是Model View Controller 是模型(model)-视图(view)-控制器(controller)的缩写 是一种软件设计规范&#xff0c;用一种业务逻辑、数据、界面显示 分离的方法组织代码 将业务逻辑聚集到一个部件里面&#xff0c;在改进和个性化定制界面及用户交互的同时&#x…