【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)

目录

一、环境准备

1、创建Vue工程

2、安装依赖 

2.1 安装项目所需要的vue依赖 

2.2 安装element-plus依赖

2.2.1 安装

2.2.2 项目导入element-plus

2.3 安装axios依赖

2.4 安装sass依赖

3、目录调整

3.1 删除部分默认目录下文件

3.1.1 src/components下自动生成的内容(删除文件夹下全部内容)

3.1.2 src/assets 下自动生成的内容(删除文件夹下全部内容) 

3.2 api、utils、views目录处理

3.2.1 src下新建目录api、utils、views

 3.2.2 utils下新增request.js文件

3.3 将资料中的静态资源拷贝到assets目录下

3.4 修改app.vue生成的内容

4、启动项目验证

二、注册功能

1、页面搭建 

1.1 views下新建Login.vue

1.2 App.vue导入Login.vue

1.3 查看结果

2、为注册页面绑定数据与事件

2.1 定义数据模型Login.vue

 2.2 注册页面Login.vue表单校验

2.3 验证

3、注册页面后台接口调用 

3.1 启动后端服务

3.2 api目录下新建user.js文件

3.3 Login.vue页面完成调用

4、跨域问题解决

4.1 request.js

4.2 vite.config.js

5、测试验证

三、登录功能

1、登录Login.vue绑定数据 

2、 登录Login.vue数据校验

3、登录页面后端接口调用

3.1 user.js提供登录调用接口

3.2 Login.vue调用后端接口

4、测试验证

5、优化登录表单与注册表单数据显示问题(Login.vue)

四、优化axios响应拦截器与alert

1、axios响应拦截器

2.1 request.js 

2.2 优化Login.vue

2、使用element-plus优化alert

2.1 request.js引用ElMessage 组件处理

2.2  Login.vue引用ElMessage 组件处理

五、主页面布局 

1、Layout页面

1.1 views下新增Layout.vue

 1.2 App.vue导入Layout.vue

2、路由

 2.1 安装vue-router

2.2 创建路由器index.js

2.3 在main.js使用vue-router

2.4 App.vue中声明router-view标签

2.5  Login.vue优化登录成功跳转

2.6 测试验证

3、子路由

3.1 views下创建vue文件 

3.1.1 ArticleCategory.vue

3.1.2 ArticleManage.vue

3.1.3 UserAvatar.vue

3.1.4 UserInfo.vue

3.1.5 UserResetPassword.vue

3.2 index.js

3.3 Layout.vue声明router-view标签

3.4 测试验证

六、文章分类 

1、列表查询

1.1 article.js

1.2 ArticleCategory.vue

2、Pinia状态管理库

2.1 安装pinia

2.2 main.js导入pinia

2.3 定义store

2.4 使用Store

2.5 测试验证

 3、 使用axios请求拦截器解决token繁琐问题

​编辑 3.1 request.js添加请求拦截器

3.2 article.js移除之前添加的请求头

4、pinia-persistedstate-plugin持久化插件

4.1 安装

4.2 pinia中使用persist插件

4.3 在创建定义状态是配置持久化

5、未登录统一处理

6、添加文章分类

6.1  ArticleCategory.vue

6.2 在article.js中提供添加分类的函数

6.3 测试验证

7、修改文章分类 

7.1 修改分类弹窗页面

7.1.1 弹窗标题显示  ArticleCategory.vue

7.1.2 在弹窗上绑定标题 ArticleCategory.vue

7.1.3 为添加分类按钮绑定事件 ArticleCategory.vue

7.1.4 为修改分类按钮绑定事件 ArticleCategory.vue

7.2 修改数据回显 ArticleCategory.vue

7.3 修改文章分类接口调用

7.3.1 article.js中提供修改分类的函数

7.3.2 修改确定按钮的绑定事件 ArticleCategory.vue

7.3.3 调用接口完成修改的函数  ArticleCategory.vue

7.3.4 优化添加时数据回显

8、删除文章分类

 8.1 删除接口

8.2 删除确认框

 8.3 为删除按钮绑定事件

8.4 调用删除接口

8.5 测试验证

七、文章列表 

1、 文章列表查询

 1.1 文章列表页面组件ArticleManage.vue

1.2 解决分页控件英文显示问题main.js

1.3 文章分类数据回显ArticleMange.vue  

1.4 文章列表接口调用

1.4.1 article.js中提供获取文章列表数据的函数

1.4.2 ArticleManage.vue中,调用接口获取数据

1.4.3 当分页条的当前页和每页条数发生变化,重新发送请求获取数据

2 、搜索和重置

3、添加文章

3.1 添加文章抽屉组件

3.2 为添加文章按钮添加单击事件,展示抽屉

3.3 富文本编辑器

3.3.1 安装:

3.3.2 导入组件和样式:

3.3.3 页面使用quill组件:​

3.3.4 样式美化:

3.4 文章封面图片上传

3.5 添加文章接口调用

3.5.1 article.js中提供添加文章函数

3.5.2 为已发布和草稿按钮绑定事件

3.5.3 ArticleManage.vue中提供addArticle函数完成添加文章接口的调用

4、编辑文章

4.1 修改文章抽屉页面

4.1.1 抽屉标题显示 定义标题

4.1.2 在抽屉上绑定标题

4.1.3 为添加文章按钮绑定事件

4.1.4 为修改文章按钮绑定事件

4.2 数据回显

4.2.1 通过插槽的方式得到被点击按钮所在行的数据

4.2.2 回显函数

4.3 修改文章接口调用

4.3.1 article.js中提供修改文章的函数

4.3.2 修改发布与草稿按钮的绑定事件

4.3.3 调用接口完成修改的函数

5、删除文章

5.1 接口调用

5.2 为删除按钮绑定事件

5.3 添加删除弹窗,当用户点击确认后,调用接口删除分类

八、顶部导航栏信息展示

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

2、 src/stores/userInfo.js中,定义个人中心状态

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

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

九 、页面右上角下拉菜单el-dropdown中功能实现

1、路由实现:

2、 退出登录实现:

十、基本资料修改

1、 基本资料页面组件UserInfo.vue

2、 表单数据回显

3、 接口调用

十一、修改头像

1、 修改头像页面组件UserAvatar.vue

2、 头像回显

3、 头像上传

4、 上传头像接口调用

十二、 重置密码

1、user.js 重置密码

 2、UserResetPassword.vue


前言:本项目的终结篇,是一名vue3完成本次课程的前端页面。

一、环境准备

1、创建Vue工程

npm init vue@latest

# 项目名称spring3vue3project

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第1张图片

2、安装依赖 

进入到创建项目目录

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第2张图片

2.1 安装项目所需要的vue依赖 

# 项目所需要的vue依赖
npm install

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第3张图片

2.2 安装element-plus依赖

2.2.1 安装
# 安装element-plus依赖
npm install element-plus --save

2.2.2 项目导入element-plus

打开项目 

code .

修改src/main.js 

import './assets/main.scss'

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'


import App from './App.vue'

const app = createApp(App)
app.use(ElementPlus)

app.mount('#app')

2.3 安装axios依赖

npm install axios

2.4 安装sass依赖

# 安装sass依赖 好像是关于css的
npm install sass -D

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第4张图片

3、目录调整

直接进到项目文件夹下操作

3.1 删除部分默认目录下文件

3.1.1 src/components下自动生成的内容(删除文件夹下全部内容)

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第5张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第6张图片

3.1.2 src/assets 下自动生成的内容(删除文件夹下全部内容) 

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第7张图片

3.2 api、utils、views目录处理

3.2.1 src下新建目录api、utils、views

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第8张图片

 3.2.2 utils下新增request.js文件
// 定制请求实例

//导入axios
import axios from 'axios'; 

//定义一个变量,记录公共的前缀baseURL
const baseURL = 'http://localhost:8080'
const instance = axios.create({baseURL})

// 添加响应拦截器
instance.interceptors.response.use(
    result=>{
        return result.data;

    },
    err=>{
        alert('服务异常')
        return Promise.reject(err);//异步的状态转化成失败的状态
    }
)

export default instance;

3.3 将资料中的静态资源拷贝到assets目录下

如需,关注,发私信

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第9张图片

3.4 修改app.vue生成的内容

删除app.vue中自动生成的内容







4、启动项目验证

npm run dev

二、注册功能

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第10张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第11张图片 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第12张图片

1、页面搭建 

1.1 views下新建Login.vue





1.2 App.vue导入Login.vue







1.3 查看结果

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第13张图片

2、为注册页面绑定数据与事件

2.1 定义数据模型Login.vue





 2.2 注册页面Login.vue表单校验

表单校验可看官网





2.3 验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第14张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第15张图片

3、注册页面后台接口调用 

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第16张图片

3.1 启动后端服务

启动前面章节后端服务以及redis 

3.2 api目录下新建user.js文件

//导入request.js请求工具
import request from '@/utils/request.js'

// 提供调用注册接口的函数
export const userRegisterService = (registerData) =>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in registerData){
        params.append(key,registerData[key]);
    }
    return request.post('/user/register',params);
    
}

3.3 Login.vue页面完成调用





验证,存在跨域问题

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第17张图片

4、跨域问题解决

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第18张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第19张图片

4.1 request.js

// 定制请求实例

//导入axios  npm install axios
import axios from 'axios';

//定义一个变量,记录公共的前缀baseURL
// const baseURL = 'http://localhost:8080'  
const baseURL = '/api'          // 注释上面代码,解决跨域问题
const instance = axios.create({baseURL})

// 添加响应拦截器
instance.interceptors.response.use(
    result=>{
        return result.data;

    },
    err=>{
        alert('服务异常')
        return Promise.reject(err);//异步的状态转化成失败的状态
    }
)

export default instance;

4.2 vite.config.js

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
  ,
  // server 部分都是为了解决跨域问题
  server:{
    proxy:{
      '/api':{//获取路径中包含了/api的请求
          target:'http://localhost:8080',//后台服务所在的源
          changeOrigin:true,//修改源
          rewrite:(path)=>path.replace(/^\/api/,'')///api替换为''
      }
    }
  }
})

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第20张图片

5、测试验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第21张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第22张图片

三、登录功能

 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第23张图片

1、登录Login.vue绑定数据 





2、 登录Login.vue数据校验





3、登录页面后端接口调用

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第24张图片

3.1 user.js提供登录调用接口

//导入request.js请求工具
import request from '@/utils/request.js'

// 二  注册函数  提供调用注册接口的函数
export const userRegisterService = (registerData) =>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in registerData){
        params.append(key,registerData[key]);
    }
    return request.post('/user/register',params);
    
}

// 三  登录函数 提供调用登录接口的函数
export const userLoginService = (loginData)=>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in loginData){
        params.append(key,loginData[key]);
    }
    return request.post('/user/login',params);

}

3.2 Login.vue调用后端接口





4、测试验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第25张图片

 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第26张图片

5、优化登录表单与注册表单数据显示问题(Login.vue)





四、优化axios响应拦截器与alert

1、axios响应拦截器

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第27张图片

2.1 request.js 

(上图右侧的文件名错误)

// 定制请求实例

//导入axios  npm install axios
import axios from 'axios';

//定义一个变量,记录公共的前缀baseURL
// const baseURL = 'http://localhost:8080'  
const baseURL = '/api'          // 注释上面代码,解决跨域问题
const instance = axios.create({baseURL})

// 添加响应拦截器
instance.interceptors.response.use(
    result=>{
        // 判断业务状态码
        if(result.data.code === 1){
            //成功,正常返回数据
            return result.data;
        }
        // 操作失败
        alert(result.data.msg?result.data.msg : '服务异常')
        // 异步操作的状态转换为失败
        return Promise.reject(result.data)

    },
    err=>{
        alert('服务异常')
        return Promise.reject(err);//异步的状态转化成失败的状态
    }
)

export default instance;

2.2 优化Login.vue





2、使用element-plus优化alert

2.1 request.js引用ElMessage 组件处理

// 定制请求实例

//导入axios  npm install axios
import axios from 'axios';
// 四 4.2 element-plus封装的组件
import { ElMessage } from 'element-plus';

//定义一个变量,记录公共的前缀baseURL
// const baseURL = 'http://localhost:8080'  
const baseURL = '/api'          // 注释上面代码,解决跨域问题
const instance = axios.create({baseURL})

// 添加响应拦截器
instance.interceptors.response.use(
    result=>{
        // 四  4.1 判断业务状态码
        if(result.data.code === 1){
            //成功,正常返回数据
            return result.data;
        }
        // 操作失败
        // alert(result.data.msg?result.data.msg : '服务异常')  
        // 四 4.2 优化alert
        ElMessage.error(result.data.msg?result.data.msg : '服务异常')
        // 异步操作的状态转换为失败
        return Promise.reject(result.data)

    },
    err=>{
        alert('服务异常')
        return Promise.reject(err);//异步的状态转化成失败的状态
    }
)

export default instance;

2.2  Login.vue引用ElMessage 组件处理





【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第28张图片

五、主页面布局 

1、Layout页面

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第29张图片

1.1 views下新增Layout.vue





 1.2 App.vue导入Layout.vue







2、路由

 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第30张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第31张图片

 2.1 安装vue-router

npm install vue-router@4

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第32张图片

2.2 创建路由器index.js

src下新增router文件夹,在router下新增index.js

import { createRouter, createWebHistory } from 'vue-router'

//导入组件
import LoginVue from '@/views/Login.vue'
import LayoutVue from '@/views/Layout.vue'



//定义路由关系
const routes = [
    { path: '/login', component: LoginVue },
    { path: '/', component: LayoutVue }  
]

//创建路由器
const router = createRouter({
    history: createWebHistory(),
    routes: routes
})

//导出路由
export default router

2.3 在main.js使用vue-router

import './assets/main.scss'  // 本项目使用sass

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//五 2.3 
import router from '@/router'


import App from './App.vue'


const app = createApp(App)
//五 2.3 
app.use(router)


app.use(ElementPlus)
app.mount('#app')

2.4 App.vue中声明router-view标签







2.5  Login.vue优化登录成功跳转





2.6 测试验证

登录页面:   http://127.0.0.1:5173/login

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第33张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第34张图片

3、子路由

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第35张图片

 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第36张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第37张图片

3.1 views下创建vue文件 

 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第38张图片

3.1.1 ArticleCategory.vue
3.1.2 ArticleManage.vue
3.1.3 UserAvatar.vue
3.1.4 UserInfo.vue
3.1.5 UserResetPassword.vue

3.2 index.js

import { createRouter, createWebHistory } from 'vue-router'

//导入组件
import LoginVue from '@/views/Login.vue'
import LayoutVue from '@/views/Layout.vue'

import ArticleCategoryVue from '@/views/article/ArticleCategory.vue'
import ArticleManageVue from '@/views/article/ArticleManage.vue'
import UserAvatarVue from '@/views/user/UserAvatar.vue'
import UserInfoVue from '@/views/user/UserInfo.vue'
import UserResetPasswordVue from '@/views/user/UserResetPassword.vue'

//定义路由关系
const routes = [
    { path: '/login', component: LoginVue },
    {
        path: '/', component: LayoutVue,redirect:'/article/manage', children: [
            { path: '/article/category', component: ArticleCategoryVue },
            { path: '/article/manage', component: ArticleManageVue },
            { path: '/user/info', component: UserInfoVue },
            { path: '/user/avatar', component: UserAvatarVue },
            { path: '/user/resetPassword', component: UserResetPasswordVue }
        ]
    }
]

//创建路由器
const router = createRouter({
    history: createWebHistory(),
    routes: routes
})

//导出路由
export default router

3.3 Layout.vue声明router-view标签





3.4 测试验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第39张图片

六、文章分类 

1、列表查询

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第40张图片

1.1 article.js

api下新建article.js

//导入request.js请求工具
import request from '@/utils/request.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    return request.get('/category');
    
}

1.2 ArticleCategory.vue




此时页面访问存在token问题

2、Pinia状态管理库

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第41张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第42张图片

2.1 安装pinia

npm install pinia

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第43张图片

2.2 main.js导入pinia

在main.js中,引入pinia,创建pinia实例,并调用vue应用实例的use方法使用pinia

import './assets/main.scss'  // 本项目使用sass

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//五 2.3 
import router from '@/router'


import App from './App.vue'
//六 2.2
import {createPinia} from 'pinia'

const app = createApp(App)
//六 2.2
const pinia = createPinia();
app.use(pinia)
//五 2.3 
app.use(router)


app.use(ElementPlus)
app.mount('#app')

2.3 定义store

在src/stores目录下定义token.js

//定义store
import {defineStore} from 'pinia'
import {ref} from 'vue'
/* 
    第一个参数:名字,唯一性
    第二个参数:函数,函数的内部可以定义状态的所有内容

    返回值: 函数
*/
export const useTokenStore = defineStore('token',()=>{
    //定义状态的内容

    //1.响应式变量
    const token = ref('')

    //2.定义一个函数,修改token的值
    const setToken = (newToken)=>{
        token.value = newToken
    }

    //3.函数,移除token的值
    const removeToken = ()=>{
        token.value=''
    }

    return {
        token,setToken,removeToken
    }
});

2.4 使用Store

在需要使用状态的地方,导入@/stores/*.js , 使用即可

在Login.vue中导入@/stores/token.js, 并且当用户登录成功后,将token保存pinia中





在article.js中导入@/stores/token.js, 从pinia中获取到存储的token,在发起查询文章分类列表的时候把token通过请求头的形式携带给服务器

//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
}

2.5 测试验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第44张图片

 3、 使用axios请求拦截器解决token繁琐问题

当进入主页后,将来要与后台交互,都需要携带token,如果每次请求都写这样的代码,将会比较繁琐,此时可以将携带token的代码通过请求拦截器统一处理

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第45张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第46张图片 3.1 request.js添加请求拦截器

在 src/util/request.js中

// 定制请求实例

//导入axios  npm install axios
import axios from 'axios';
// 四 4.2 element-plus封装的组件
import { ElMessage } from 'element-plus';

// 六  3 导入token状态
import { useTokenStore } from '@/stores/token.js';

//定义一个变量,记录公共的前缀baseURL
// const baseURL = 'http://localhost:8080'  
const baseURL = '/api'          // 注释上面代码,解决跨域问题
const instance = axios.create({baseURL})
//六  3 添加请求拦截器
instance.interceptors.request.use(
    (config)=>{
        //在发送请求之前做什么
        let tokenStore = useTokenStore()
        //如果token中有值,在携带
        if(tokenStore.token){
            config.headers.Authorization=tokenStore.token
        }
        return config
    },
    (err)=>{
        //如果请求错误做什么
        Promise.reject(err)
    }
)

// 添加响应拦截器
instance.interceptors.response.use(
    result=>{
        // 四  4.1 判断业务状态码
        if(result.data.code === 1){
            //成功,正常返回数据
            return result.data;
        }
        // 操作失败
        // alert(result.data.msg?result.data.msg : '服务异常')  
        // 四 4.2 优化alert
        ElMessage.error(result.data.msg?result.data.msg : '服务异常')
        // 异步操作的状态转换为失败
        return Promise.reject(result.data)

    },
    err=>{
        alert('服务异常')
        return Promise.reject(err);//异步的状态转化成失败的状态
    }
)

export default instance;

3.2 article.js移除之前添加的请求头

//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

4、pinia-persistedstate-plugin持久化插件

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第47张图片

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第48张图片

4.1 安装

npm install pinia-persistedstate-plugin

4.2 pinia中使用persist插件

在main.js中

import './assets/main.scss'  // 本项目使用sass

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//五 2.3 
import router from '@/router'


import App from './App.vue'
//六 2.2
import {createPinia} from 'pinia'

// 六  4.2 导入持久化插件
import {createPersistedState} from'pinia-persistedstate-plugin'

const app = createApp(App)
//六 2.2
const pinia = createPinia();
// 六  4.2
const persist = createPersistedState()
//六  4.2 pinia使用持久化插件
pinia.use(persist)
app.use(pinia)
//五 2.3 
app.use(router)


app.use(ElementPlus)
app.mount('#app')

4.3 在创建定义状态是配置持久化

在src/stores/token.js中

//定义store
import {defineStore} from 'pinia'
import {ref} from 'vue'
/* 
    第一个参数:名字,唯一性
    第二个参数:函数,函数的内部可以定义状态的所有内容

    返回值: 函数
*/
export const useTokenStore = defineStore('token',()=>{
    //定义状态的内容

    //1.响应式变量
    const token = ref('')

    //2.定义一个函数,修改token的值
    const setToken = (newToken)=>{
        token.value = newToken
    }

    //3.函数,移除token的值
    const removeToken = ()=>{
        token.value=''
    }

    return {
        token,setToken,removeToken
    }
},{
    persist:true//  六 4.3持久化存储
});

5、未登录统一处理

在后续访问接口时,如果没有登录,则前端不携带token,后台服务器会返回响应状态码401,代表未登录,此时可以在axios的响应拦截器中,统一对未登录的情况做处理request.js

// 定制请求实例

//导入axios  npm install axios
import axios from 'axios';
// 四 4.2 element-plus封装的组件
import { ElMessage } from 'element-plus';

// 六  3.1 导入token状态
import { useTokenStore } from '@/stores/token.js';

// 六 5  导入路由跳转到首页
import router from '@/router'

//定义一个变量,记录公共的前缀baseURL
// const baseURL = 'http://localhost:8080'  
const baseURL = '/api'          // 注释上面代码,解决跨域问题
const instance = axios.create({baseURL})
//六  3 添加请求拦截器
instance.interceptors.request.use(
    (config)=>{
        //在发送请求之前做什么
        let tokenStore = useTokenStore()
        //如果token中有值,在携带
        if(tokenStore.token){
            config.headers.Authorization=tokenStore.token
        }
        return config
    },
    (err)=>{
        //如果请求错误做什么
        Promise.reject(err)
    }
)

// 添加响应拦截器
instance.interceptors.response.use(
    result=>{
        // 四  4.1 判断业务状态码
        if(result.data.code === 1){
            //成功,正常返回数据
            return result.data;
        }
        // 操作失败
        // alert(result.data.msg?result.data.msg : '服务异常')  
        // 四 4.2 优化alert
        // ElMessage.error(result.data.msg?result.data.msg : '服务异常')
        ElMessage.error(result.data.msg || '服务异常')
        // 异步操作的状态转换为失败
        return Promise.reject(result.data)

    },
    err=>{
       // 六 5  如果响应状态码时401,代表未登录,给出对应的提示,并跳转到登录页
       if(err.response.status===401){
        ElMessage.error('请先登录!')
        router.push('/login')
    }else{
        ElMessage.error('服务异常');
    }
    return Promise.reject(err);//异步的状态转化成失败的状态
}
)

export default instance;

6、添加文章分类

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第49张图片

6.1  ArticleCategory.vue

添加弹窗分类、数据模型和校验规则、添加分类按钮单击事件,确认按钮单击事件、在页面中调用接口




6.2 在article.js中提供添加分类的函数

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第50张图片

//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}

6.3 测试验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第51张图片

7、修改文章分类 

分析编辑与新增的弹窗页面可以复用,优化实施

7.1 修改分类弹窗页面

修改分类弹窗和新增文章分类弹窗长的一样,所以可以复用添加分类的弹窗

7.1.1 弹窗标题显示  ArticleCategory.vue

定义标题

//弹窗标题
const title=ref('')
7.1.2 在弹窗上绑定标题 ArticleCategory.vue
 
7.1.3 为添加分类按钮绑定事件 ArticleCategory.vue
添加分类
7.1.4 为修改分类按钮绑定事件 ArticleCategory.vue

7.2 修改数据回显 ArticleCategory.vue

当点击修改分类按钮时,需要把当前这一条数据的详细信息显示到修改分类的弹窗上,这个叫回显

通过插槽的方式得到被点击按钮所在行的数据




7.3 修改文章分类接口调用

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第52张图片

7.3.1 article.js中提供修改分类的函数
//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}


//六 7.3.1   修改分类
export const articleCategoryUpdateService = (categoryModel)=>{
    return request.put('/category',categoryModel)
   }
7.3.2 修改确定按钮的绑定事件 ArticleCategory.vue
 
                取消
                 确认 
            
7.3.3 调用接口完成修改的函数  ArticleCategory.vue



7.3.4 优化添加时数据回显

由于现在修改和新增共用了一个数据模型,所以在点击添加分类后,有时候会显示数据,此时可以将categoryModel中的数据清空

//清空模型数据
const clearCategoryModel = ()=>{
    categoryModel.value.categoryName='',
    categoryModel.value.categoryAlias=''
}



8、删除文章分类

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第53张图片

 8.1 删除接口

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第54张图片

//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}


//六 7.3.1   修改分类
export const articleCategoryUpdateService = (categoryModel)=>{
    return request.put('/category',categoryModel)
   }


//六 8.1  删除分类
export const articleCategoryDeleteService = (id) => {
    return request.delete('/category?id='+id)
}

8.2 删除确认框

//删除分类  给删除按钮绑定事件
const deleteCategory = (row) => {
    ElMessageBox.confirm(
        '你确认删除该分类信息吗?',
        '温馨提示',
        {
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning',
        }
    )
        .then(() => {
            //用户点击了确认
            ElMessage({
                type: 'success',
                message: '删除成功',
            })
        })
        .catch(() => {
            //用户点击了取消
            ElMessage({
                type: 'info',
                message: '取消删除',
            })
        })
}

 8.3 为删除按钮绑定事件

8.4 调用删除接口




8.5 测试验证

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第55张图片

七、文章列表 

1、 文章列表查询

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第56张图片

 1.1 文章列表页面组件ArticleManage.vue



1.2 解决分页控件英文显示问题main.js

import './assets/main.scss'  // 本项目使用sass

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 七 1.2 解决分页控件显示英文问题
import locale from  'element-plus/dist/locale/zh-cn.js'
//五 2.3 
import router from '@/router'


import App from './App.vue'
//六 2.2
import {createPinia} from 'pinia'

// 六  4.2 导入持久化插件
import {createPersistedState} from 'pinia-persistedstate-plugin'

const app = createApp(App)
//六 2.2
const pinia = createPinia();
// 六  4.2
const persist = createPersistedState()
//六  4.2 pinia使用持久化插件
pinia.use(persist)
app.use(pinia)
//五 2.3 
app.use(router)
// 七 1.2 解决分页控件显示英文问题
app.use(ElementPlus,{locale})
app.mount('#app')

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第57张图片

1.3 文章分类数据回显ArticleMange.vue  

//文章列表查询
import { articleCategoryListService } from '@/api/article.js'
const getArticleCategoryList = async () => {
    //获取所有分类
    let resultC = await articleCategoryListService();
    categorys.value = resultC.data
}
getArticleCategoryList(); 

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第58张图片

1.4 文章列表接口调用

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第59张图片

1.4.1 article.js中提供获取文章列表数据的函数
//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}


//六 7.3.1   修改分类
export const articleCategoryUpdateService = (categoryModel)=>{
    return request.put('/category',categoryModel)
   }


//六 8.1  删除分类
export const articleCategoryDeleteService = (id) => {
    return request.delete('/category?id='+id)
}

// 八 1.4.1 文章列表查询
export const articleListService = (params) => {
    return request.get('/article', { params: params })
   }
1.4.2 ArticleManage.vue中,调用接口获取数据


 【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第60张图片

1.4.3 当分页条的当前页和每页条数发生变化,重新发送请求获取数据
//当每页条数发生了变化,调用此函数
const onSizeChange = (size) => {
    pageSize.value = size
    articleList()  //七  1.4.3 **当分页条的当前页和每页条数发生变化,重新发送请求获取数据**
}
//当前页码发生变化,调用此函数
const onCurrentChange = (num) => {
    pageNum.value = num
    articleList()  //七  1.4.3 **当分页条的当前页和每页条数发生变化,重新发送请求获取数据**
}

2 、搜索和重置

为搜索按钮绑定单击事件,调用getArticles函数即可

为重置按钮绑定单击事件,清除categoryId和state的之即可



3、添加文章

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第61张图片

3.1 添加文章抽屉组件

import {Plus} from '@element-plus/icons-vue'
//控制抽屉是否显示
const visibleDrawer = ref(false)
//添加表单数据模型
const articleModel = ref({
    title: '',
    categoryId: '',
    coverImg: '',
    content:'',
    sta

        
            
            
                
                    
                
                
                    
                        
                        
                    
                
                

                    
                        
                        
                            
                        
                    
                
                
                    
富文本编辑器
发布 草稿

/* 抽屉样式 */
.avatar-uploader {
    :deep() {
        .avatar {
            width: 178px;
            height: 178px;
            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: 178px;
            height: 178px;
            text-align: center;
        }
    }
}
.editor {
  width: 100%;
  :deep(.ql-editor) {
    min-height: 200px;
  }
}

3.2 为添加文章按钮添加单击事件,展示抽屉



3.3 富文本编辑器

文章内容需要使用到富文本编辑器,这里咱们使用一个开源的富文本编辑器 Quill

官网地址: VueQuill | Rich Text Editor Component for Vue 3

3.3.1 安装:
npm install @vueup/vue-quill@latest --save

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第62张图片

3.3.2 导入组件和样式:
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
3.3.3 页面使用quill组件:

3.3.4 样式美化:
.editor {
  width: 100%;
  :deep(.ql-editor) {
    min-height: 200px;
  }
}


【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第63张图片

3.4 文章封面图片上传

将来当点击+图标,选择本地图片后,el-upload这个组件会自动发送请求,把图片上传到指定的服务器上,而不需要我们自己使用axios发送异步请求,所以需要给el-upload标签添加一些属性,控制请求的发送

auto-upload:是否自动上传

action: 服务器接口路径

name: 上传的文件字段名

headers: 设置上传的请求头

on-success: 上传成功的回调函数


                
                    

                    
                        
                        
                            
                        
                    
                

注意:

  1. 由于这个请求时el-upload自动发送的异步请求,并没有使用咱们的request.js请求工具,所以在请求的路ing上,需要加上/api, 这个时候请求代理才能拦截到这个请求,转发到后台服务器上

  2. 要携带请求头,还需要导入pinia状态才可以使用

    import { useTokenStore } from '@/stores/token.js'
    const tokenStore = useTokenStore();
    
    
    

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第64张图片

3.5 添加文章接口调用

3.5.1 article.js中提供添加文章函数

//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}


//六 7.3.1   修改分类
export const articleCategoryUpdateService = (categoryModel)=>{
    return request.put('/category',categoryModel)
   }


//六 8.1  删除分类
export const articleCategoryDeleteService = (id) => {
    return request.delete('/category?id='+id)
}

// 七 1.4.1 文章列表查询
export const articleListService = (params) => {
    return request.get('/article', { params: params })
   }


//七 3.5.1添加文章
export const articleAddService = (articleModel)=>{
    return request.post('/article',articleModel)
}
3.5.2 为已发布和草稿按钮绑定事件

    发布
    草稿
3.5.3 ArticleManage.vue中提供addArticle函数完成添加文章接口的调用
const addArticle=async (state)=>{
    articleModel.value.state = state
    let result = await articleAddService(articleModel.value);
    ElMessage.success(result.message? result.message:'添加成功')
    //再次调用getArticles,获取文章
    articleList()
    //隐藏抽屉
    visibleDrawer.value=false
}


4、编辑文章

4.1 修改文章抽屉页面

修改文章抽屉和新增文章抽屉长的一样,所以可以复用添加分类的弹窗

4.1.1 抽屉标题显示 定义标题
//抽屉标题
const title=ref('')
4.1.2 在抽屉上绑定标题
 
4.1.3 为添加文章按钮绑定事件
 添加文章 
4.1.4 为修改文章按钮绑定事件
  

4.2 数据回显

当点击修改文章按钮时,需要把当前这一条数据的详细信息显示到修改文章的抽屉上,这个叫回显

4.2.1 通过插槽的方式得到被点击按钮所在行的数据
 
4.2.2 回显函数
// 七 4.2.2展示抽屉弹窗
const showDrawer = (row)=>{
    title.value = '修改文章';visibleDrawer.value = true
    //数据拷贝
    articleModel.value.title = row.title;
    articleModel.value.categoryId = row.categoryId;
    articleModel.value.coverImg = row.coverImg;
    articleModel.value.content = row.content;
    //扩展id属性,将来需要传参给后台完成文章的修改
    articleModel.value.id = row.id
}


4.3 修改文章接口调用

4.3.1 article.js中提供修改文章的函数
//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}


//六 7.3.1   修改分类
export const articleCategoryUpdateService = (categoryModel)=>{
    return request.put('/category',categoryModel)
   }


//六 8.1  删除分类
export const articleCategoryDeleteService = (id) => {
    return request.delete('/category?id='+id)
}

// 七 1.4.1 文章列表查询
export const articleListService = (params) => {
    return request.get('/article', { params: params })
   }


//七 3.5.1添加文章
export const articleAddService = (articleModel)=>{
    return request.post('/article',articleModel)
}

//七 4.3.1修改文章
export const articleUpdateService = (articleModel)=>{
    return request.put('/article',articleModel)
   }
4.3.2 修改发布与草稿按钮的绑定事件

                        发布 
                        草稿 
                    
4.3.3 调用接口完成修改的函数
//七 4.4.4 修改文章
const updateArticle=async ()=>{
    let result = await articleUpdateService(articleModel.value)
    ElMessage.success(result.message? result.message:'修改成功')
    //隐藏抽屉
    visibleDrawer.value=false
    //再次访问后台接口,查询所有文章
    articleList()
}

由于现在修改和新增共用了一个数据模型,所以在点击添加文章后,有时候会显示数据,此时可以将articleModel中的数据清空

//七 4.4.3 清空模型数据
const clearArticleModel = ()=>{
    articleModel.value.title='',
    articleModel.value.categoryId='',
    articleModel.value.coverImg='',
    articleModel.value.content='
', articleModel.value.state='' }

修改 添加文章按钮的点击事件()

添加文章  


5、删除文章

5.1 接口调用

article.js中提供删除分类的函数

//导入request.js请求工具
import request from '@/utils/request.js'
// 六 2.4 导入@/stores/token.js
import { useTokenStore } from '@/stores/token.js'

// 六  文章分类列表查询函数  
export const articleCategoryListService = (registerData) =>{    
    // 六 2.4获取token状态
    // 六 3.2
    // const tokenStore = useTokenStore()
    //通过请求头Authorization携带token
    // return request.get('/category', { headers: { 'Authorization': tokenStore.token } });
    
    return request.get('/category');
    
}

// 六 6.2  文章分类 添加文章分类 函数  json 参数
export const articleCategoryAddService = (categoryModel) => {
    return request.post('/category', categoryModel)
}


//六 7.3.1   修改分类
export const articleCategoryUpdateService = (categoryModel)=>{
    return request.put('/category',categoryModel)
   }


//六 8.1  删除分类
export const articleCategoryDeleteService = (id) => {
    return request.delete('/category?id='+id)
}

// 七 1.4.1 文章列表查询
export const articleListService = (params) => {
    return request.get('/article', { params: params })
   }


//七 3.5.1添加文章
export const articleAddService = (articleModel)=>{
    return request.post('/article',articleModel)
}

//七 4.3.1修改文章
export const articleUpdateService = (articleModel)=>{
    return request.put('/article',articleModel)
   }

//七 5.1删除文章
export const articleDeleteService = (id) => {
    return request.delete('/article?id='+id)
   }

5.2 为删除按钮绑定事件

5.3 添加删除弹窗,当用户点击确认后,调用接口删除分类



八、顶部导航栏信息展示

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第65张图片

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

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

//导入request.js请求工具
import request from '@/utils/request.js'

// 二  注册函数  提供调用注册接口的函数
export const userRegisterService = (registerData) =>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in registerData){
        params.append(key,registerData[key]);
    }
    return request.post('/user/register',params);
    
}

// 三  登录函数 提供调用登录接口的函数
export const userLoginService = (loginData)=>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in loginData){
        params.append(key,loginData[key]);
    }
    return request.post('/user/login',params);

}

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

2、 src/stores/userInfo.js中,定义个人中心状态

import {defineStore} from 'pinia'
import {ref} from 'vue'
const useUserInfoStore = defineStore('userInfo',()=>{
    //定义状态相关的内容

    const info = ref({})

    const setInfo = (newInfo)=>{
        info.value = newInfo
    }


    const removeInfo = ()=>{
        info.value = {}
    }

    return {info,setInfo,removeInfo}

},{persist:true})

export default useUserInfoStore;

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

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

const userInfoStore = useUserInfoStore();
//获取个人信息
const getUserInfo = async ()=>{
    let result = await userInfoGetService();
    //存储pinia
    userInfoStore.info =result.data;
}
getUserInfo()

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

 
编码集中营:{{ userInfoStore.info.nickname ? userInfoStore.info.nickname : userInfoStore.info.usrename }}
 
​全部Layout.vue




九 、页面右上角下拉菜单el-dropdown中功能实现

在el-dropdown中有四个子条目,分别是:

  • 基本资料

  • 更换头像

  • 重置密码

  • 退出登录

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

1、路由实现:

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


                
                
                    
                         
                        
                            
                        
                    
                    
                

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

提供handleCommand函数,参数为点击条目的command属性值

//dropDown条目被点击后,回调的函数
import {useRouter} from 'vue-router'
const router = useRouter()
const handleCommand = (command)=>{
    if(command==='logout'){
        //退出登录
        alert('退出登录')
    }else{
        //路由
        router.push('/user/'+command)
    }
}

2、 退出登录实现:





十、基本资料修改

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第66张图片

1、 基本资料页面组件UserInfo.vue

views\user\UserInfo.vue

2、 表单数据回显

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

// 十  2
import  useUserInfoStore  from '@/stores/userInfo.js';
const userInfoStore = useUserInfoStore()
const userInfo = ref({...userInfoStore.info})

3、 接口调用

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

//导入request.js请求工具
import request from '@/utils/request.js'

// 二  注册函数  提供调用注册接口的函数
export const userRegisterService = (registerData) =>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in registerData){
        params.append(key,registerData[key]);
    }
    return request.post('/user/register',params);
    
}

// 三  登录函数 提供调用登录接口的函数
export const userLoginService = (loginData)=>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in loginData){
        params.append(key,loginData[key]);
    }
    return request.post('/user/login',params);

}

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


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

为修改按钮绑定单击事件

提交修改 

提供updateUserInfo函数

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
}

十一、修改头像

【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第67张图片

1、 修改头像页面组件UserAvatar.vue





2、 头像回显

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

//读取用户信息
import {ref} from 'vue'
import useUserInfoStore from '@/stores/userInfo.js'

const userInfoStore = useUserInfoStore()
//用户头像地址
const imgUrl=ref(userInfoStore.info.userPic)

img标签上绑定图片地址


3、 头像上传

为el-upload指定属性值,分别有:

  • action: 服务器接口路径

  • headers: 设置请求头,需要携带token

  • on-success: 上传成功的回调函数

  • name: 上传图片的字段名称


                    
                    
                

提供上传成功的回调函数

//读取token信息
import {useTokenStore} from '@/stores/token.js'
const tokenStore = useTokenStore()
​
//图片上传成功的回调
const uploadSuccess = (result)=>{
    //回显图片
    imgUrl.value = result.data
}

外部触发图片选择

需要获取到el-upload组件,然后再通过$el.querySelector('input')获取到el-upload对应的元素,触发click事件

// 十 、3//获取el-upload元素
const uploadRef = ref()

    选择图片

4、 上传头像接口调用

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

//导入request.js请求工具
import request from '@/utils/request.js'

// 二  注册函数  提供调用注册接口的函数
export const userRegisterService = (registerData) =>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in registerData){
        params.append(key,registerData[key]);
    }
    return request.post('/user/register',params);
    
}

// 三  登录函数 提供调用登录接口的函数
export const userLoginService = (loginData)=>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in loginData){
        params.append(key,loginData[key]);
    }
    return request.post('/user/login',params);

}

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


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


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

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

  
                    上传头像
                

提供updateAvatar函数,完成头像更新

//调用接口,更新头像url
import {userAvatarUpdateService} from '@/api/user.js'
import {ElMessage} from 'element-plus'
const updateAvatar = async ()=>{
    let result = await userAvatarUpdateService(imgUrl.value)
    ElMessage.success(result.message? result.message:'修改成功')
    //更新pinia中的数据
    userInfoStore.info.userPic=imgUrl.value
}




十二、 重置密码

1、user.js 重置密码

//导入request.js请求工具
import request from '@/utils/request.js'

// 二  注册函数  提供调用注册接口的函数
export const userRegisterService = (registerData) =>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in registerData){
        params.append(key,registerData[key]);
    }
    return request.post('/user/register',params);
    
}

// 三  登录函数 提供调用登录接口的函数
export const userLoginService = (loginData)=>{
    //借助于URLSearchParam完成参数传递
    const params = new URLSearchParams();
    for(let key in loginData){
        params.append(key,loginData[key]);
    }
    return request.post('/user/login',params);

}

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


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


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


   // 十二  重置密码
export const userUpdatePwdService=(userPwd)=>{    
    return request.patch('/user/updatePwd',userPwd)
}

 2、UserResetPassword.vue

 views/UserResetPassword.vue


【SpringBoot3+Vue3】五【完】【实战篇】-前端(配合后端)_第68张图片

你可能感兴趣的:(java,VUE,前端,Vue3,实战)