ElementUI组件table展开expand子项动态获取数据时,视图不更新

最近碰到一个新的需求,先是需要获取用户组列表(做成表格),表格项可以展开,在展开的时候动态的获取所展开的用户组底下的用户列表。

问题描述

起初,我是把表格数据分开来,即外层用户组列表使用list数组,内层嵌套的用户列表使用innerList数组,两者互不干扰。然后监听外层表格的expand-change事件,在事件回调中配合表格属性expand-row-keys来控制展开的行(需求是手风琴模式,即一次最多展开一行),同时回调中去动态请求数据,数据返回后对innerList进行赋值。
示例Demo代码如下:

<template> 
  <!-- 外层为用户组数据 -->
  <el-table 
 	:data="list" 
 	style="width: 100%" 
 	@expand-change="handleExpandChange" 
 	:expand-row-keys="currentExpandRow" 
 	row-key="id"
  > 
    <el-table-column type="expand"> 
      <!-- 内层为用户列表数组 -->
      <el-table :data="innerList" style="width: 100%"> 
        <el-table-column prop="user_id" label="用户ID" />
        <el-table-column prop="nickname" label="昵称" /> 
      </el-table>
    </el-table-column> 
    <el-table-column prop="id" label="ID" /> 
 	<el-table-column prop="user_group_name" label="组名" />  
  </el-table>  
</template>

对应的data还有methods

<script>
export default {
  data() {
    return {
      list: [],
      innerList: [],
      currentExpandRow: []
    }
  },
  methods: {
    // 获取某个用户组中的用户列表
    async handleExpandChange(row) {
      const currentID = this.currentExpandRow[0] ? this.currentExpandRow[0] : ''
      if (currentID == row.id) {
        this.currentExpandRow = []
        return
      }
      const groupID = row.id
      this.currentExpandRow = [groupID] // 控制展开行
      const res = await this.axios.post('getData', {
        groupID
      })
      this.innerList = res.data.data.data
    }
  }
}
</script>

一番操作后,发现展开后数据确确实实是拿到了,可是视图却不更新,确切的讲,是不会及时更新,展开后的内嵌表格会渲染上一次拿到的数据,即第一次展开无数据,第二次展开渲染第一次获取的数据,依次类推。
于是我便在事件的最后加上this.$forceUpdate()强制更新,然而并没有什么卵用。

如何解决?

首先当然还是百度,谷歌了,可是一番查找后,并没有理想的方案,网上给的方案大多用this.$set去处理,可实际操作起来并没有解决。
在捣鼓的过程中,发现了this.currentExpandRow的赋值会触发视图的更新,于是我便在事件的最后用$nextTick去赋值这个变量,结果是能成功,但是常常会出现拿不到数据(空白)。
怎么办呢?只好返回官网去找答案了。

解决

参照着官网的示例代码,我发现了好像只能在外层的list内部去内嵌innerList
简单点讲,就是表格组件的更新,是看最外层的data所绑定的变量,只要它一改变,那么视图也会相应的更新。
改动后的Demo代码如下:

<template> 
  <!-- 外层为用户组数据 -->
  <el-table
    :data="list"
    style="width: 100%"
    @expand-change="handleExpandChange"
    :expand-row-keys="currentExpandRow"
    row-key="id"
  >
    <el-table-column type="expand">
      <template slot-scope="props">
      	<!-- 内层为用户列表数组 -->
        <el-table :data="props.row.innerList" style="width: 100%">
          <el-table-column prop="user_id" label="用户ID" />
          <el-table-column prop="nickname" label="昵称" />
        </el-table>
      </template>
    </el-table-column>
    <el-table-column prop="id" label="ID" />
    <el-table-column prop="user_group_name" label="组名" />
  </el-table>
</template>

对应的data还有methods

<script>
export default {
  data() {
    return {
      list: [],
      currentExpandRow: []
    }
  },
  methods: {
    // 获取某个用户组中的用户列表
    async handleExpandChange(row) {
      const currentID = this.currentExpandRow[0] ? this.currentExpandRow[0] : ''
      if (currentID == row.id) {
        this.currentExpandRow = []
        return
      }
      let currentIndex = 0
      this.list.some((item, index) => {
        if (item.id === row.id) {
          currentIndex = index
          return true
        }
      })
      const groupID = row.id
      this.currentExpandRow = [groupID] // 控制展开行
      const res = await this.axios.post('getData', {
        groupID
      })
      this.$set(this.list[currentIndex], 'innerList', res.data.data.data)
    }
  }
}
</script>

我将原本的innerList内嵌到list
DOM中是对table-column做多一层template包裹,通过props传每一行的innerList作为内嵌表格的data
事件回调中去获取当前点击行的currentIndex,在获取数据的最后通过$set去做数据的赋值。
这样做就能完美的渲染内嵌表格列表了,后续还能为内嵌表格增加分页功能!

总结

接触了UI库这么久了,感觉有些需要自定义的需求写起来还是有点费脑,不知道是本人代码水平还不够高还是官方文档不够明示,还是得继续学习!
Keep learning…

  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的示例,使用Angular Material的cdk-tree组件实现树状表格,点击展开按钮可以获取下级数据。 在这个示例中,我们假设有一个名为Node的数据模型,每个节点都有一个id属性和一个children属性,表示该节点的子节点。我们将创建一个名为TreeTableComponent的组件,用于显示树状表格,并绑定节点数据。 首先需要安装Angular Material和CDK: ``` npm install --save @angular/material @angular/cdk ``` 接下来,导入所需的Angular Material组件和CDK: ``` import { Component } from '@angular/core'; import { CdkTreeModule } from '@angular/cdk/tree'; import { MatTreeModule } from '@angular/material/tree'; ``` 然后,定义Node节点的数据模型: ``` interface Node { id: number; children?: Node[]; } ``` 接下来,创建TreeTableComponent组件,定义节点数据和树控件: ``` @Component({ selector: 'app-tree-table', template: ` <mat-tree [dataSource]="dataSource"> <mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding> <button mat-icon-button disabled></button> {{node.id}} </mat-tree-node> <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding> <button mat-icon-button (click)="toggleNode(node)"> <mat-icon>{{node.expanded ? 'expand_more' : 'chevron_right'}}</mat-icon> </button> {{node.id}} <div [class.hidden]="!node.expanded"> <ng-container matTreeNodeOutlet></ng-container> </div> </mat-nested-tree-node> </mat-tree> ` }) export class TreeTableComponent { nodes: Node[] = [ { id: 1, children: [ { id: 2, children: [ { id: 3 }, { id: 4 }, { id: 5 } ] }, { id: 6, children: [ { id: 7 }, { id: 8 }, { id: 9 } ] } ] } ]; dataSource = this.nodes; hasChild = (_: number, node: Node) => !!node.children && node.children.length > 0; toggleNode(node: Node) { node.expanded = !node.expanded; if (node.expanded && !node.children) { // load children data node.children = [{id: 10}, {id: 11}, {id: 12}]; } } } ``` 在这个组件中,我们首先定义了一个名为nodes的节点数据数组,它表示树的根节点。然后,我们将该数组绑定到dataSource属性,作为树的数据源。 接下来,我们定义了一个名为hasChild的函数,用于判断节点是否有子节点。如果节点具有子节点,则返回true,否则返回false。 然后,我们定义了一个名为toggleNode的函数,用于切换节点的展开状态。如果节点已经展开,则将其折叠;如果节点是折叠的,则将其展开。如果节点展开且没有子节点,则加载子节点数据,并将其添加到节点的children属性中。 最后,我们在组件的HTML模板中使用Angular Material的cdk-tree组件和MatTreeModule模块来显示树状表格。我们使用matTreeNodeDef指令定义树节点和嵌套树节点,用于在不同的节点级别显示不同的内容。我们使用matTreeNodePadding指令来添加缩进和填充,以使树节点在视觉上分层。我们使用mat-icon-button组件来显示折叠/展开图标,并使用mat-icon组件来显示不同的图标。我们使用ng-container组件来嵌套树节点,并在需要使用matTreeNodeOutlet指令动态加载子节点。 这样,就实现了一个简单的树状表格组件,可以展开折叠节点并获取子节点数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值