21.番外篇——Ant Design Vue可展开table的实现
21.番外篇——Ant Design Vue可展开table的实现目标实现代码实现目标实现本章内容是使用Ant Design Vue实现与之前使用Element UI实现的类似角色表格,因为内容太多,所以采用点击展开的方式。代码实现...
21.番外篇——Ant Design Vue可展开table的实现
目标实现
本章内容是使用Ant Design Vue实现与之前使用Element UI实现的类似角色表格,因为内容太多,所以采用点击展开的方式。
代码实现
1.先实现简单的table
代码如下:
<template>
<div>
<!-- 面包屑区域 -->
<my-breadcrumb :items="items"></my-breadcrumb>
<!-- 卡片视图区域 -->
<a-card>
<!-- 添加角色按钮区域 -->
<a-col>
<a-button type="primary">添加角色</a-button>
</a-col>
<!-- 角色列表区域 -->
<a-table :columns="columns" :data-source="rolesList" rowKey="id" bordered></a-table>
</a-card>
</div>
</template>
<script>
import { getRolesList } from '@/api/role/role.js'
export default {
data () {
return {
// 面包屑菜单
items: [
{
href: '/roles',
title: '权限管理'
},
{
href: '/roles',
title: '角色列表'
}
],
// 所有角色权限列表数据
rolesList: [],
// 表格列
columns: [
{
title: '角色名称',
dataIndex: 'roleName'
},
{
title: '角色描述',
dataIndex: 'roleDesc'
}
]
}
},
created () {
this.getRolesList()
},
methods: {
// 获取角色列表
async getRolesList () {
const { data: res } = await getRolesList()
if (res.meta.status !== 200) {
return this.$message.error('获取列表失败')
}
this.rolesList = res.data
}
}
}
</script>
<style scoped>
/* @import url(); 引入css类 */
</style>
效果如下:
我们发现和Element UI区别很大,我们还没写点击展开的扩展行代码,但是表格却已经出现了类似的树结构,并且控制台报错[Vue warn]: Duplicate keys detected: '101'. This may cause an update error.
大致意思是说我们表格出现了重复的key,这样会导致更新的问题。
所以我查看了角色接口的数据:
发现他们的children数组(其实就是权限)确实存在key值重复的情况,然后再结合Ant Design Vue官网中的这段
破案了,就是Ant Design Vue的问题。
2.解决children的key值重复问题
将角色单独抽离出来,去掉children即可。
代码:
<template>
<div>
<!-- 面包屑区域 -->
<my-breadcrumb :items="items"></my-breadcrumb>
<!-- 卡片视图区域 -->
<a-card>
<!-- 添加角色按钮区域 -->
<a-col>
<a-button type="primary">添加角色</a-button>
</a-col>
<img src="C:\Users\Pactera\Desktop\1.jpg" alt="">
<!-- 角色列表区域 -->
<a-table :columns="columns" :data-source="rolesList" rowKey="id" bordered></a-table>
</a-card>
</div>
</template>
<script>
import { getRolesList } from '@/api/role/role.js'
export default {
data () {
return {
// 面包屑菜单
items: [
{
href: '/roles',
title: '权限管理'
},
{
href: '/roles',
title: '角色列表'
}
],
//
powerList: [],
// 所有角色权限列表数据
rolesList: [],
// 表格列
columns: [
{
title: '角色名称',
dataIndex: 'roleName'
},
{
title: '角色描述',
dataIndex: 'roleDesc'
}
// {
// title: '操作',
// key: 'action',
// scopedSlots: { customRender: 'action' }
// }
],
rowSelection: {
}
}
},
created () {
this.getRolesList()
},
methods: {
// 获取角色列表
async getRolesList () {
const { data: res } = await getRolesList()
if (res.meta.status !== 200) {
return this.$message.error('获取列表失败')
}
const powerList = this.powerList = res.data
this.rolesList = []
for (let i = 0; i < powerList.length; i++) {
this.rolesList.push({
id: powerList[i].id,
roleName: powerList[i].roleName,
roleDesc: powerList[i].roleDesc
})
}
console.log('this.rolesList', this.rolesList)
}
}
}
</script>
<style scoped>
/* @import url(); 引入css类 */
</style>
3.实现展开行
展开行的内容通过expandedRowRender插槽进行插入,详细代码如下:
<template>
<div>
<!-- 面包屑区域 -->
<my-breadcrumb :items="items"></my-breadcrumb>
<!-- 卡片视图区域 -->
<a-card>
<!-- 添加角色按钮区域 -->
<a-col>
<a-button type="primary">添加角色</a-button>
</a-col>
<img src="C:\Users\Pactera\Desktop\1.jpg" alt="">
<!-- 角色列表区域 -->
<a-table :columns="columns" :data-source="rolesList" rowKey="id" bordered>
<!-- 展开行区域 -->
<p slot="expandedRowRender" slot-scope="record,index" style="margin: 0">
<a-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1,i1) in powerList[index].children" :key="item1.id">
<!-- 渲染一级权限 -->
<a-col :span="5">
<!-- 这里close事件, @close="(e)=>{removeRightById(e,powerList[index], item1.id)}"这种写法可以携带方法自带参数和自定义参数,而不会产生覆盖的情况-->
<a-tag closable color="blue" @close="(e)=>{removeRightById(e,powerList[index], item1.id)}">{{item1.authName}} </a-tag>
<a-icon type="caret-right" />
</a-col>
<!-- 渲染二级权限 -->
<a-col :span="19">
<a-row :class="[i2 !== 0 ? 'bdtop' : '', 'vcenter']" v-for="(item2, i2) in item1.children" :key="item2.id">
<a-col :span="5">
<a-tag closable color="green" @close="(e)=>{removeRightById(e,powerList[index], item2.id)}">{{item2.authName}}</a-tag>
<a-icon type="caret-right" />
</a-col>
<!-- 渲染三级权限 -->
<a-col :span="18">
<a-tag v-for="(item3) in item2.children" :key="item3.id" closable color="orange" @close="(e)=>{removeRightById(e,powerList[index], item3.id)}">{{item3.authName}}</a-tag>
</a-col>
</a-row>
</a-col>
</a-row>
</p>
</a-table>
</a-card>
</div>
</template>
<script>
import { getRolesList, removeRightById } from '@/api/role/role.js'
export default {
data () {
return {
// 面包屑菜单
items: [
{
href: '/roles',
title: '权限管理'
},
{
href: '/roles',
title: '角色列表'
}
],
//
powerList: [],
// 所有角色权限列表数据
rolesList: [],
// 表格列
columns: [
{
title: '角色名称',
dataIndex: 'roleName'
},
{
title: '角色描述',
dataIndex: 'roleDesc'
}
// {
// title: '操作',
// key: 'action',
// scopedSlots: { customRender: 'action' }
// }
],
rowSelection: {
}
}
},
created () {
this.getRolesList()
},
methods: {
// 获取角色列表
async getRolesList () {
const { data: res } = await getRolesList()
if (res.meta.status !== 200) {
return this.$message.error('获取列表失败')
}
const powerList = this.powerList = res.data
this.rolesList = []
for (let i = 0; i < powerList.length; i++) {
this.rolesList.push({
id: powerList[i].id,
roleName: powerList[i].roleName,
roleDesc: powerList[i].roleDesc
})
}
console.log('this.rolesList', this.rolesList)
},
// 删除三级权限
async removeRightById (e, role, rightId) {
// 阻止默认关闭事件
e.preventDefault()
console.log(e)
this.$confirm({
title: '提示',
content: '此操作将永久删除该权限, 是否继续?',
cancelText: '取消',
okText: '确认',
onOk: async () => {
const { data: res } = await removeRightById(role, rightId)
if (res.meta.status !== 200) {
return this.$message.error('删除权限失败!')
}
// 直接给当前列表赋值,这样就相当于局部刷新,同时代替关闭事件
// this.getRolesList() // 会让整个列表重新加载,体验不好
role.children = res.data
},
onCancel: () => {
this.$message.info('取消了删除!')
}
})
}
}
}
</script>
<style lang="less" scoped>
/* @import url(); 引入css类 */
.ant-tag{
margin-top: 7px;
margin-bottom: 7px;
margin-right: 7px;
}
.bdtop {
border-top: 1px solid #eee;
}
.bdbottom {
border-bottom: 1px solid #eee;
}
.vcenter {
display: flex;
align-items: center;
}
</style>
4.展开行中使用tag的几个技巧
这里有几个小技巧:
1)tag的关闭事件不要直接写成:
@close="removeRightById(powerList[index], item1.id)"
这样会将原来的默认参数event覆盖,所以我们建议采用以下这种写法:
@close="(e)=>{removeRightById(e,powerList[index], item1.id)}"
这样就可以同时携带默认参数和其他自定义的参数了。其他组件也可能有类似情况,参照这种写法即可。
2)使用e.preventDefault()
阻止tag的默认关闭事件,因为一些情况下,我们通常需要询问才可以判断是否可以删除该tag。
3)使用刷新数据的方式来代替关闭事件(刷新数据可以是整个列表刷新,但是更加推荐当前行局部刷新,这样可以加快刷新效率,让后端在删除事件中返回需要刷新的局部数据即可)
更多推荐
所有评论(0)