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)使用刷新数据的方式来代替关闭事件(刷新数据可以是整个列表刷新,但是更加推荐当前行局部刷新,这样可以加快刷新效率,让后端在删除事件中返回需要刷新的局部数据即可)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39055970/article/details/120800987
今日推荐