基于Antd-Vue3的a-table组件嵌套Table以及选择框联动操作

嵌套表格带选择

难点

选择时让父级选择有中间态
1.设置子Table手动选择/取消某行的回调
2.设置父Table手动选择/取消某行的回调
3.设置父Table手动选择/取消选择所有行的回调

1.vue代码

<a-table
  :columns="columns"
  :data-source="data"
  :pagination="false"
  :scroll="billScroll"
  :row-selection="parentRowSelection"
  class="components-table-demo-nested"
>
  <template #expandedRowRender="{record}">
    <a-table
      :columns="innerColumns"
      :data-source="record.child"
      :scroll="{x:'max-content'}"
      :row-selection="childRowSelection"
      :pagination="false"
    />
  </template>
</a-table>

2.js代码

const columns = [{
  title: '代码',
  dataIndex: 'name'
}, {
  title: '营业项目',
  dataIndex: 'platform'
}, {
  title: '笔数',
  dataIndex: 'version'
}, {
  title: '金额',
  dataIndex: 'upgradeNum'
}]
const data = [
  {
    key: 1,
    name: '1',
    platform: '房费1',
    version: '1',
    upgradeNum: 500,
    child: [
      {
        key: 3,
        date: '2014-12-24 23:12:00',
        name: 'This is production name 0',
        state: '2022-12-12',
        upgradeNum: 'Upgraded: 56',
        code: 'xxx',
        business: '2022-12-12',
        time: '2022-11-11 16:23:48',
        comment: '这是一个备注xxxxxxxxxxxxxxxxxx',
        amount: 'xxxx',
        card: '2222222',
        sta: '正常',
        rea: '理由',
        opt: '操作'
      },
      {
        key: 4,
        date: '2014-12-24 23:12:00',
        name: 'This is production name 0',
        state: '2022-12-12',
        upgradeNum: 'Upgraded: 56',
        code: 'xxx',
        business: '2022-12-12',
        time: '2022-11-11 16:23:48',
        comment: '这是一个备注xxxxxxxxxxxxxxxxxx',
        amount: 'xxxx',
        card: '2222222',
        sta: '正常',
        rea: '理由',
        opt: '操作'
      },
      {
        key: 5,
        date: '2014-12-24 23:12:00',
        name: 'This is production name 0',
        state: '2022-12-12',
        upgradeNum: 'Upgraded: 56',
        code: 'xxx',
        business: '2022-12-12',
        time: '2022-11-11 16:23:48',
        comment: '这是一个备注xxxxxxxxxxxxxxxxxx',
        amount: 'xxxx',
        card: '2222222',
        sta: '正常',
        rea: '理由',
        opt: '操作'
      }
    ]
  },
  {
    key: 2,
    name: '2',
    platform: '房费2',
    version: '2',
    upgradeNum: 500,
    child: [
      {
        key: 6,
        date: '2014-12-24 23:12:00',
        name: 'This is production name 0',
        state: '2022-12-12',
        upgradeNum: 'Upgraded: 56',
        code: 'xxx',
        business: '2022-12-12',
        time: '2022-11-11 16:23:48',
        comment: '这是一个备注xxxxxxxxxxxxxxxxxx',
        amount: 'xxxx',
        card: '2222222',
        sta: '正常',
        rea: '理由',
        opt: '操作'
      },
      {
        key: 7,
        date: '2014-12-24 23:12:00',
        name: 'This is production name 0',
        state: '2022-12-12',
        upgradeNum: 'Upgraded: 56',
        code: 'xxx',
        business: '2022-12-12',
        time: '2022-11-11 16:23:48',
        comment: '这是一个备注xxxxxxxxxxx',
        amount: 'xxxx',
        card: '2222222',
        sta: '正常',
        rea: '理由',
        opt: '操作'
      },
      {
        key: 8,
        date: '2014-12-24 23:12:00',
        name: 'This is production name 0',
        state: '2022-12-12',
        upgradeNum: 'Upgraded: 56',
        code: 'xxx',
        business: '2022-12-12',
        time: '2022-11-11 16:23:48',
        comment: '这是一个备注xxxxxxxxxxxxxxxxxx',
        amount: 'xxxx',
        card: '2222222',
        sta: '正常',
        rea: '理由',
        opt: '操作'
      }
    ]
  }
]

const innerColumns = [
  {
    title: '账目ID',
    dataIndex: 'date'
  },
  {
    title: '房号',
    dataIndex: 'name'
  },
  {
    title: '营业日期',
    dataIndex: 'date'
  },
  {
    title: '账目类型',
    dataIndex: 'upgradeNum'
  },
  {
    title: '代码',
    dataIndex: 'code'
  },
  {
    title: '营业项目',
    dataIndex: 'business'
  },
  {
    title: '金额',
    dataIndex: 'amount'
  },
  {
    title: '银行卡号',
    dataIndex: 'card'
  },
  {
    title: '状态',
    dataIndex: 'sta'
  },
  {
    title: '入账时间',
    dataIndex: 'time'
  },
  {
    title: '备注',
    dataIndex: 'comment'
  },
  {
    title: '理由',
    dataIndex: 'rea'
  },
  {
    title: '操作',
    dataIndex: 'opt'
  }
]

//获取数据时更新获取dom的节点 billRef 为table的节点
const queryData = async() =>{
const res = await fetchData()
if(res.data){
	data.value = res.data
	checkboxDomList.value = [...billRef.value.querySelectorAll('label.ant-checkbox-wrapper span:not(.ant-checkbox-inner)')]
	}
}

// 外部多选内部多选
const parentSelectedRowKeys = ref([])
const parentRowSelection = {
  fixed: true,
  selectedRowKeys: parentSelectedRowKeys,
  onSelect: (record, selected, selectedRows) => {
    // setChildArr:选择父Table下的所有子选项
    const setChildArr = data.find(d => d.key === record.key).child.map(item => item.key)
    // 第一步 判断selected true:选中,false,取消选中
    if (selected) {
      // 第二步,父Table选中,子Table全选中(全部整合到一起,然后去重)
      parentSelectedRowKeys.value.push(record.key)
      childSelectedRowKeys.value = Array.from(new Set([...setChildArr, ...childSelectedRowKeys.value]))
    } else {
      // 第二步,父Table取消选中,子Table全取消选中(针对childSelectedRowKeys,过滤掉取消选中的父Table下的所有子Table的key)
      parentSelectedRowKeys.value.splice(parentSelectedRowKeys.value.findIndex(item => item === record.key), 1)
      childSelectedRowKeys.value = childSelectedRowKeys.value.filter(item => !setChildArr.some(e => e === item))
    }
    // 第三步, 判断所有子选项长度  是否为全选
    checkAllSelected()
  },
  onSelectAll: (selected, selectedRows, changeRows) => {
    // 将改变的父Table下的子Table下的key都添加到setChildArr中
    let setChildArr = []
    changeRows.forEach(e => {
      setChildArr = [...setChildArr, ...e.child.map(item => item.key)]
    })
    // 第一步判断selected true:全选,false:取消全选
    if (selected) {
      // 第二步:父Table选中,子Table全选中,设置子Table的SelectedRowKeys
      parentSelectedRowKeys.value = Array.from(new Set([...parentSelectedRowKeys.value, ...changeRows.map(item => item.key)]))
      childSelectedRowKeys.value = setChildArr
    } else {
      // 第二步:父Table取消选中,子Table全取消选中,设置子Table的SelectedRowKeys
      parentSelectedRowKeys.value = parentSelectedRowKeys.value.filter(item => !changeRows.some(e => e.key === item))
      childSelectedRowKeys.value = []
    }
  }
}
const childSelectedRowKeys = ref([])
const childRowSelection = {
  fixed: true,
  hideSelectAll: true,
  selectedRowKeys: childSelectedRowKeys,
  onSelect: (record, selected, selectedRows) => {
    //  record:选择的行数据 selected:当前行是否选择 true/false selectedRows:选择的行 如果选择分组的行上个数据会变成[undefined, undefined, {…}]
    // 1.设置子Table手动选择/取消某行的回调 onSelect
    // 1.1 判断selected true:选中,将key值添加到childSelectedRowKeys,false:取消选中,将key值从childSelectedRowKeys中移除
    if (selected) {
      childSelectedRowKeys.value.push(record.key)
    } else {
      childSelectedRowKeys.value.splice(childSelectedRowKeys.value.findIndex(item => item === record.key), 1)
    }

    // 1.1.1 必须去除undefined,否则selectedRows会将其他子Table中选中的key值放到数组中,但是值为undefined,如:[ undefined,1,uundefined]
    selectedRows = selectedRows.filter(item => item !== undefined)

    // 1.2 判断selectedRows的长度是否为data中child的长度,相等,就将父table选中,不等就不选中
    for (const [index, item] of data.entries()) {
      // 1.2.1 如果当前选择的在一个分组中   find返回对象  没有undefined
      if (item.child.find(d => d.key === record.key)) {
        // 1.2.2 判断长度相等  将父级的key加入
        if (item.child.length === selectedRows.length) {
          parentSelectedRowKeys.value.push(item.key)
        } else {
          // 1.2.3 不相等 将父级的key进行删除
          if (parentSelectedRowKeys.value.some(d => d === item.key)) {
            parentSelectedRowKeys.value.splice(parentSelectedRowKeys.value.findIndex(item1 => item1 === item.key), 1)
          }
          // 1.2.4 先找出data.child的数据的key集合
          const setChildArr = item.child.map(item => item.key)
          // 1.2.5 更新父级行的选择状态  判断选择的行中是否存在key在setChildArr中
          setTimeout(() => {
            if (setChildArr.some(k => selectedRows.some(j => k === j.key))) {
              checkboxDomList.value[index + 1].setAttribute('class', 'ant-checkbox-indeterminate')
            } else {
              checkboxDomList.value[index + 1].removeAttribute('class', 'ant-checkbox-indeterminate')
            }
          }, 0)
        }
        // 1.2.6 判断所有子选项长度  是否为全选
        checkAllSelected()
        break
      }
    }
  }
}
const checkAllSelected = () => {
  const allChildKey = []
  data.forEach(item => {
    allChildKey.push(...item.child.map(i => i.key))
  })
  setTimeout(() => {
    // 如果有长度 为中间态
    if (childSelectedRowKeys.value.length) {
      checkboxDomList.value[0].setAttribute('class', 'ant-checkbox-indeterminate')
      // 全部相等
      if (allChildKey.length === childSelectedRowKeys.value.length) {
        checkboxDomList.value[0].setAttribute('class', 'ant-checkbox-checked')
      } else {
        checkboxDomList.value[0].removeAttribute('class', 'ant-checkbox-checked')
        checkboxDomList.value[0].setAttribute('class', 'ant-checkbox-indeterminate')
      }
    } else {
      checkboxDomList.value[0].removeAttribute('class', 'ant-checkbox-indeterminate')
    }
  }, 0)
}

总结

希望对大家有帮助,有问题大家一起探讨!

Logo

前往低代码交流专区

更多推荐