如何创建一个项目(学习笔记)

如何创建一个项目(学习笔记)本文供学习交流使用 使用技术栈 piniavue3axi plusvant4JSO server 不包含后端内容 不提供接口使用 新建项目

大家好,欢迎来到IT知识分享网。

前言:

欢迎来到本次教程。这篇文章旨在深入解析在 B 站上的 Vue3 后台管理项目,同时也为您提供了创建此类项目的实践思路。我们将通过这个笔记系统地梳理一个项目的整体框架,涵盖了我们在 Vue 课程中学习的主要内容。

在此过程中,我尝试使用 Vant4 组件库替代了原先的 Element-Plus 组件,但请注意,由于 Vant4 和 Element-Plus 有所不同,有些 Element-Plus 组件可能无法找到完全相同的 Vant4 替代品。因此,本文中的 Vant4 代码仅供参考。

由于时间紧迫,尽管我已尽最大努力保证内容的准确性和完整性,但仍有可能存在一些疏漏或不够完善的地方。如果您在阅读过程中发现任何需要改进的地方,非常欢迎指出,您的建议将对我来说极为宝贵。

在此,小天同学再次向同学们表示感谢。我希望这篇文章能为你的学习提供有价值的参考,让我们一起探索 Vue3 的世界。

使用到的技术:
附本文使用技术的官网链接
vue3:https://cn.vuejs.org/
element-plus:http://element-plus.org/zh-CN/
vant4:https://vant-contrib.gitee.io/vant/#/zh-CN
pinia:https://pinia.web3doc.top/
vuex:https://vuex.vuejs.org/zh/
JSON-SERVER:https://github.com/typicode/json-server
axios:https://www.axios-http.cn/docs/intro
项目出处:[https://www.bilibili.com/video/BV1no4y1Y7gF?p=1&vd_source=6f495ad66c7e55ede1b042f9e](https://www.bilibili.com/video/BV1no4y1Y7gF?








# 1.创建项目 如何创建一个工程 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ac3bbf84666c4eecb4a9fd9e64838af8.png#pic_center)

1.打开文件夹(找到对应的文件打开)

2.集成终端打开

image.png

3.配置相关指令

image.png

npm init vue@latest 

4.配置选择

5.创建vite

从这一步开始,所有的“在终端中打开,全部指的是右键vue-project再点击在集成终端中打开!!
image.png
右键点击vue-project的位置,选择在集成终端中打开
输入以下指令
image.png



npm i vite 

5.引入vant

npm i vant 

至此,我们的项目基本内容已经创建完毕
(注:想要检查安装的文件版本,可以控package-lock.json中寻找)

2.相关配置

1.vant配置

全局引入

在main.js中加入以下代码

import { 
     createApp } from 'vue'; // 1. 引入你需要的组件 import { 
     Button } from 'vant'; // 2. 引入组件样式 import 'vant/lib/index.css'; const app = createApp(); // 3. 注册你需要的组件 app.use(Button); 

image.pngimage.png

按需引入

如果是部分引入,就需要先安装一个插件,再分别引入,操作方法如下:
1.在终端中输入

# 通过 npm 安装 npm i unplugin-vue-components -D # 通过 pnpm 安装 pnpm add unplugin-vue-components -D 

之后就非常简单,我们的组件需要哪一个就直接在script中引入就可以了。

注意:如果使用的是以下写法,不需要引入这一行代码,可以直接使用

image.png
每个vue组件引入即可(就是复制过来)

<script setup> import { Swipe, SwipeItem } from "vant";//其实使用了setup的写法以后,可以不需要这个 </script> <template> <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white"> <van-swipe-item>1</van-swipe-item> <van-swipe-item>2</van-swipe-item> <van-swipe-item>3</van-swipe-item> <van-swipe-item>4</van-swipe-item> </van-swipe> </template> <style scoped> .my-swipe .van-swipe-item { color: #fff; font-size: 20px; line-height: 150px; text-align: center; background-color: #39a9ed; } </style> 

2.路由配置

如果你从一开始就跟着我们的操作,左边的列表里是有router的字样的,里面有一个文件index.js,那就只需要image.png

npm install vue-router@4 

3.pinia配置

1.pinia安装

如果您从一开始就是跟我们的步骤做,那您相对来说比较轻松,直接跳到第2部分
image.png
但是如果不是,那就遭老罪喽。请执行以下步骤:
1.在终端中输入以下代码:


npm install pinia 

2.将以下代码补充到main.js中

import { createPinia } from 'pinia' app.use(createPinia()) 
import { 
     defineStore } from 'pinia' // useStore 可以是 useUser、useCart 之类的任何东西 // 第一个参数是应用程序中 store 的唯一 id export const useStore = defineStore('main', { 
     // other options... }) 

2.pinia的基本内容

我们把pinia配置好了以后,现在主要的内容给写进去

import { 
     ref, computed } from 'vue' import { 
     defineStore } from 'pinia' export const useUsersStore = defineStore("main", { 
     // 这个相当于是一个数据仓库,是处理数据用的。 state: () => { 
     return { 
     // 比如我可以在这里定义年龄,姓名等等 // name: "xiaotian", // age: 18, // id: 1 }; }, // 这个相当于是一个计算属性,也是处理数据用的。比如说,我要把年龄加100岁, //那么我就可以在这里写一个方法,然后在页面上调用这个方法,就可以得到加了100岁的年龄了。 getters: { 
     // 比如我想给state的年龄+100 return state.age + 100; }, //这个相当于是一个method,写一些方法,比如处理数据的方法,比如点击事件的方法,比如axios请求的方法,比如定时器的方法... actions: { 
     } }) 

3.如何使用pinia配置好的数据

<!-- import { ref } from 'vue' --> // 注意,这里from后面是路径,别写错了,不行就先输入 ../ 看看弹出来的是啥 import { useUsersStore } from '@/stores/counter.js' // 这里是做响应式用的,在子页面修改的数据,通过这种方式可以完成同步,原因官网上面写的很清楚 import { storeToRefs } from 'pinia' // 这里的useUsersStore(),和你store/index.js中配置的是一样的 const store = useUsersStore(); 
//修改前 const { 
    name,doubleCount} = store //修改后 const { 
    name,doubleCount} = storeToRefs(store) // 加了一个storeToRefs() 

4.JSON-SERVER配置

  1. node 环境安装
  2. 安装 json-server
  3. 创建数据库(其实就是一个 json 文件)
  4. 启动服务

1.node环境安装

2.安装json-server

npm i json-server // 想要全局安装选下面这个 npm install -g json-server 

3.填写数据

  1. 创建 json-server-demo 文件夹,
  2. 在 json-server-demo 里创建 db.json 文件(这些文件夹和文件名都可以自由命名)。
  3. db.json 文件录入以下数据(数据来自 json-server 官方文档)
{ 
     "posts": [ { 
     "id": 1, "title": "json-server", "author": "typicode" } ], "comments": [ { 
     "id": 1, "body": "some comment", "postId": 1 } ], "profile": { 
     "name": "typicode" } } 

4.启动服务

运行指令

json-server --watch db.json 
npm install -g json-server 
  1. 使用管理员方式打开Power Shell
  2. 输入Get-ExecutionPolicy,可以查看到当前的策略
  3. 输入Set-ExecutionPolicy RemoteSigned,设置当前的策略为RemoteSigned
  4. 输入Y

5.数据修改

1.增

image.png
接下来可以增添数据
输入您的posts链接
image.png
image.png
这里就会输出相关代码






2.删
3.改
{ 
     "title": "php", "author": "xiaotiantian" } 

image.png
image.png


4.查
http://localhost:3000/posts/{id} 
http://localhost:3000/posts?name=php&sex=man 

5.更新

6.修改端口

如果你想要修改我们的端口,不再使用3000,那可以使用以下指令修改

json-server -p 8888 db.json 

7.修改主机端口

终端中输入以下代码修改主机号

json-server --host 0.0.0.0 db.json 

5.axios配置

1. 下载Axios

首先,在Vue 3项目中下载Axios库,可以使用npm或yarn进行安装。在终端中进入项目目录,执行以下命令进行安装:

安装npm:

// 下面两个二选一 npm install axios cnpm install axios -g 

2. 配置Axios

// axios引入 import axios from "axios" //pinia引入 import store from "../store/index.js" //创建一个axios实例 const Service = axios.create({ 
     baseURL: 'https://some-domain.com/api/', timeout: 1000, headers: { 
    'X-Custom-Header': 'foobar'} }); 

3.路由的详细配置

const routes = [ { 
     path: "/login", name: "login", component: () => import ("../views/pages/login.vue") // 懒加载引入登录页面组件 } ] 
const routes = [ { 
     path: "/", name: "layout", component: () => import ("../views/Layout/LayOut.vue"), redirect: "/index", // 子路由/嵌套路由 children: [{ 
     path: "/index", name: "index", component: () => import ("../views/pages/index.vue") // 懒加载引入首页组件 },] } ] 

也就是在配置中多加入一个children项目。

{ 
     path: "/", name: "layout", component: () => import ("../views/Layout/LayOut.vue"), redirect: "/index", // 子路由/嵌套路由 children: [{ 
     path: "/index", name: "index", component: () => import ("../views/pages/index.vue") // 懒加载引入首页组件 }, { 
     path: "/roles", name: "roles", component: () => import ("../views/pages/rolesList.vue") // 懒加载引入角色列表组件 }, { 
     path: "/user", name: "user", component: () => import ("../views/pages/userList.vue") // 懒加载引入用户列表组件 }, { 
     path: "/goods", name: "goods", component: () => import ("../views/pages/goodsList.vue") // 懒加载引入商品列表组件 } ] } 

完整配置:

import { 
     createRouter, createWebHashHistory } from 'vue-router' import store from "../store/index.js" // 引入Vuex的store实例 // 路由配置 const routes = [ // 登陆页面 { 
     path: "/login", name: "login", component: () => import ("../views/pages/login.vue") // 懒加载引入登录页面组件 }, { 
     path: "/", name: "layout", component: () => import ("../views/Layout/LayOut.vue"), redirect: "/index", // 子路由/嵌套路由 children: [{ 
     path: "/index", name: "index", component: () => import ("../views/pages/index.vue") // 懒加载引入首页组件 }, { 
     path: "/roles", name: "roles", component: () => import ("../views/pages/rolesList.vue") // 懒加载引入角色列表组件 }, { 
     path: "/user", name: "user", component: () => import ("../views/pages/userList.vue") // 懒加载引入用户列表组件 }, { 
     path: "/goods", name: "goods", component: () => import ("../views/pages/goodsList.vue") // 懒加载引入商品列表组件 } ] } ] // 生成hash路由对象 const router = createRouter({ 
     history: createWebHashHistory(), routes }) // 路由守卫 router.beforeEach((to, from, next) => { 
     / * to:即将要进入的目标 * from:正要离开的路由 * next:只有执行next()页面才会进行跳转 */ // 判断用户是否登录 console.log("store", store.state.uInfo) const uInfo = store.state.uInfo.userInfo if (!uInfo.username) { 
     // 未登录,跳转到login if (to.path === "/login") { 
     next() return } next("/login") } else { 
     next() } }) // 暴露路由对象 export default router 

4.项目的详细配置

1.登录页面

1.html+css配置

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button><a href="登录地址"></a></button> </body> </html> 

我不建议这么写,因为这么写没分。

html和css我们就不细说了,我这里直接给出

<template> <div class="login_wrap"> <div class="form_wrap"> <van-form ref="formRef" :model="loginData" class="demo-dynamic" > <!-- 用户名表单项 --> <van-field v-model="loginData.username" label="用户名" name="username" :rules="[ { required: true, message: '此项为必填项', trigger: 'blur', }, ]" /> <!-- 密码表单项 --> <van-field v-model="loginData.password" label="密码" name="password" type="password" :rules="[ { required: true, message: '此项为必填项', trigger: 'blur', }, ]" /> </van-form> <!-- 登录按钮 --> <van-button type="primary" class="login_btn" @click="handleLogin">登录</van-button> </div> </div> </template> <!-- 样式 --> <style scoped> .login_wrap { width: 100%; height: 100vh; background: rgb(56, 86, 139); position: relative; } .form_wrap { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #fff; padding: 30px 50px; border-radius: 5px; } .login_btn { display: block; margin: 10px auto; } </style> 

那在这个组件里的script怎么写呢
那首先我们是要访问我们库里面有没有相关的数据在,比如账号、密码、个人信息等等,
并且核实账号密码是否正确

2.axios请求配置

我们打开service.js写入以下部分(看注释,只写新增部分!!最上边的代码之前我已经配置了,
不信点这里!!(点击这里)

//这里是原本就有的,之前axios叫你们配置过的部分 import axios from "axios" import store from "../store/index.js" // 使用create创建axios实例 const Service = axios.create({ 
     timeout:8000, //这里写URL地址/接口地址等 baseURL:"http://122.114.229.181:3000/api/private/v1/", headers:{ 
     "Content-type":"application/json;charset=utf-8", "Authorization":store.state.uInfo.userInfo.token } }) //  //下面是新增的部分 // post请求 export const post=config=>{ 
     return Service({ 
     ...config, method:"post", data:config.data }) } // get请求 export const get=config=>{ 
     return Service({ 
     ...config, method:"get", params:config.data }) } // put请求 export const put=config=>{ 
     return Service({ 
     ...config, method:"put", data:config.data }) }// delete请求 export const del=config=>{ 
     return Service({ 
     ...config, method:"delete" }) } 

当然了,我们还需要状态管理器store/userInfo.js。

export default { 
     state: { 
     // 定义一个名为 userInfo 的变量,其值为一个对象。 // 初始值为通过判断 localStorage 中是否存在名为 loginData 的数据, // 如果存在则将该数据解析为一个 JavaScript 对象,否则设置为空对象 {}。 userInfo: (localStorage.getItem('loginData') && JSON.parse(localStorage.getItem('loginData'))) || { 
    }, }, actions: { 
     // 定义一个名为 setUserInfo 的 mutation 方法来修改 userInfo 变量的值。 // 这个方法接收两个参数:state 和 uInfo,其中 state 是当前模块的状态对象, // 而 uInfo 是用于更新 userInfo 的新值。 setUserInfo(state, uInfo) { 
     state.userInfo = uInfo; }, }, }; 

如果你的程序中要写很多个状态管理,我建议在stores文件夹下新建一个index.js文件

import { 
     createStore } from 'vuex' import uInfo from "./state/userinfo.state.js" export default createStore({ 
     // 数据比较多,分模块 modules: { 
     uInfo } }) 

3.思考组件包含的功能

这里既然是登陆页面,就要考虑用户登录信息的核对和保存
既然如此,我们首先想到需要连接状态管理器路由以及响应式,于是我们导入以下代码

import { ref } from 'vue'; import { useStore } from 'vuex'; import { useRouter } from 'vue-router'; 

4.aixos基本的逻辑配置

// 导入service中导出的HTTP方法 import { 
     post, get, put, del } from "./service" // 登录API export const loginApi = data => { 
     return post({ 
     url: "/login", data }) } 

之后我们再导入登录请求的API

<script setup> // 引入Vue 3的ref,用于创建响应式引用 import { ref } from 'vue'; // 引入Vuex的useStore,用于获取Vuex存储实例 import { useStore } from 'vuex'; // 引入Vue Router的useRouter,用于获取路由器实例 import { useRouter } from 'vue-router'; // 引入登录API函数 import { loginApi } from '@/util/request'; </script> 
<script setup> // 引入Vue 3的ref,用于创建响应式引用 import { ref } from 'vue'; // 引入Vuex的useStore,用于获取Vuex存储实例 import { useStore } from 'vuex'; // 引入Vue Router的useRouter,用于获取路由器实例 import { useRouter } from 'vue-router'; // 引入登录API函数 import { loginApi } from '@/util/request'; // // 以下为补充内容 // // 获取Vuex存储实例 const store = useStore(); // 获取路由器实例 const router = useRouter(); // 创建一个响应式引用,存储登录表单数据 const loginData = ref({ username: '', password: '' }); // 处理登录按钮点击事件的函数 const handleLogin = async () => { // 使用登录API函数发送登录请求,并等待响应 const res = await loginApi(loginData.value); // 如果响应中包含数据 if (res.data) { // 使用Vuex存储实例的commit方法更新用户信息 store.commit('setUserInfo', res.data); // 将登录数据存储到localStorage localStorage.setItem('loginData', JSON.stringify(res.data)); // 使用路由器实例将用户重定向到根路径 router.push({ path: '/' }); } }; </script> 
import { 
     createRouter, createWebHashHistory } from 'vue-router' import store from "../store/index.js" // 引入Vuex的store实例 // 路由配置 const routes = [ // 登陆页面 { 
     path: "/login", name: "login", component: () => import ("../views/pages/login.vue") // 懒加载引入登录页面组件 }, { 
     path: "/", name: "layout", component: () => import ("../views/Layout/LayOut.vue"), redirect: "/index", // 子路由/嵌套路由 children: [{ 
     path: "/index", name: "index", component: () => import ("../views/pages/index.vue") // 懒加载引入首页组件 }, { 
     path: "/roles", name: "roles", component: () => import ("../views/pages/rolesList.vue") // 懒加载引入角色列表组件 }, { 
     path: "/user", name: "user", component: () => import ("../views/pages/userList.vue") // 懒加载引入用户列表组件 }, { 
     path: "/goods", name: "goods", component: () => import ("../views/pages/goodsList.vue") // 懒加载引入商品列表组件 } ] } ] // 生成hash路由对象 const router = createRouter({ 
     history: createWebHashHistory(), routes }) //* //*路由守卫在这里!! //* // 路由守卫 router.beforeEach((to, from, next) => { 
     / * to:从哪个页面 * from:到哪个页面 * next:只有执行next()页面才会进行跳转 */ // 判断用户是否登录 console.log("store", store.state.uInfo) const uInfo = store.state.uInfo.userInfo if (!uInfo.username) { 
     // 未登录,跳转到login if (to.path === "/login") { 
     next() return } next("/login") } else { 
     next() } }) // 暴露路由对象 export default router 

我们的登陆页面及其功能详解到此结束。

const handleLogin = async () => { //<!-- 定义登录方法 --> const res = await loginApi(loginData.value); // <!-- 发送登录请求 --> if (res.data) { //<!-- 登录成功 --> store.commit('setUserInfo', res.data); //<!-- 提交用户信息到Vuex中 --> localStorage.setItem('loginData', JSON.stringify(res.data)); //<!-- 将用户信息保存到本地存储中 --> router.push({ path: '/' }); // <!-- 跳转到首页 --> } }; 

现在考虑,如果登录正在加载,或服务器出错应该弹出提示,这个提示的信息也要在axios文件中配置

import { 
     Toast } from 'vant'; // 请求拦截器 axios.interceptors.request.use(config => { 
     // 显示 loading Toast.loading({ 
     message: 'Loading...', forbidClick: true, // 禁止点击背景 loadingType: 'spinner', // loading 样式 }); return config; // 返回请求配置 }); // 响应拦截器 axios.interceptors.response.use(response => { 
     // 隐藏 loading Toast.clear(); const data = response.data; // 获取响应数据 if (data.code !== 200) { 
     // 处理错误 Toast.fail(data.msg || '服务器出错'); // 显示错误提示 return Promise.reject(data); // 返回 rejected 状态的 Promise } return data; // 返回响应数据 }, error => { 
     // 隐藏 loading Toast.clear(); Toast.fail('服务器错误'); // 显示错误提示 return Promise.reject(error); // 返回 rejected 状态的 Promise }); 
import axios from "axios" import store from "../store/index.js" import { 
     Toast } from 'vant'; // 创建一个axios实例,并设置请求超时时间、基础URL和请求头 const Service = axios.create({ 
     timeout: 8000, baseURL: "http://122.114.229.181:3000/api/private/v1/", headers: { 
     "Content-type": "application/json;charset=utf-8", "Authorization": store.state.uInfo.userInfo.token } }) // 请求拦截器 axios.interceptors.request.use(config => { 
     // 显示 loading Toast.loading({ 
     message: 'Loading...', forbidClick: true, // 禁止点击背景 loadingType: 'spinner', // loading 样式 }); return config; // 返回请求配置 }); // 响应拦截器 axios.interceptors.response.use(response => { 
     // 隐藏 loading Toast.clear(); const data = response.data; // 获取响应数据 if (data.code !== 200) { 
     // 处理错误 Toast.fail(data.msg || '服务器出错'); // 显示错误提示 return Promise.reject(data); // 返回 rejected 状态的 Promise } return data; // 返回响应数据 }, error => { 
     // 隐藏 loading Toast.clear(); Toast.fail('服务器错误'); // 显示错误提示 return Promise.reject(error); // 返回 rejected 状态的 Promise }); // post请求 export const post = config => { 
     // 使用Service实例发送post请求,并传入请求配置 return Service({ 
     ...config, method: "post", data: config.data }) } // get请求 export const get = config => { 
     // 使用Service实例发送get请求,并传入请求配置 return Service({ 
     ...config, method: "get", params: config.data }) } // put请求 export const put = config => { 
     // 使用Service实例发送put请求,并传入请求配置 return Service({ 
     ...config, method: "put", data: config.data }) } // delete请求 export const del = config => { 
     // 使用Service实例发送delete请求,并传入请求配置 return Service({ 
     ...config, method: "delete" }) } 

现在将login.vue的代码完整版整理出来

<template> <div class="login_wrap"> <div class="form_wrap"> <van-form ref="formRef" :model="loginData" class="demo-dynamic" > <!-- 用户名表单项 --> <van-field v-model="loginData.username" label="用户名" name="username" :rules="[ { required: true, message: '此项为必填项', trigger: 'blur', }, ]" /> <!-- 密码表单项 --> <van-field v-model="loginData.password" label="密码" name="password" type="password" :rules="[ { required: true, message: '此项为必填项', trigger: 'blur', }, ]" /> </van-form> <!-- 登录按钮 --> <van-button type="primary" class="login_btn" @click="handleLogin">登录</van-button> </div> </div> </template> <script setup> import { ref } from 'vue'; import { useStore } from 'vuex'; import { useRouter } from 'vue-router'; import { loginApi } from '@/util/request'; const store = useStore(); const router = useRouter(); const loginData = ref({ username: '', password: '' }); const handleLogin = async () => { const res = await loginApi(loginData.value); if (res.data) { store.commit('setUserInfo', res.data); localStorage.setItem('loginData', JSON.stringify(res.data)); router.push({ path: '/' }); } }; </script> <style scoped> .login_wrap { width: 100%; height: 100vh; background: rgb(56, 86, 139); position: relative; } .form_wrap { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #fff; padding: 30px 50px; border-radius: 5px; } .login_btn { display: block; margin: 10px auto; } </style> 

2.角色页面

1.html+css配置

老规矩,html直接给出,因为都是element的配置。vant只要找到相同的功能直接写就可以

<template> <div> <!-- 面包屑导航 --> <van-nav-bar> <template #left> <van-icon name="arrow-left" @click="goToHome" /> </template> <template #title> 角色列表 </template> </van-nav-bar> <!-- 白色内容区域 --> <div class="page_content"> <!-- 新建角色按钮 --> <van-button type="primary" @click="dialogFormVisible=true">新建角色</van-button> <!-- 表格展示角色列表 --> <van-list :data="rolesList"> <template #default="{item}"> <van-cell :title="item.roleName" :value="item.roleDesc"> <template #right-icon> <div class="buttons"> <van-button type="primary" plain size="small" @click="editRow(item)">编辑</van-button> <van-button type="danger" plain size="small" @click="deleteRow(item)">删除</van-button> </div> </template> </van-cell> </template> </van-list> </div> <!-- 新建/编辑角色弹窗表单 --> <van-popup v-model="dialogFormVisible" round> <van-form ref="userForm" :model="formData" :rules="rules" > <van-field name="roleName" label="角色名称" v-model="formData.roleName" placeholder="请输入角色名称" /> <van-field name="roleDesc" label="角色描述" v-model="formData.roleDesc" placeholder="请输入角色描述" /> <div class="buttons"> <van-button @click="clearForm">取消</van-button> <van-button type="primary" @click="submitForm(userForm)">确定</van-button> </div> </van-form> </van-popup> </div> </template> 

以及按钮触发的方法
这里可以理解为一个点击事件,做了一个绑定,点击以后自动触发函数。
@close=“clearForm”//‘编辑角色’:‘新建角色’(这个是关闭事件)
@click=“goToHome”
@click=“dialogFormVisible=true”//新建角色
@click=”editRow(item)//编辑
@click=“deleteRow(item)”//删除
@click=”submitForm(userForm)//确定按钮






// 以上是之前写过的部分 // 导入service中导出的HTTP方法 import { 
     post, get, put, del } from "./service" // 登录API export const loginApi = data => { 
     return post({ 
     url: "/login", data }) } // * // 以下是新增部分 // * // 获取角色API export const getRolesApi = data => { 
     return get({ 
     url: "roles", data }) } // 新建角色API export const addRolesApi = data => { 
     return post({ 
     url: "roles", data }) } // 编辑角色API export const editRolesApi = data => { 
     return put({ 
     url: `roles/${ 
      data.id}`, data }) } // 删除角色API export const rolesDeleteApi = data => { 
     return del({ 
     url: `roles/${ 
      data.id}` }) } 

(其实内部结构差不多,文件名也写的很清楚。如果你喜欢,export const dog=data都可以。)

import { ref } from 'vue'; import { useForm } from '@/composables'; import { getRolesApi, addRolesApi, editRolesApi, rolesDeleteApi } from '@/util/request.js'; 
const rolesList = ref([]); const dialogFormVisible = ref(false); const formData = ref({ roleName: '', roleDesc: '' }); const userForm = ref(); 

在表单中,创建一个规则,标记某个项目必须填写

const rules = { roleName: { required: true, message: '此项必填', trigger: 'blur', }, }; 

我们还需要验证表单数据是否符合规则

const { validate } = useForm(userForm, formData, rules); 
  • userForm:一个响应式的对象,用于存储表单数据。
  • formData:一个普通的对象,包含了表单数据的初始值。
  • rules:一个普通的对象,包含了表单验证的规则。

在上面的代码中,当表单提交时,我们调用validate 方法进行验证。如果验证通过,就执行表单提交操作。如果验证失败,validate 方法会返回 false,我们可以在组件中根据这个返回值来进行错误提示等操作。

我们表单已经制作完成,下面就要执行以下步骤:

  1. 获取用户数据
  2. 编辑/添加
  3. 删除
  4. 新建

我们的思路是,通过API实现各种功能。通过异步处理就可以了

// 定义获取角色列表的函数 const getList = async () => { 
     const res = await getRolesApi(); rolesList.value = res.data; }; // 定义提交表单的函数 const submitForm = async () => { 
     const res = await validate(); if (!res) { 
     return; } if (formData.value.id) { 
     await editRolesApi(formData.value); } else { 
     await addRolesApi(formData.value); } dialogFormVisible.value = false; getList(); }; // 定义编辑角色的函数 const editRow = (row) => { 
     dialogFormVisible.value = true; const { 
     roleName, roleDesc, id } = row; formData.value = { 
     id, roleName, roleDesc }; }; // 定义删除角色的函数 const deleteRow = async (row) => { 
     await rolesDeleteApi(row); getList(); }; // 定义清空表单的函数 const clearForm = () => { 
     formData.value = { 
     roleName: '', roleDesc: '' }; }; // 初始化时获取角色列表 getList(); 

如果提交表单函数看不懂,我这里写了详细注释

// 定义提交表单的函数 const submitForm = async () => { // 首先调用了validate()方法来验证表单数据 // validate()方法是由上文引入的useForm自定义Hook返回的方法之一,用于验证表单数据是否符合预设的规则 // validate()方法返回一个Promise,我们使用await语句等待这个Promise解析 const res = await validate(); // 如果验证失败(validate()方法返回的Promise解析为false), // 那么我们立即返回,停止函数的执行,避免提交无效的表单数据 if (!res) { return; } // 如果表单数据(formData.value)中包含id字段,那么我们认为用户正在编辑一个已存在的角色 // 在这种情况下,我们调用editRolesApi()方法来更新这个角色的信息 // editRolesApi()方法接受一个包含角色数据的对象作为参数,并返回一个Promise,我们使用await语句等待这个Promise解析 if (formData.value.id) { await editRolesApi(formData.value); } else { // 如果表单数据(formData.value)中不包含id字段,那么我们认为用户正在创建一个新的角色 // 在这种情况下,我们调用addRolesApi()方法来创建新的角色 // addRolesApi()方法接受一个包含角色数据的对象作为参数,并返回一个Promise,我们使用await语句等待这个Promise解析 await addRolesApi(formData.value); } // 不论是创建新的角色还是编辑已存在的角色,我们都会在表单提交成功后隐藏表单对话框 // 我们通过将dialogFormVisible.value设为false来隐藏对话框 dialogFormVisible.value = false; // 表单提交成功后,我们需要获取最新的角色列表以便在页面上显示 // 我们通过调用getList()方法来获取最新的角色列表 getList(); }; 

好了,下面是roleList.vue完整代码

<template> <template> <div> <!-- 面包屑导航 --> <van-nav-bar> <template #left> <van-icon name="arrow-left" @click="goToHome" /> </template> <template #title> 角色列表 </template> </van-nav-bar> <!-- 白色内容区域 --> <div class="page_content"> <!-- 新建角色按钮 --> <van-button type="primary" @click="dialogFormVisible=true">新建角色</van-button> <!-- 表格展示角色列表 --> <van-list :data="rolesList"> <template #default="{item}"> <van-cell :title="item.roleName" :value="item.roleDesc"> <template #right-icon> <div class="buttons"> <van-button type="primary" plain size="small" @click="editRow(item)">编辑</van-button> <van-button type="danger" plain size="small" @click="deleteRow(item)">删除</van-button> </div> </template> </van-cell> </template> </van-list> </div> <!-- 新建/编辑角色弹窗表单 --> <van-popup v-model="dialogFormVisible" round> <van-form ref="userForm" :model="formData" :rules="rules" > <van-field name="roleName" label="角色名称" v-model="formData.roleName" placeholder="请输入角色名称" /> <van-field name="roleDesc" label="角色描述" v-model="formData.roleDesc" placeholder="请输入角色描述" /> <div class="buttons"> <van-button @click="clearForm">取消</van-button> <van-button type="primary" @click="submitForm(userForm)">确定</van-button> </div> </van-form> </van-popup> </div> </template> <script setup> import { ref } from 'vue'; // 引入Vue 3的ref功能,用于创建响应式数据 import { useForm } from '@/composables'; // 引入useForm自定义的表单处理函数 import { getRolesApi, addRolesApi, editRolesApi, rolesDeleteApi } from '@/util/request.js'; // 引入API方法,包括获取角色列表、增加角色、编辑角色和删除角色的方法 // 定义需要的响应式数据 const rolesList = ref([]); // 存放角色列表的响应式数据 const dialogFormVisible = ref(false); // 控制新建/编辑角色对话框的显示与隐藏 const formData = ref({ roleName: '', roleDesc: '' }); // 存放表单数据的响应式数据 const userForm = ref(); // 表单的引用 // 定义表单验证规则 const rules = { roleName: { required: true, message: '此项必填', trigger: 'blur', }, }; // 使用useForm函数处理表单验证 const { validate } = useForm(userForm, formData, rules); // 定义获取角色列表的函数 const getList = async () => { const res = await getRolesApi(); rolesList.value = res.data; }; // 定义提交表单的函数 const submitForm = async () => { const res = await validate(); if (!res) { return; } if (formData.value.id) { await editRolesApi(formData.value); } else { await addRolesApi(formData.value); } dialogFormVisible.value = false; getList(); }; // 定义编辑角色的函数 const editRow = (row) => { dialogFormVisible.value = true; const { roleName, roleDesc, id } = row; formData.value = { id, roleName, roleDesc }; }; // 定义删除角色的函数 const deleteRow = async (row) => { await rolesDeleteApi(row); getList(); }; // 定义清空表单的函数 const clearForm = () => { formData.value = { roleName: '', roleDesc: '' }; }; // 初始化时获取角色列表 getList(); </script> 

3.用户页面

<template> <div> <!-- 面包屑 --> <el-breadcrumb :separator-icon="ArrowRight"> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item>账号列表</el-breadcrumb-item> </el-breadcrumb> <!-- 白色内容区域 --> <div class="page_content"> <div class="flex"> <div class="input_box"> <el-input v-model="searchParams.query" placeholder="搜索关键字" class="input-with-select" > <template #append> <el-button @click="searchList"><el-icon><Search /></el-icon></el-button> </template> </el-input> </div> <el-button type="primary" @click="addUser">新建用户</el-button> </div> <!-- 表格 --> <!-- el-table 的 data:要展示的数据数组 el-table-column:列 prop每条数据的对应属性 label:列标题 scope.row:相当于一条数据 --> <el-table :data="userList" style="width: 100%"> <el-table-column prop="username" label="姓名" width="180" /> <el-table-column prop="email" label="邮箱" width="180" /> <el-table-column prop="mobile" label="电话" /> <el-table-column prop="role_name" label="角色" /> <el-table-column prop="mg_state" label="状态" > <template #default="scope"> <el-switch v-model="scope.row.mg_state" @change="switchChange(scope.row)" /> </template> </el-table-column> <el-table-column label="操作" > <template #default="scope"> <el-button type="primary" @click="editRow(scope.row)">编辑</el-button> <el-button type="danger" @click="deleteRow(scope.row)">删除</el-button> </template> </el-table-column> <!-- mg_state 状态 --> </el-table> <!-- 分页 --> <el-pagination v-model:currentPage="searchParams.pagenum" v-model:page-size="searchParams.pagesize" :page-sizes="[2,5,10,20]" :small="small" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="searchList" @current-change="searchList" /> </div> <!-- 新增弹窗 --> <el-dialog v-model="dialogFormVisible" title="新建用户"> <!-- 表单 | username | 用户名称 | 不能为空 | | password | 用户密码 | 不能为空 | | email | 邮箱 | 可以为空 | | mobile | 手机号 | 可以为空 | --> <el-form ref="userForm" :model="formData" :rules="rules" > <el-form-item label="用户名称" prop="username"> <el-input v-model="formData.username" placeholder="请输入用户名称" /> </el-form-item> <el-form-item label="用户密码" prop="password"> <el-input type="password" v-model="formData.password" placeholder="请输入密码" /> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="formData.email" placeholder="请输入用户邮箱" /> </el-form-item> <el-form-item label="手机号" prop="mobile"> <el-input v-model="formData.mobile" placeholder="请输入用户手机号" /> </el-form-item> </el-form> <template #footer> <div class="flex"> <el-button>取消</el-button> <el-button type="primary" @click="submitForm(userForm)" >确定</el-button> </div> </template> </el-dialog> <!-- 编辑弹窗 --> <el-dialog v-model="dialogFormEVisible" title="编辑用户"> <!-- 表单 | email | 邮箱 | 可以为空 | | mobile | 手机号 | 可以为空 | --> <el-form ref="userForm2" :model="formData2" :rules="rules2" > <el-form-item label="邮箱" prop="email"> <el-input v-model="formData2.email" placeholder="请输入用户邮箱" /> </el-form-item> <el-form-item label="手机号" prop="mobile"> <el-input v-model="formData2.mobile" placeholder="请输入用户手机号" /> </el-form-item> </el-form> <template #footer> <div class="flex"> <el-button>取消</el-button> <el-button type="primary" @click="submitEForm(userForm2)" >确定</el-button> </div> </template> </el-dialog> </div> </template> 

(以下是vant平替版本文档是element修改的,很多组件我没找着vant4可以替代,以下vant4代码仅供参考)

<template> <div> <!-- 面包屑 --> <!-- Vant没有面包屑组件,你可能需要自己实现,或者使用第三方库 --> <!-- 白色内容区域 --> <div class="page_content"> <div class="flex"> <div class="input_box"> <!-- 在Vant中,搜索框和按钮是两个独立的组件 --> <van-search v-model="searchParams.query" placeholder="搜索关键字" @search="searchList" /> <van-button type="primary" @click="addUser">新建用户</van-button> </div> </div> <!-- 表格 --> <!-- Vant没有表格组件,你可能需要自己实现,或者使用第三方库 --> <!-- 分页 --> <van-pagination v-model="searchParams.pagenum" :total-items="total" :items-per-page="searchParams.pagesize" @change="searchList" /> </div> <!-- 新增弹窗 --> <van-dialog v-model="dialogFormVisible" title="新建用户"> <!-- 表单 --> <van-form ref="userForm" :model="formData" :rules="rules"> <!-- 在Vant中,表单项和输入框是两个独立的组件 --> <van-field v-model="formData.username" label="用户名称" placeholder="请输入用户名称" required /> <van-field v-model="formData.password" label="用户密码" placeholder="请输入密码" type="password" required /> <van-field v-model="formData.email" label="邮箱" placeholder="请输入用户邮箱" type="email" /> <van-field v-model="formData.mobile" label="手机号" placeholder="请输入用户手机号" type="tel" /> </van-form> <van-button round block type="default" @click="dialogFormVisible = false">取消</van-button> <van-button round block type="primary" @click="submitForm(userForm)">确定</van-button> </van-dialog> <!-- 编辑弹窗 --> <van-dialog v-model="dialogFormEVisible" title="编辑用户"> <!-- 表单 --> <van-form ref="userForm2" :model="formData2" :rules="rules2"> <van-field v-model="formData2.email" label="邮箱" placeholder="请输入用户邮箱" type="email" /> <van-field v-model="formData2.mobile" label="手机号" placeholder="请输入用户手机号" type="tel" /> </van-form> <van-button round block type="default" @click="dialogFormEVisible = false">取消</van-button> <van-button round block type="primary" @click="submitEForm(userForm2)">确定</van-button> </van-dialog> </div> </template> 
// 获取用户列表API export const userListApi = data => { 
     return get({ 
     url: "/users", data }) } // 新增用户API export const userAddApi = data => { 
     return post({ 
     url: "/users", data }) } // 更改用户状态API export const userChangeStateApi = data => { 
     return put({ 
     url: `users/${ 
      data.id}/state/${ 
      data.mg_state}`, data }) } // 更改用户信息API export const userChangeInfoApi = data => { 
     return put({ 
     url: `users/${ 
      data.id}`, data }) } // 删除用户API export const userDeleteApi = data => { 
     return del({ 
     url: `users/${ 
      data.id}` }) } 

接下来写入我们的方法,以下是条件限制部分
这个我就不一一详解了,直接写注释里去了
这一部分我们写入的是用户基本信息的格式(规则),以及提交单的数组等

// 使用Vue 3的reactive方法创建一个响应性对象 const data = reactive({ 
     // searchParams对象包含了搜索参数 searchParams: { 
     query: "", // 查询字符串,默认为空 pagesize: 5, // 每页显示的数据量,默认为5 pagenum: 1 // 当前的页数,默认为第一页 }, total: 0, // 用于存储数据的总数量 userList: [], // 存储用户列表的数组 dialogFormVisible: false, // 控制添加用户的对话框是否可见,默认为不可见 dialogFormEVisible: false, // 控制编辑用户的对话框是否可见,默认为不可见 formData: { 
     // 添加用户的表单数据 username: "", // 用户名 password: "", // 密码 email: "", // 邮箱 mobile: "", // 手机号 }, formData2: { 
     // 编辑用户的表单数据 id: "", // 用户ID email: "", // 邮箱 mobile: "", // 手机号 }, // 添加用户的表单验证规则 rules: { 
     username: [ // 用户名规则 { 
     required: true, message: "此项为必填", trigger: "blur" } // 必填项,失去焦点时触发 ], password: [ // 密码规则 { 
     required: true, message: "此项为必填", trigger: "blur" } // 必填项,失去焦点时触发 ], email: [ // 邮箱规则 { 
     required: false, pattern: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-])+$/, // 邮箱的正则表达式规则 message: "请填写正确邮箱", trigger: "blur" } ], mobile: [ // 手机号规则 { 
     required: false, pattern: /^[1][3,4,5,7,8][0-9]{9}$/, // 手机号的正则表达式规则 message: "请填写正确手机号", trigger: "blur" } ] }, // 编辑用户的表单验证规则,规则同上 rules2: { 
     email: [ { 
     required: false, pattern: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-])+$/, message: "请填写正确邮箱", trigger: "blur" } ], mobile: [ { 
     required: false, pattern: /^[1][3,4,5,7,8][0-9]{9}$/, message: "请填写正确手机号", trigger: "blur" } ] } }) 

以下是功能性的方法

// 定义一个函数 searchList,它通过调用 userListApi 并传递搜索参数来获取用户列表 const searchList = () => { 
     userListApi(data.searchParams).then(res => { 
     if (res.data) { 
     // 如果响应中有数据 data.userList = res.data.users // 将响应数据中的用户列表存到 data.userList data.total = res.data.total // 将响应数据中的用户总数存到 data.total } }) } // 定义一个函数 addUser,用于显示添加用户的表单 const addUser = () => { 
     data.dialogFormVisible = true // 将 data.dialogFormVisible 设置为 true,通常用于在 UI 上显示表单 } // 定义一个函数 submitForm,用于提交添加用户的表单 const submitForm = (formEl) => { 
     formEl.validate(res => { 
     // 验证表单字段 if (!res) { 
     // 如果验证不通过 return // 直接返回,不再继续执行 } // 调用 userAddApi 来添加用户,并传递表单数据 userAddApi(data.formData).then(res => { 
     if (res.data) { 
     // 如果响应中有数据 data.dialogFormVisible = false // 隐藏表单 // 重置表单数据 data.formData = { 
     username: "", password: "", email: "", mobile: "", } searchList() // 添加用户成功后,重新获取用户列表 } }) }) } // 定义一个函数 submitEForm,用于提交编辑用户的表单 const submitEForm = (formEl) => { 
     formEl.validate(res => { 
     // 验证表单字段 if (!res) { 
     // 如果验证不通过 return // 直接返回,不再继续执行 } // 调用 userChangeInfoApi 来修改用户信息,并传递表单数据 userChangeInfoApi(data.formData2).then(res => { 
     if (res.data) { 
     // 如果响应中有数据 data.dialogFormEVisible = false // 隐藏表单 searchList() // 修改用户信息成功后,重新获取用户列表 } }) }) } // 定义一个函数 switchChange,用于切换用户的状态 const switchChange = row => { 
     // 调用 userChangeStateApi 来切换用户状态,并传递当前行数据 userChangeStateApi(row).then(res => { 
     if (res.data) { 
     // 如果响应中有数据 searchList() // 切换用户状态成功后,重新获取用户列表 } }) } // 定义一个函数 editRow,用于编辑用户信息 const editRow = row => { 
     const { 
     email, mobile, id } = row // 从当前行数据中解构出 email, mobile, id data.dialogFormEVisible = true // 显示编辑用户的表单 // 将 email, mobile, id 存到 data.formData2,这通常会自动填充到表单中 data.formData2.email = email data.formData2.mobile = mobile data.formData2.id = id } // 定义一个函数 deleteRow,用于删除用户 const deleteRow = row => { 
     // 调用 userDeleteApi 来删除用户,并传递当前行数据 userDeleteApi(row).then(res => { 
     searchList() // 删除用户成功后,重新获取用户列表 }) } // 执行 searchList 函数,获取用户列表 searchList() // 定义两个 ref,通常用于 Vue 3 Composition API 中的 ref 响应式引用 const userForm = ref() const userForm2 = ref() 

以下是uesrList.vue部分完整代码(element-plus版本)

<template> <div> <!-- 面包屑导航 --> <el-breadcrumb :separator-icon="ArrowRight"> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item>角色列表</el-breadcrumb-item> </el-breadcrumb> <!-- 白色内容区域 --> <div class="page_content"> <!-- 新建角色按钮 --> <el-button type="primary" @click="dialogFormVisible=true">新建角色</el-button> <!-- 表格展示角色列表 --> <el-table :data="rolesList" style="width: 100%"> <el-table-column prop="roleName" label="角色名" /> <el-table-column prop="roleDesc" label="角色描述" /> <!-- 表格操作列,包含编辑和删除按钮 --> <el-table-column> <template #default="scope"> <el-button type="primary" @click="editRow(scope.row)">编辑</el-button> <el-button type="danger" @click="deleteRow(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> <!-- 新建/编辑角色弹窗表单 --> <el-dialog v-model="dialogFormVisible" @close="clearForm" :title="formData.id?'编辑角色':'新建角色'"> <el-form ref="userForm" :model="formData" :rules="rules" > <el-form-item label="角色名称" prop="roleName"> <el-input v-model="formData.roleName" placeholder="请输入角色名称" /> </el-form-item> <el-form-item label="角色描述" prop="roleDesc"> <el-input v-model="formData.roleDesc" placeholder="请输入角色描述" /> </el-form-item> </el-form> <template #footer> <div class="flex"> <el-button>取消</el-button> <el-button type="primary" @click="submitForm(userForm)" >确定</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import { ref } from 'vue'; // 引入Vue 3的ref功能,用于创建响应式数据 import { useForm } from '@/composables'; // 引入useForm自定义的表单处理函数 import { getRolesApi, addRolesApi, editRolesApi, rolesDeleteApi } from '@/util/request.js'; // 引入API方法,包括获取角色列表、增加角色、编辑角色和删除角色的方法 // 定义需要的响应式数据 const rolesList = ref([]); // 存放角色列表的响应式数据 const dialogFormVisible = ref(false); // 控制新建/编辑角色对话框的显示与隐藏 const formData = ref({ roleName: '', roleDesc: '' }); // 存放表单数据的响应式数据 const userForm = ref(); // 表单的引用 // 定义表单验证规则 const rules = { roleName: { required: true, message: '此项必填', trigger: 'blur', }, }; // 使用useForm函数处理表单验证 const { validate } = useForm(userForm, formData, rules); // 定义获取角色列表的函数 const getList = async () => { const res = await getRolesApi(); rolesList.value = res.data; }; // 定义提交表单的函数 const submitForm = async () => { const res = await validate(); if (!res) { return; } if (formData.value.id) { await editRolesApi(formData.value); } else { await addRolesApi(formData.value); } dialogFormVisible.value = false; getList(); }; // 定义编辑角色的函数 const editRow = (row) => { dialogFormVisible.value = true; const { roleName, roleDesc, id } = row; formData.value = { id, roleName, roleDesc }; }; // 定义删除角色的函数 const deleteRow = async (row) => { await rolesDeleteApi(row); getList(); }; // 定义清空表单的函数 const clearForm = () => { formData.value = { roleName: '', roleDesc: '' }; }; // 初始化时获取角色列表 getList(); </script> 

4.商品页面

这一段代码没啥难的,老思路先写html

<template> <div> <!-- 面包屑 --> <el-breadcrumb :separator-icon="ArrowRight"> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item>商品列表</el-breadcrumb-item> </el-breadcrumb> <!-- 白色内容区域 --> <div class="page_content"> <div class="flex"> <div class="input_box"> <el-input v-model="searchParams.query" placeholder="搜索关键字" class="input-with-select" > <template #append> <el-button @click="searchList"><el-icon><Search /></el-icon></el-button> </template> </el-input> </div> </div> <!-- 表格 --> <!-- el-table 的 data:要展示的数据数组 el-table-column:列 prop每条数据的对应属性 label:列标题 scope.row:相当于一条数据 --> <el-table :data="goodsList" style="width: 100%"> <el-table-column prop="goods_name" label="商品名" width="180" /> <el-table-column prop="goods_price" label="价格(¥)" width="180" /> <el-table-column prop="goods_weight" label="商品重量(kg)" /> <el-table-column prop="goods_state" label="商品状态" > <template #default="scope"> <p>{ 
   {switchState(scope.row.goods_state)}}</p> </template> </el-table-column> </el-table> <!-- 分页 --> <el-pagination v-model:currentPage="searchParams.pagenum" v-model:page-size="searchParams.pagesize" :page-sizes="[2,5,10,20]" :small="small" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="searchList" @current-change="searchList" /> </div> </div> </template> 
// 获取商品列表API export const goodsListApi = data => { 
     return get({ 
     url: "goods", data }) } 
// 导入service中导出的HTTP方法 import { 
     post, get, put, del } from "./service" // 登录API export const loginApi = data => { 
     return post({ 
     url: "/login", data }) } // 获取用户列表API export const userListApi = data => { 
     return get({ 
     url: "/users", data }) } // 新增用户API export const userAddApi = data => { 
     return post({ 
     url: "/users", data }) } // 更改用户状态API export const userChangeStateApi = data => { 
     return put({ 
     url: `users/${ 
      data.id}/state/${ 
      data.mg_state}`, data }) } // 更改用户信息API export const userChangeInfoApi = data => { 
     return put({ 
     url: `users/${ 
      data.id}`, data }) } // 删除用户API export const userDeleteApi = data => { 
     return del({ 
     url: `users/${ 
      data.id}` }) } // 获取角色API export const getRolesApi = data => { 
     return get({ 
     url: "roles", data }) } // 新建角色API export const addRolesApi = data => { 
     return post({ 
     url: "roles", data }) } // 编辑角色API export const editRolesApi = data => { 
     return put({ 
     url: `roles/${ 
      data.id}`, data }) } // 删除角色API export const rolesDeleteApi = data => { 
     return del({ 
     url: `roles/${ 
      data.id}` }) } // 获取商品列表API export const goodsListApi = data => { 
     return get({ 
     url: "goods", data }) } 

(上文中使用的拦截器部分是vant4中的Toast,现在共享的是element-plus版本,代码不同,实现功能类似)

import axios from "axios" import { 
     ElLoading } from 'element-plus' import { 
     ElMessage } from 'element-plus' import store from "../store/index.js" // 创建一个axios实例,并设置请求超时时间、基础URL和请求头 const Service = axios.create({ 
     timeout: 8000, baseURL: "http://122.114.229.181:3000/api/private/v1/", headers: { 
     "Content-type": "application/json;charset=utf-8", "Authorization": store.state.uInfo.userInfo.token } }) // 请求拦截器:在发送请求之前执行 Service.interceptors.request.use(config => { 
     // 显示全屏加载动画 loadingObj = ElLoading.service({ 
     lock: true, text: 'Loading', background: 'rgba(0, 0, 0, 0.7)', }) // 返回修改后的请求配置 return config }) // 响应拦截器:在收到响应之后执行 Service.interceptors.response.use(response => { 
     // 关闭全屏加载动画 loadingObj.close() const data = response.data // 检查响应的状态码,如果不是200或201,显示错误消息 if (data.meta.status != 200 && data.meta.status != 201) { 
     ElMessage.error(data.meta.msg || "服务器出错") return data } // 返回响应数据 return data }, error => { 
     // 关闭全屏加载动画 loadingObj.close() // 如果发生错误,显示错误消息 ElMessage({ 
     message: "服务器错误", type: "error", duration: 2000 }) }) // post请求 export const post = config => { 
     // 使用Service实例发送post请求,并传入请求配置 return Service({ 
     ...config, method: "post", data: config.data }) } // get请求 export const get = config => { 
     // 使用Service实例发送get请求,并传入请求配置 return Service({ 
     ...config, method: "get", params: config.data }) } // put请求 export const put = config => { 
     // 使用Service实例发送put请求,并传入请求配置 return Service({ 
     ...config, method: "put", data: config.data }) } // delete请求 export const del = config => { 
     // 使用Service实例发送delete请求,并传入请求配置 return Service({ 
     ...config, method: "delete" }) } 

好的,接下来写业务逻辑,每句话的用途我都在注释中标明了。

<script setup> // 导入 reactive 和 toRefs 函数从 'vue' 库,reactive 用于创建响应式对象,toRefs 用于将响应式对象的属性转化为单独的响应式引用。 import { ref, reactive, toRefs } from 'vue' // 导入 goodsListApi 函数,这个函数可能是用于发起网络请求获取商品列表。 import { goodsListApi } from "@/util/request.js" // 使用 reactive 函数创建一个响应式对象 data,这个对象包含了 searchParams(搜索参数),total(商品总数),goodsList(商品列表)三个属性。 const data = reactive({ searchParams: { query: "", pagesize: 5, pagenum: 1 }, total: 0, goodsList: [], }) // 定义了一个函数 searchList,这个函数会调用 goodsListApi 函数发起网络请求,根据 data.searchParams 的值获取商品列表。 const searchList = () => { goodsListApi(data.searchParams).then(res => { if(res.data){ // 检查返回的 res 对象中是否包含 data 属性。 console.log("商品数据", res) // 在浏览器的控制台打印商品数据。 data.goodsList = res.data.goods // 将返回的商品数据赋值给 data.goodsList。 data.total = res.data.total // 将返回的商品总数赋值给 data.total。 } }) } // 定义了一个函数 switchState,这个函数接收一个状态码作为参数,根据状态码的值返回对应的状态字符串。 const switchState = (state) => { switch (state) { case 0: return "未通过" case 1: return "审核中" case 2: return "已审核" } } // 在初始化时调用 searchList 函数,这样在组件加载时就会自动获取商品列表。 searchList() // 使用 toRefs 函数将 data 对象转化为多个响应式引用,这样在模板中可以直接使用这些引用,而不需要通过 data 对象进行访问。 const { searchParams, total, goodsList } = toRefs(data) </script> 

5.补充一段Layout代码

先提供HTML+css

<template> <div class="common-layout"> <el-container class="el-container"> <el-header class="common-header flex-float"> <div class="flex"> <img class="logo" src="../../assets/logo.svg"> <h1 class="title">后台管理系统</h1> </div> <el-button type="danger" @click="loginOut">退出</el-button> </el-header> <el-container> <el-aside class="common-aside" width="200px"> <el-row class="tac"> <el-col > <el-menu active-text-color="#ffd04b" background-color="none" class="el-menu-vertical-demo" default-active="2" text-color="#fff" @open="handleOpen" @close="handleClose" :router="true" > <!-- 这里是账号管理这个分列--> <el-sub-menu index="1"> <template #title> <el-icon><Avatar /></el-icon> <span>账号管理</span> </template> <el-menu-item-group> <el-menu-item index="/user">账号列表</el-menu-item> </el-menu-item-group> <!-- <el-menu-item index="/">item two</el-menu-item>--> </el-sub-menu> <!-- 这里是账号管理分列--> <el-sub-menu index="2"> <template #title> <el-icon><Box /></el-icon> <span>角色管理</span> </template> <el-menu-item-group> <el-menu-item index="/roles">角色列表</el-menu-item> </el-menu-item-group> <!-- <el-menu-item index="/">item two</el-menu-item>--> </el-sub-menu> </el-menu> </el-col> <!-- <router-link to="/index">角色列表</router-link>--> <!-- <router-link to="/user">用户列表</router-link>--> </el-row> </el-aside> <el-main> <router-view></router-view> </el-main> </el-container> </el-container> </div> <el-row class="tac"> <el-col :span="12"> <h5 class="mb-2">Custom colors</h5> <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2" text-color="#fff" @open="handleOpen" @close="handleClose" > <el-sub-menu index="1"> <template #title> <el-icon><location /></el-icon> <span>Navigator One</span> </template> <el-menu-item index="1-1">item one</el-menu-item> <el-menu-item index="1-2">item two</el-menu-item> </el-sub-menu> <el-menu-item index="2"> <el-icon><icon-menu /></el-icon> <span>Navigator Two</span> </el-menu-item> <el-menu-item index="3" disabled> <el-icon><document /></el-icon> <span>Navigator Three</span> </el-menu-item> <el-menu-item index="4"> <el-icon><setting /></el-icon> <span>Navigator Four</span> </el-menu-item> </el-menu> </el-col> </el-row> </template> <style> .el-container { 
     height: 100vh; overflow: hidden; } .common-header { 
     background: #272d41; display: flex; } .common-aside { 
     background: #; } .logo { 
     width: 80px; } .title { 
     color: #f8f8f8; } .flex-float { 
     display: flex; justify-content: space-between; align-items: center; } .flex { 
     display: flex; align-items: center; } /*.title{*/ /* background-color: #fefefe;*/ /*}*/ </style> 

这段代码中,我们导入了一些必要的库和组件,同时定义了处理菜单展开、折叠和退出登录功能的函数。以下是详细的解释:

  1. 导入所需库和组件:
import { 
     Document, Menu as IconMenu, Location, Setting, } from '@element-plus/icons-vue'; // 导入 Element Plus 的图标组件 import { 
     useStore } from 'vuex'; // 导入 Vuex 的 useStore 函数,用于使用 Vuex 的 store import { 
     useRouter } from 'vue-router'; // 导入 Vue Router 的 useRouter 函数,用于使用 Vue Router 的实例 
  1. 定义处理菜单展开和折叠事件的函数:
const handleOpen = (key: string, keyPath: string[]) => { 
     console.log(key, keyPath); // 当菜单展开时,输出展开的菜单项 key 和 keyPath }; const handleClose = (key: string, keyPath: string[]) => { 
     console.log(key, keyPath); // 当菜单折叠时,输出折叠的菜单项 key 和 keyPath }; 

handleOpenhandleClose 函数在这个例子中只是简单地输出事件的信息。

  1. 获取 Vuex 的 store 和 Vue Router 的实例:
const store = useStore(); // 使用 Vuex 的 store const router = useRouter(); // 使用 Vue Router 的实例 
  1. 定义退出登录功能:
const loginOut = () => { 
     localStorage.removeItem('loginData'); // 移除本地存储的登录数据 store.commit('setUserInfo', { 
    }); // 通过 commit 函数,调用名为 'setUserInfo' 的 Vuex mutation,将用户信息设置为空对象 router.push({ 
     path: '/login' }); // 使用 Vue Router 的 push 函数,跳转到登录页面 }; 

总结:这段代码主要导入了所需的库和组件,并定义了处理菜单展开、折叠和退出登录功能的函数。通过使用 Vuex 和 Vue Router,我们能够实现对登录信息和页面跳转的控制。


免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121575.html

(0)
上一篇 2025-10-22 20:00
下一篇 2025-10-22 20:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信