Element Plus 树形表格全选多选以及子节点勾选

<template>
  <div>
    <el-table
      ref="multipleDevCreateRef"
      v-model:selected-row-keys="multipleDevCreateList"
      :data="tableData"
      style="width: 100%"
      row-key="Path"
      default-expand-all
      @select="select"
      @select-all="selectAll"
      @selection-change="handleSelectionChange"
      :tree-props="{ children: 'Children' }"
      :row-class-name="tableRowClassName"
    >
      <el-table-column type="selection" width="55" :selectable="selectable" />
      <el-table-column property="Path" label="设备名" width="240" />
      <el-table-column property="TypStr" label="类型" />
      <el-table-column property="Mount" label="挂载点" />
      <el-table-column property="Capacity" label="容量" />
    </el-table>
  </div>
</template>

<script setup lang="ts">
interface nodeItem {
  Path: string // 路径
  Capacity: string // 空间
  Parent: string // 父节点(如果空就是根节点)
  Mount: string // 挂载点
  Typstr: string // 类型
  IsUsed: boolean // 是否使用
  Children?: nodeItem[]
}

const multipleDevCreateRef = ref<InstanceType<typeof ElTable>>()
const multipleDevCreateList = ref<nodeItem[]>([])
const handleSelectionChange = (value: nodeItem[]) => {
  multipleDevCreateList.value = multipleDevCreateRef.value?.getSelectionRows()
}

// 转化前数据:
/* [
    {
        "Capacity": "20.0GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "",
        "Path": "/dev/sdb",
        "TypStr": "disk"
    },
    {
        "Capacity": "19.9GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "/dev/sdb",
        "Path": "/dev/sdb1",
        "TypStr": "part"
    },
    {
        "Capacity": "200.0GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "",
        "Path": "/dev/sdc",
        "TypStr": "disk"
    },
    {
        "Capacity": "190.0GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "/dev/sdc",
        "Path": "/dev/sdc1",
        "TypStr": "part"
    },
    {
        "Capacity": "9.9GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "/dev/sdc",
        "Path": "/dev/sdc2",
        "TypStr": "part"
    },
    {
        "Capacity": "20.0GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "",
        "Path": "/dev/sdd",
        "TypStr": "disk"
    },
    {
        "Capacity": "19.9GB",
        "IsUsed": false,
        "Mount": "",
        "Parent": "/dev/sdd",
        "Path": "/dev/sdd1",
        "TypStr": "part"
    }
] */
// 转化后的数据
const tableData = ref<any[]>([
  {
    Capacity: '200.0GB',
    IsUsed: false,
    Mount: '',
    Parent: '',
    Path: '/dev/sdc',
    TypStr: 'disk',
    Children: [
      {
        Capacity: '190.GB',
        IsUsed: false,
        Mount: '',
        Parent: '/dev/sdc',
        Path: '/dev/sdc1',
        TypStr: 'part',
      },
      {
        Capacity: '9.9GB',
        IsUsed: false,
        Mount: '',
        Parent: '/dev/sdc',
        Path: '/dev/sdc2z',
        TypStr: 'part',
      },
    ],
  },
  {
    Capacity: '20.0GB',
    IsUsed: false,
    Mount: '',
    Parent: '',
    Path: '/dev/sdd',
    TypStr: 'disk',
    Children: [
      {
        Capacity: '19.9GB',
        IsUsed: false,
        Mount: '',
        Parent: '/dev/sdd',
        Path: '/dev/sdd1',
        TypStr: 'part',
      },
    ],
  },
  {
    Capacity: '20.0GB',
    IsUsed: false,
    Mount: '',
    Parent: '',
    Path: '/dev/sdb',
    TypStr: 'disk',
    Children: [
      {
        Capacity: '19.9GB',
        IsUsed: false,
        Mount: '',
        Parent: '/dev/sdb',
        Path: '/dev/sdb1',
        TypStr: 'part',
      },
    ],
  },
])

const tableRowClassName = ({ row }: { row: nodeItem }) => {
  // 被使用了的设备   颜色加深   原生UI 不太明显
  if (row.IsUsed === true) {
    return 'disabled-row'
  } else {
    return ''
  }
}

const selectable = (row: nodeItem) => {
  return row.IsUsed === false
}

const setChildren = (children: nodeItem[], type: boolean) => {
  // 编辑多个子层级
  children.map((j: nodeItem) => {
    toggleSelection(j, type)
    if (j.Children) {
      setChildren(j.Children, type)
    }
  })
}

// 设置父级选中/取消
const setParent = (
  currentRow: any,
  type: boolean,
  parent: nodeItem[],
  selectionLists: nodeItem[]
) => {
  if (!parent.length) {
    parent = tableData.value
  }
  let allSelect: any[] = []
  parent.forEach((item: nodeItem) => {
    if (item.Children) {
      // 注:Parent 是当前选中节点的所有父节点的一个字符串形式的数据,这个很关键
      if (currentRow.Parent === item.Path) {
        // 选中
        if (type) {
          selectionLists.forEach((k: nodeItem) => {
            item.Children?.forEach((j: nodeItem) => {
              if (k.Path == j.Path) {
                allSelect.push(j)
              }
            })
          })
          if (allSelect.length == item.Children.length) {
            toggleSelection(item, type)
            selectionLists.push(item)
            select(selectionLists, item)
          } else {
            setParent(currentRow, type, item.Children, selectionLists)
          }
        } else {
          // 取消选中
          toggleSelection(item, type)
          setParent(currentRow, type, item.Children, [])
        }
      }
    }
  })
}

const toggleSelection = (row: nodeItem, select: boolean) => {
  // 编辑多个子层级
  if (row) {
    multipleDevCreateRef.value?.toggleRowSelection(row, select)
  }
}

// 选中父节点时,子节点一起选中/取消
const select = (selection: nodeItem[], row: nodeItem) => {
  const hasSelect = selection.some((el: nodeItem) => {
    return row.Path === el.Path
  })
  if (hasSelect) {
    if (row.Children) {
      // 解决子组件没有被勾选到
      setChildren(row.Children, true)
    }
    // 子节点被全勾选,父节点也勾上
    setParent(row, true, [], selection)
  } else {
    if (row.Children) {
      setChildren(row.Children, false)
    }
    // 子级取消选中, 传入当前选中节点, 所有父级取消选中
    setParent(row, false, [], [])
  }
}

// 选择全部
const selectAll = (selection: nodeItem[]) => {
  // tabledata第一层只要有在selection里面就是全选
  const isSelect = selection.some((el: nodeItem) => {
    const tableDataPaths = tableData.value.map((j: nodeItem) => j.Path)
    return tableDataPaths.includes(el.Path)
  })
  // tableDate第一层只要有不在selection里面就是全不选
  const isCancel = !tableData.value.every((el: nodeItem) => {
    const selectPaths = selection.map((j) => j.Path)
    return selectPaths.includes(el.Path)
  })
  if (isCancel) {
    tableData.value.map((el: nodeItem) => {
      if (el.Children) {
        // 解决子组件没有被勾选到
        setChildren(el.Children, false)
      }
    })
  }
  if (isSelect) {
    selection.map((el) => {
      if (el.Children) {
        // 解决子组件没有被勾选到
        setChildren(el.Children, true)
      }
    })
  }
}
</script>

<style scoped></style>

Element Plus 的树形表格也可以使用类似的方式实现全选反选功能。以下是示例代码: ```html <template> <div> <el-checkbox v-model="allChecked" @change="selectAll">全选</el-checkbox> <el-table :data="tableData" style="width: 100%"> <el-table-column type="selection" v-model="checkedItems"></el-table-column> <el-table-column prop="name" label="名称"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> </el-table> </div> </template> <script> import { ref, computed } from 'vue'; import { ElTable, ElTableColumn, ElCheckbox } from 'element-plus'; export default { components: { ElTable, ElTableColumn, ElCheckbox }, setup() { const tableData = ref([ { id: 1, name: 'John', age: 25, children: [ { id: 11, name: 'Mike', age: 22 }, { id: 12, name: 'Mary', age: 20 } ] }, { id: 2, name: 'Tom', age: 30, children: [ { id: 21, name: 'Jack', age: 28 }, { id: 22, name: 'Lucy', age: 26 } ] } ]); const checkedItems = ref([]); const checkAll = ref(false); const allChecked = computed({ get() { return checkedItems.value.length === tableData.value.length; }, set(val) { checkedItems.value = val ? tableData.value.slice() : []; } }); function selectAll() { checkedItems.value = allChecked.value ? [] : tableData.value.slice(); } return { tableData, checkedItems, checkAll, allChecked, selectAll }; } }; </script> ``` 在上面的代码中,我们使用 Element Plus 的 `ElTable` 和 `ElTableColumn` 组件来实现树形表格,用 `type="selection"` 的方式来添加选择列,将其与 `checkedItems` 变量绑定。在全选复选框中,我们使用 `ElCheckbox` 组件,并将其与 `allChecked` 变量绑定,使用 `@change` 事件监听全选复选框的状态变化,通过 `selectAll` 方法实现全选反选功能。 需要注意的是,在树形表格中,每一行数据可能还包含子节点,因此我们需要修改计算全选状态的逻辑,同时需要修改全选反选的实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值