element-plus 表格跨页全选

<template>
  <div class="app">
    <div>
      <el-checkbox v-model="crossPage">跨页全选</el-checkbox>
    </div>
    <el-table
      ref="tableRef"
      :data="dataRender"
      row-key="id"
      :columns="columns"
      border
      stripe
      @select="onSelect"
      @selection-change="onSelectionChange"
    >
      <el-table-column type="selection" />
      <el-table-column
        :prop="item.dataIndex"
        :label="item.title"
        :width="item.width"
        v-for="item in columns"
        :key="item.dataIndex"
      />
    </el-table>
    <div class="pagination">
      <el-pagination
        layout="total, prev, pager, next"
        @current-change="onPageChange"
        :total="pagination.total"
      />
    </div>
    <div>
      <div v-if="crossPage">排除:{{ JSON.stringify(excludeSelected) }}</div>
      <div v-else>已选择:{{ JSON.stringify(selection) }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref, watch, nextTick } from "vue";
import axios from "axios";
import { changeArr } from "../utils/arr-helper";

// 分页信息
const pagination = reactive({
  current: 1,
  pageSize: 10,
  total: 5,
  showTotal: true,
});

// 表头
const columns = [
  {
    title: "姓名",
    dataIndex: "name",
    width: 100,
  },
  {
    title: "年龄",
    dataIndex: "age",
    width: 100,
  },
  {
    title: "工资",
    dataIndex: "salary",
    width: 100,
  },
  {
    title: "住址",
    dataIndex: "address",
  },
];

const dataRender = ref([]);
const syncDataRender = async () => {
  const {
    data: { data },
  } = await axios.get("/api/user", {
    params: {
      current: pagination.current,
      pageSize: pagination.pageSize,
    },
  });
  dataRender.value = data.list;
  pagination.total = data.total;
};
syncDataRender();

const onPageChange = async (current) => {
  pagination.current = current;
  syncDataRender();
};

// 跨页全选要立即选中当前页数据,即便翻页的也要选中,但是不能包含排除的
// 需要注意的是:当勾选了跨页全选后,已经选中的就不在作数,而是重点关注排除项

// 记录 excludeSelected
// 用户手动勾选触发
// 主要用于记录用户手动取消勾选的项,用于跨页全选时排除
const excludeSelected = ref([]);
const onSelect = (selection, row) => {
  const isSelected = selection.findIndex((item) => item.id === row.id) > -1; // 本次是选中还是取消
  if (crossPage.value) {
    excludeSelected.value = changeArr({
      arr: excludeSelected.value,
      row,
      action: isSelected ? "rm" : "push",
    });
  }
};

// 记录 selection
// 当选择项发生变化时会触发该事件(包含手动or 调用 tableRef.value.toggleRowSelection)
const selection = ref([]);
const onSelectionChange = (arg) => {
  selection.value = arg;
};

// 当跨页全选时,要选中当前页的所有数据
const crossPage = ref(false);
const tableRef = ref(null);
watch(
  () => crossPage.value,
  () => {
    if (crossPage.value) {
      for (const element of dataRender.value) {
        tableRef.value.toggleRowSelection(element, true);
      }
    } else {
      excludeSelected.value = [];
    }
  }
);

//  跨页全选时,即便内容变化(如翻页)的也要选中,但是不能包含排除的
watch(
  () => dataRender.value,
  async () => {
    // 这里要做还原选中状态
    if (crossPage.value) {
      for (const element of dataRender.value) {
        const isExclude = excludeSelected.value.findIndex((item) => item.id === element.id) >-1;
        if (!isExclude) {
          await nextTick();
          tableRef.value.toggleRowSelection(element, true);
        }
      }
    }
  }
);
</script>
<style>
.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 20px;
}
</style>

posted @ 2025-04-22 10:33  丁少华  阅读(157)  评论(2)    收藏  举报