vue3+element-plus实现el-table表格自动勾选、翻页勾选数据的实现方式

需求描述

页面初始化时加载table列表,默认列表数据的时间周期为空,多选框不可选择;在操作栏中点击添加按钮实现手动输入,输入完成默认勾选该条数据,多选框可选择、取消。
支持翻页勾选,以及当前页的全选、取消全选(对于全数据选择/取消需要后端全数据处理,不建议)。

实现方法

方法一

利用el-tableselectselect-all事件;表格selection列的selectable属性进行操作,代码如下:
表格(弹框):

<el-dialog v-model="dialogFormVisible" title="选择" append-to-body draggable width="60%">
    <div class="page-content">
      <el-table :data="tableData" ref="tableRef" style="width: 100%" height="100%" border  highlight-current-row header-row-class-name="header-table" @select="handleSelect" @select-all="handleSelectAll">
        <el-table-column type="selection" width="55" :selectable="selectable"/>
        <el-table-column prop="groupId" label="列一" align="center"/>
        <el-table-column prop="groupName" label="列二" align="center"/>
        <el-table-column prop="groupCycleDate" label="时间周期" min-width="180" align="center">
          <template #default='scope'>
            <span v-if="!scope.row.add">{{ scope.row.groupCycleDate }}</span>
            <el-date-picker v-model="scope.row.groupCycleDateRange" type="datetimerange" range-separator="-" :default-time="defaultTime"
              start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss" clearable v-else/>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="100" fixed='right' align="center">
          <template #default='scope'>
            <el-button type="primary" size="small" @click="changeDate(scope.row, true, '0')" link v-if="!scope.row.add">添加</el-button>
            <div v-else>
              <el-button size="small" @click="changeDate(scope.row, false, '1')" link>取消</el-button>
              <el-button type="primary" size="small" @click="changeDate(scope.row, false, '2')" link>确认</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!-- 自行封装的分页组件 -->
    <div class="page-footer">
      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"  @pagination="getList" />
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" @click="submit" :loading="submitLoading">确 定</el-button>
        <el-button @click="handleClose">取 消</el-button>
      </div>
    </template>
  </el-dialog>

主要实现逻辑:

const dialogFormVisible = ref(false);
const submitLoading = ref(false);
const tableData = ref([]);
const tableRef = ref(null);
const allSelectedData = ref([]);
// 保存已填写时间的数据
const allTimeData = ref([]);
const tableLoading = ref(false);
const defaultTime = [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)];

// 是否可勾选
const selectable = (row, index) => {
  return !!row.groupCycleDate;
}
// 用户手动勾选时触发
const handleSelect = (selection,row) => {
  // selection: 当前页所有已选中的行数据(包括本次变化后的结果)
  // row: 刚刚被操作(选中或取消)的那一行数据
  console.log('selection', selection)
  const selectedRowIds = new Set(allSelectedData.value.map(item => item.id))
  if (selection.includes(row)) {
    // 选中操作:如果该行不在全部选中集合中,则添加
    if (!selectedRowIds.has(row.id)) {
      allSelectedData.value.push(row)
    }
  } else {
    // 取消选中操作:从全部选中集合中移除该行
    const index = allSelectedData.value.findIndex(item => item.id === row.id)
    if (index > -1) {
      allSelectedData.value.splice(index, 1)
    }
  }
}
// 用户手动勾选全选框时触发
const handleSelectAll = (selection) => {
  // selection: 当前页所有被选中的行数据(如果操作是取消全选,则为空数组),tableData只会包含当前页面的数据
  const currentPageIds = tableData.value.map(row => row.id);
  const selectedRowIds = new Set(allSelectedData.value.map(item => item.id));
  if (selection.length > 0) {
    // 全选当前页:将当前页尚未选中的项添加到总集合
    selection.forEach(row => {
      if (!selectedRowIds.has(row.id)) {
        allSelectedData.value.push(row);
      }
    })
  } else {
    // 取消全选当前页:只从总集合中移除当前页的项
    allSelectedData.value = allSelectedData.value.filter(
      item => !currentPageIds.includes(item.id)
    )
  }
}
// 翻页勾选数据
const fetchTableData = async () => {
  // 数据更新后,在nextTick中回显选中状态
  nextTick(() => {
    if (tableData.value && allSelectedData.value.length > 0) {
      tableData.value.forEach(row => {
        const isSelected = allSelectedData.value.some(
          selected => selected.id === row.id
        )
        tableRef.value?.toggleRowSelection(row, isSelected);
      })
    }
  })
}
// 列表查询
const getList = () => {
	// 模拟数据
  if (queryParams.value.pageNum == 2) {
    tableData.value = [
      {
        id: '1-1-5',
        groupId: '1562145875445',
        groupName: '五',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      },
      {
        id: '1-1-6',
        groupId: '3562145875346',
        groupName: '六',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      },
      {
        id: '1-1-7',
        groupId: '458745875447',
        groupName: '七',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      },
      {
        id: '1-1-8',
        groupId: '32145145875448',
        groupName: '八',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      }
    ];
  } else {
    tableData.value = [
      {
        id: '1-1-1',
        groupId: '1562145875441',
        groupName: '一',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      },
      {
        id: '1-1-2',
        groupId: '3562145875342',
        groupName: '二',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      },
      {
        id: '1-1-3',
        groupId: '458745875443',
        groupName: '三',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      },
      {
        id: '1-1-4',
        groupId: '32145145875444',
        groupName: '四',
        groupCycleDate: '',
        groupCycleDateRange: [],
        add: false
      }
    ];
  }
  tableData.value.forEach(item => {
    item.groupCycleDate = '';
    item.groupCycleDateRange = [];
    const indexItem = allTimeData.value.findIndex(filled => filled.id === item.id);
    if (indexItem > -1) {
      item.groupCycleDate = allTimeData.value[indexItem].groupCycleDate;
      item.groupCycleDateRange = allTimeData.value[indexItem].groupCycleDateRange;
    }
  });
  fetchTableData();
}

// 确定
const submit = () => {
  if (!allSelectedData.value.length) {
    proxy.$modal.msgError('请选择要添加的群聊');
    submitLoading.value = false;
    return false;
  }
  console.log('params', params);
  ... // 其他业务逻辑
}
// 添加
const changeDate = (row, status,selection) => {
  row.add = status;
  const preCycleDate = row.groupCycleDate;
  if (row?.groupCycleDateRange?.length) {
    if (selection == '2') {
      row.groupCycleDate = row.groupCycleDateRange.join('—');
      toggleSelection([row], true);
    } else if (selection == '1') {
      const preCycleDateRange = [];
      if (preCycleDate) {
        preCycleDateRange.push(...preCycleDate.split('—'));
      }
      row.groupCycleDate = preCycleDate;
      row.groupCycleDateRange = preCycleDateRange;
    }
  } else {
    if (selection == '2') {
      row.groupCycleDate = '';
      toggleSelection([row],false);
    }else if (selection == '1') {
      const preCycleDateRange = [];
      if (preCycleDate) {
        preCycleDateRange.push(...preCycleDate.split('—'));
      }
      row.groupCycleDate = preCycleDate;
      row.groupCycleDateRange = preCycleDateRange;
    }
  }
}

// 勾选
const toggleSelection = (rows,isSelected) => {
  if (rows) {
    rows.forEach((row) => {
      tableRef.value.toggleRowSelection(row, isSelected);
      if (isSelected) {
        allSelectedData.value.push(row);
        allTimeData.value.push(row);
      }else {
        allSelectedData.value = allSelectedData.value.filter(item => item.id !== row.id);
        allTimeData.value = allTimeData.value.filter(item => item.id !== row.id);
      }
    })
  }
}

方法二

基本原理与方法一中的实现逻辑一致。不同之处在于,使用el-tablerow-keyreserve-selection属性,翻页时不用再使用fetchTableData方法重新进行过勾选,el-table会自动记录之前勾选的内容,翻页时会进行自动勾选。
需要注意的是此时select-all事件中的参数selection不再只是当前页中的内容,它包括所有页面已经勾选的数据,所以此处在做逻辑处理时,不用适用selection.length > 0进行判断,因为此时可能会有上一页或者下一页或者其他页码勾选的数据。
html代码:

...
<!-- 省略相同代码 -->
<el-table :data="tableData" ref="tableRef" style="width: 100%" height="100%" border highlight-current-row header-row-class-name="header-table" @select="handleSelect" @select-all="handleSelectAll" row-key="id">
<el-table-column type="selection" width="55" :selectable="selectable" :reserve-selection="true"/>
...
</el-table>
...

业务逻辑代码中删除fetchTableData方法,修改handleSelectAll方法,getList加载数据时无需再调用fetchTableData方法。

...
// 省略相同代码
// 用户手动勾选全选框时触发
const handleSelectAll = (selection) => {
  // selection: 所有页被选中的行数据(如果没有选中的数据,则为空数组),tableData只会包含当前页面的数据
  allSelectedData.value = [...selection];
}
// 删除fetchTableData方法
// 去除getList中的fetchTableData调用
const getList = () => {
  ...
  // fetchTableData();
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值