【前端】Vue+Element UI案例:通用后台管理系统

您所在的位置:网站首页 VueElementplus的api离线 【前端】Vue+Element UI案例:通用后台管理系统

【前端】Vue+Element UI案例:通用后台管理系统

2024-07-17 05:28:11| 来源: 网络整理| 查看: 265

文章目录 目标代码0.结构1.按钮-删除2.按钮-编辑3.debug4.样式5.分页Pagination:功能6.分页Pagination:样式7.搜索框:功能8.搜索框:样式 总效果总代码修改和创建的文件User.vueapi下的index.jsapi下的mock.jsapi下的user.js 上一篇: 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出

参考视频:VUE项目,VUE项目实战,vue后台管理系统,前端面试,前端面试项目

案例链接【前端】Vue+Element UI案例:通用后台管理系统-导航栏(视频p1-16)https://blog.csdn.net/karshey/article/details/127640658【前端】Vue+Element UI案例:通用后台管理系统-Header+导航栏折叠(p17-19)https://blog.csdn.net/karshey/article/details/127652862【前端】Vue+Element UI案例:通用后台管理系统-Home组件:卡片、表格(p20-22)https://blog.csdn.net/karshey/article/details/127674643【前端】Vue+Element UI案例:通用后台管理系统-Echarts图表准备:axios封装、mock数据模拟实战(p23-25)https://blog.csdn.net/karshey/article/details/127735159【前端】Vue+Element UI案例:通用后台管理系统-Echarts图表:折线图、柱状图、饼状图(p27-30)https://blog.csdn.net/karshey/article/details/127737979【前端】Vue+Element UI案例:通用后台管理系统-面包屑、tag栏(p31-35)https://blog.csdn.net/karshey/article/details/127756733【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出(p36-38)https://blog.csdn.net/karshey/article/details/127787418【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table表格增删查改、Pagination分页、搜索框(p39-42)https://blog.csdn.net/karshey/article/details/127777962【前端】Vue+Element UI案例:通用后台管理系统-登陆页面Login(p44)https://blog.csdn.net/karshey/article/details/127795302【前端】Vue+Element UI案例:通用后台管理系统-登陆页面功能:登录权限跳转、路由守卫、退出(p45-46)https://blog.csdn.net/karshey/article/details/127849502【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由(p47-48)https://blog.csdn.net/karshey/article/details/127865621【前端】Vue+Element UI案例:通用后台管理系统-项目总结https://blog.csdn.net/karshey/article/details/127867638 目标

总体是这样:

在这里插入图片描述

需求:本篇主要是Table表格增删查改、Pagination分页。上篇已经完成了表单、对话框弹出。

表格Table显示用户数据用户数据由Mock随机生成,提供后端接口删除:可以删除用户数据,弹出消息提示搜索框:可以搜索用户数据分页效果 代码 0.结构

上篇已经完成了提交功能,但由于现在还没有表格,不知道自己写的对不对。我们先迅速地用组件把表格写出来。

当el-table元素中注入data对象数组后,在el-table-column中用prop属性来对应对象中的键名即可填入数据,用label属性来定义表格的列名。可以使用width属性来定义列宽。

在这里插入图片描述

效果:

在这里插入图片描述 我们先测试一下提交功能:

在这里插入图片描述 提交本身没问题,但细节有点问题:我们要规范一下出生日期的格式。

在这里插入图片描述 代码:添加value-format="yyyy-MM-DD"

1.按钮-删除

需求:

在这里插入图片描述

自定义列:列名操作按钮:编辑、删除点击后有弹窗

自定义列:

在这里插入图片描述

编辑 删除

点击后的弹窗功能:

在这里插入图片描述 methods如下:

this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$message({ type: 'success', message: '删除成功!' }); }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }); });

效果:删除数据+弹窗。

在这里插入图片描述

2.按钮-编辑

需求:

点击编辑后:打开表单把当前用户信息填上去(深拷贝)

显然会调用update的接口。

表单有新建和编辑两种打开方式:

新建:打开空表单,左上角为“新建”,调用接口为create编辑:打开表单,自动填进当前用户信息,左上角为“编辑”,调用接口为update

因此我们用一个变量modalType来表示是新建(0)还是编辑(1)。

代码:点击编辑按钮后标记modalType为1,打开表单,进行深拷贝。

// 编辑按钮 handleEdit(index) { this.modalType = 1 this.openForm() // 深拷贝 this.form = JSON.parse(JSON.stringify(index)) }, // 打开表单 openForm() { this.dialogVisible = true }

接下来的逻辑判断就由submit来实现:若modalType为0,则新增;否则修改:

// 表单提交 submit() { // 要用箭头函数,若用function会报错,不知道为什么 this.$refs.form.validate((valid) => { // 符合校验 if (valid) { // 提交数据 if (this.modalType === 0) { // 新增 createUser(this.form).then(() => { this.getList() }) } else { // 编辑 updateUser(this.form).then(() => { this.getList() }) } // 清空,关闭 this.closeDialog() } }) }

效果:确实显示在了表单中。显然还有一些问题,比如日期显示的是错误的,性别显示的是数字。我们在下一节修改它。

3.debug

debug:

点击新建则表单左上角显示新建,点击编辑则表单左上角显示编辑性别显示“男女”而非10

新建与编辑:

性别显示:

{{ scope.row.sex == 1 ? '男' : '女' }}

效果:在表格中的性别显示已经改过来了。至于为什么年龄匹配不上,且名为娟的会是男性…因为数据全是随机生成的(详见user.js中的mock.random)

在这里插入图片描述 但是出现了新的问题,点击编辑后自动填入的性别还是1和0,为什么呢?

在这里插入图片描述 原因:后端返回的数据中sex是integer(0,1)

for (let i = 0; i id: Mock.Random.guid(), name: Mock.Random.cname(), addr: Mock.mock('@county(true)'), 'age|18-60': 1, birth: Mock.Random.date(), sex: Mock.Random.integer(0, 1) }) ) }

而前端的表单中的value是String:

解决方法:动态绑定value,让它可以更改:

效果:

在这里插入图片描述

4.样式

当前样式:鼠标滚轮往下滑,可以看到表格的所有数据都显示在一页。许多数据会把table的高度撑的很大。我们要限制table的宽高。

在这里插入图片描述

在html中增加Attribute:height

在这里插入图片描述

这样会受控于外部样式,所以我们要给外部div也写上样式。

最大的div的高度占浏览器100%,common-table高度为父级的90%,于是el-table表格的高度为common-table的90%。

.manage { height: 100%; .common-table { height: 90%; } }

效果:

在这里插入图片描述

5.分页Pagination:功能

在这里插入图片描述

这只是结构,我们还要完成点击对应页码就跳转到对应Table页的效果:

在这里插入图片描述 参数为点击的页码:

// 改变页码 currentChange(val){ console.log(val); }

在这里插入图片描述 到这里我们可以确定:我们能通过currentChange获取到点击的页码,至于如何完成跳转呢?由于表格中显示哪些数据由getList这个函数决定,而getList又是由后端接口中的getUserList决定的: 我们可以看一下后端的接口文档。

/** * 获取列表 * 要带参数 name, page, limt; name可以不填, page,limit有默认值。 * @param name, page, limit * @return {{code: number, count: number, data: *[]}} */ getUserList: config => { const { name, page = 1, limit = 20 } = param2Obj(config.url) // console.log('name:' + name, 'page:' + page, '分页大小limit:' + limit) const mockList = List.filter(user => { if (name && user.name.indexOf(name) === -1 && user.addr.indexOf(name) === -1) return false return true }) const pageList = mockList.filter((item, index) => index = limit * (page - 1)) return { code: 20000, count: mockList.length, list: pageList } }

所以page页码数可以当作参数传给getUser。由注释可知:要带参数 name, page, limt; name可以不填, page,limit有默认值。显然传入的是一个对象。于是我们在data中定义这个对象:

page:要展示第page页limit:每页limit条数据,这里是默认值 pageData:{ page:1, limit:20 }

每次点击分页时就修改pageData.page,然后把它传给getUser。

// 获取列表数据 getList() { // 由接口文档知传入一个对象 getUser({params:{...this.pageData}}).then((data) => { this.tableData = data.data.list }) }

效果:数据竟然消失了?

在这里插入图片描述 看一下控制台,原来错误出在::8081/api/user/get?page=1&limit=20:1 Failed to load resource: the server responded with a status of 404 (Not Found)

由于我们之前定义的getUser是get方法,它的参数是会在url里的,而我们在mock里定义的:

Mock.mock('/api/user/get',user.getUserList)

是写死的,/api/user/get?page=1&limit=20与/api/user/get是匹配不上的!

解决方法:正则表达式。

Mock.mock(/\/api\/user\/get/,user.getUserList)

getList:

getList() { // 由接口文档知传入一个对象 getUser({ params: { ...this.pageData } }).then((data) => { this.tableData = data.data.list this.total = data.data.count || 0 }) }

改变页码:

// 改变页码 currentChange(val) { this.pageData.page = val this.getList() }

效果:

第一页: 在这里插入图片描述 第三页:

在这里插入图片描述

6.分页Pagination:样式

右下角。子绝父相。

.common-table { height: 90%; position: relative; .pager { position: absolute; right:20px; bottom: 0; } }

效果:(忽略搜索框!分页的样式是我最后写的…)

在这里插入图片描述

7.搜索框:功能

搜索框,但是用的是表单组件: 在这里插入图片描述 html:

查询

由于table显示的数据是本页数据+搜索到的数据的交集,我们要修改getList:

getList() { // 由接口文档知传入一个对象:要返回的是当前页面数据和搜索到的数据的交集 getUser({ params: { ...this.pageData,...this.searchForm } }).then((data) => { this.tableData = data.data.list this.total = data.data.count || 0 }) }

但凡触发了搜索事件:重新获取table数据即可。

search(){ this.getList() }

效果:

在这里插入图片描述

8.搜索框:样式

让新建按钮和搜索框并排:flex。 让搜索框的输入框和按钮并排:inline。

html:

css:

.manage { height: 100%; .manage-header { display: flex; justify-content: space-between; align-items: center; } .common-table { height: 90%; } }

效果:

在这里插入图片描述

总效果

在这里插入图片描述

总代码 修改和创建的文件

在这里插入图片描述

User.vue + 新增 取 消 确 定 查询 {{ scope.row.sex == 1 ? '男' : '女' }} 编辑 删除 import { getUser, createUser, deleteUser, updateUser } from '../api/index' export default { data() { return { // 表单绑定的数据 form: { name: '', age: '', sex: '', birth: '', addr: '' }, // 表单验证规则 rules: { name: [{ required: true, message: '请输入名称', trigger: 'blur' }], age: [{ required: true, message: '请输入年龄', trigger: 'blur' }], sex: [{ required: true, message: '请输入性别', trigger: 'blur' }], birth: [{ required: true, message: '请输入日期', trigger: 'blur' }], addr: [{ required: true, message: '请输入地址', trigger: 'blur' }], }, // 表单是否打开 dialogVisible: false, // 列表数据 tableData: [], // 打开表单:新建0,编辑1 modalType: 0, // 分页的对象 pageData: { page: 1, limit: 20 }, // 分页页数 total: 0, // 搜索框表单 searchForm: { name: '' } } }, methods: { // 获取列表数据 getList() { // 由接口文档知传入一个对象:要返回的是当前页面数据和搜索到的数据的交集 getUser({ params: { ...this.pageData, ...this.searchForm } }).then((data) => { this.tableData = data.data.list this.total = data.data.count || 0 }) }, // 表单提交 submit() { // 要用箭头函数,若用function会报错,不知道为什么 this.$refs.form.validate((valid) => { // 符合校验 if (valid) { // 提交数据 if (this.modalType === 0) { // 新增 createUser(this.form).then(() => { this.getList() }) } else { // 编辑 updateUser(this.form).then(() => { this.getList() }) } // 清空,关闭 this.closeDialog() } }) }, // 关闭对话框 closeDialog() { // 先重置 this.$refs.form.resetFields() // 后关闭 this.dialogVisible = false }, // 编辑按钮 handleEdit(index) { this.modalType = 1 this.openForm() // 深拷贝 this.form = JSON.parse(JSON.stringify(index)) }, // 删除按钮 handleDelete(index) { this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { // 删除操作:根据后端接口,参数是对象,id是唯一标识符 deleteUser({ id: index.id }).then(() => { this.$message({ type: 'success', message: '删除成功!' }) this.getList() }); }).catch(() => { // 点击取消:不删除了 this.$message({ type: 'info', message: '已取消删除' }); }); }, // 新建按钮 handlecreate() { this.modalType = 0 this.openForm() }, // 打开表单 openForm() { this.dialogVisible = true }, // 改变页码 currentChange(val) { this.pageData.page = val this.getList() }, // 搜索 search() { this.getList() } }, mounted() { this.getList() } } .manage { height: 100%; .manage-header { display: flex; justify-content: space-between; align-items: center; } .common-table { height: 90%; position: relative; .pager { position: absolute; right:20px; bottom: 0; } } } api下的index.js import http from '../utils/request' // 请求首页数据,直接把这个对象导出 export const getData = () => { // 返回一个promise return http.get('/home/getData') } // 下面四个:用户管理-后端-网络请求接口 export const getUser = (params) => { return http.get('/user/get/', params) } export const createUser = (data) => { return http.post('/user/create', data) } export const deleteUser = (data) => { return http.post('/user/del', data) } export const updateUser = (data) => { return http.post('/user/update', data) } api下的mock.js import Mock from 'mockjs' import homeMock from '../api/mockServe/home' import user from './user' // 定义mock拦截 Mock.mock('/api/home/getData',homeMock) // 用户管理:增删查改 Mock.mock(/\/api\/user\/get/,user.getUserList) Mock.mock('/api/user/create','post',user.createUser) Mock.mock('/api/user/update','post',user.updateUser) Mock.mock('/api/user/del','post',user.deleteUser) api下的user.js import Mock from 'mockjs' // get请求从config.url获取参数,post从config.body中获取参数 function param2Obj (url) { const search = url.split('?')[1] if (!search) { return {} } return JSON.parse( '{"' + decodeURIComponent(search) .replace(/"/g, '\\"') .replace(/&/g, '","') .replace(/=/g, '":"') + '"}' ) } let List = [] const count = 200 for (let i = 0; i id: Mock.Random.guid(), name: Mock.Random.cname(), addr: Mock.mock('@county(true)'), 'age|18-60': 1, birth: Mock.Random.date(), sex: Mock.Random.integer(0, 1) }) ) } export default { /** * 获取列表 * 要带参数 name, page, limt; name可以不填, page,limit有默认值。 * @param name, page, limit * @return {{code: number, count: number, data: *[]}} */ getUserList: config => { const { name, page = 1, limit = 20 } = param2Obj(config.url) // console.log('name:' + name, 'page:' + page, '分页大小limit:' + limit) const mockList = List.filter(user => { if (name && user.name.indexOf(name) === -1 && user.addr.indexOf(name) === -1) return false return true }) const pageList = mockList.filter((item, index) => index = limit * (page - 1)) return { code: 20000, count: mockList.length, list: pageList } }, /** * 增加用户 * @param name, addr, age, birth, sex * @return {{code: number, data: {message: string}}} */ createUser: config => { const { name, addr, age, birth, sex } = JSON.parse(config.body) console.log(JSON.parse(config.body)) List.unshift({ id: Mock.Random.guid(), name: name, addr: addr, age: age, birth: birth, sex: sex }) return { code: 20000, data: { message: '添加成功' } } }, /** * 删除用户 * @param id * @return {*} */ deleteUser: config => { const { id } = JSON.parse(config.body) if (!id) { return { code: -999, message: '参数不正确' } } else { List = List.filter(u => u.id !== id) return { code: 20000, message: '删除成功' } } }, /** * 批量删除 * @param config * @return {{code: number, data: {message: string}}} */ batchremove: config => { let { ids } = param2Obj(config.url) ids = ids.split(',') List = List.filter(u => !ids.includes(u.id)) return { code: 20000, data: { message: '批量删除成功' } } }, /** * 修改用户 * @param id, name, addr, age, birth, sex * @return {{code: number, data: {message: string}}} */ updateUser: config => { const { id, name, addr, age, birth, sex } = JSON.parse(config.body) const sex_num = parseInt(sex) List.some(u => { if (u.id === id) { u.name = name u.addr = addr u.age = age u.birth = birth u.sex = sex_num return true } }) return { code: 20000, data: { message: '编辑成功' } } } }


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭