Bootstrap

Vue3 + Element Plus 实现表格全选/反选/禁用功能详解

Vue3 + Element Plus 实现表格全选/反选/禁用功能详解

一、功能概述与最终效果

本文将基于Vue3组合式API,实现Element Plus表格的以下核心功能:

  1. 全选/全不选:表头复选框控制全部数据
  2. 反选功能:快速反转当前选中状态
  3. 行禁用:禁止选中特定数据行
  4. 分页保持:分页切换时保留选中状态

二、基础表格搭建

<template>
  <div class="table-demo">
    <el-table
      ref="tableRef"
      :data="tableData"
      row-key="id"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" :selectable="checkSelectable" />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column prop="status" label="状态" />
    </el-table>

    <div class="operate-btns">
      <el-button @click="toggleAll">全选/反选</el-button>
      <el-button @click="reverseSelect">反选</el-button>
    </div>
  </div>
</template>

三、核心功能实现

1. 数据准备与禁用控制

import { ref } from 'vue'

interface TableItem {
  id: number
  name: string
  age: number
  status: '正常' | '禁用'
}

// 响应式数据
const tableRef = ref()
const tableData = ref<TableItem[]>([
  { id: 1, name: '张三', age: 25, status: '正常' },
  { id: 2, name: '李四', age: 30, status: '禁用' },
  // 更多数据...
])

// 禁用判断方法
const checkSelectable = (row: TableItem) => {
  return row.status !== '禁用'
}

2. 全选/全不选实现

const toggleAll = () => {
  // 获取当前页所有可选项
  const selectableRows = tableData.value.filter(row => checkSelectable(row))
  
  // 判断是否需要全选
  const shouldSelectAll = selectableRows.some(row => 
    !tableRef.value?.getRowSelected(row)
  )

  tableData.value.forEach(row => {
    if (checkSelectable(row)) {
      tableRef.value?.toggleRowSelection(row, shouldSelectAll)
    }
  })
}

3. 反选功能实现

const reverseSelect = () => {
  const currentSelection = tableRef.value?.getSelectionRows() || []
  const selectableRows = tableData.value.filter(row => checkSelectable(row))

  selectableRows.forEach(row => {
    const isSelected = currentSelection.some(
      (selected: TableItem) => selected.id === row.id
    )
    tableRef.value?.toggleRowSelection(row, !isSelected)
  })
}

4. 选中状态保持(配合分页)

// 存储选中ID
const selectedIds = ref<number[]>([])

// 监听选中变化
const handleSelectionChange = (rows: TableItem[]) => {
  selectedIds.value = rows.map(row => row.id)
}

// 分页切换时恢复选中
const handlePageChange = () => {
  nextTick(() => {
    tableData.value.forEach(row => {
      if (selectedIds.value.includes(row.id)) {
        tableRef.value?.toggleRowSelection(row, true)
      }
    })
  })
}

四、功能增强技巧

1. 表头复选框样式优化

::v-deep .el-table__header-wrapper .el-checkbox {
  display: inline-flex;
  
  &__inner::after {
    border-color: #fff;
  }
  
  &.is-disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}

2. 禁用行视觉提示

<el-table :row-class-name="setDisabledStyle">

<script>
const setDisabledStyle = ({ row }: { row: TableItem }) => {
  return row.status === '禁用' ? 'disabled-row' : ''
}
</script>

<style>
.disabled-row {
  opacity: 0.6;
  cursor: not-allowed;
  
  td:first-child .el-checkbox {
    display: none;
  }
}
</style>

五、完整组件代码

<template>
  <div class="table-container">
    <el-table
      ref="tableRef"
      :data="tableData"
      :row-class-name="setDisabledStyle"
      row-key="id"
      @selection-change="handleSelectionChange"
    >
      <el-table-column 
        type="selection" 
        width="55" 
        :selectable="checkSelectable" 
      />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column prop="status" label="状态" />
    </el-table>

    <div class="table-actions">
      <el-button type="primary" @click="toggleAll">
        {{ isAllSelected ? '取消全选' : '全选' }}
      </el-button>
      <el-button @click="reverseSelect">反选</el-button>
      <span class="selected-count">已选:{{ selectedIds.length }} 项</span>
    </div>

    <el-pagination 
      layout="prev, pager, next" 
      :total="50" 
      @current-change="handlePageChange"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, nextTick, computed } from 'vue'

// 数据与状态定义...
// 此处插入前面章节的实现代码
</script>

<style scoped>
/* 样式优化代码... */
</style>

六、常见问题解决方案

Q1: 分页切换后选中状态丢失?

  • 方案:使用row-key绑定唯一标识,配合selection-change存储选中ID

Q2: 禁用行仍可被全选选中?

  • 检查点
    1. selectable方法是否正确返回布尔值
    2. 全选逻辑是否过滤了不可选数据

Q3: 大数据量性能问题?

  • 优化建议
    • 使用虚拟滚动(el-table-v2)
    • 避免在模板中使用复杂表达式
    • 使用Web Worker处理数据筛选

七、扩展思考

  1. 服务端分页场景:需要结合接口传递选中ID集合
  2. 树形表格处理:使用el-table的tree-props配置
  3. 多级表头支持:嵌套el-table-column实现复杂表头
  4. 无障碍访问:为操作按钮添加ARIA标签

通过合理运用Element Plus提供的API和Vue3响应式特性,可以构建出功能强大且用户体验良好的表格组件。建议在实际开发中根据具体业务需求灵活调整实现方案。

;