el-table手动实现多选,全选实现的是分页全选

当前el-table的多选实现是仅仅选择当前的数据,不满足需求

当数据是一次性全部返回的时候,我们需要全选的时候选择的是全部数据,这时组件库不满足需求

复制代码
<template>
  <div class="table-container">
    <!-- 全选和操作 -->
    <div class="toolbar">
      <el-button
        type="danger"
        :disabled="selectedIds.size === 0"
        @click="handleDeleteSelected"
      >
        批量删除
      </el-button>

      <span v-if="selectedIds.size > 0" class="selection-info">
        已选择 {{ selectedIds.size }} 项
      </span>
    </div>

    <el-table
      :data="paginatedData"
      style="width: 100%"
      v-loading="loading"
      row-key="id"
      ref="tableRef"
    >
      <!-- 手动多选列 -->
      <el-table-column width="55" align="center">
        <template #header>
          <el-checkbox
            v-model="allSelected"
            :indeterminate="isIndeterminate"
            @change="handleSelectAll"
          />
        </template>
        <template #default="{ row }">
          <el-checkbox v-model="row.selected" @change="handleRowSelect(row)" />
        </template>
      </el-table-column>

      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="name" label="姓名" width="120" />
      <el-table-column prop="age" label="年龄" width="80" />
      <el-table-column prop="email" label="邮箱" />
      <el-table-column prop="address" label="地址" />
      <el-table-column prop="createTime" label="创建时间" width="180" />
    </el-table>

    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="currentPage"
      :page-sizes="[10, 20, 50, 100]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="total"
      background
      style="margin-top: 20px; text-align: right"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onMounted } from "vue";
import type { TableInstance } from "element-plus";
import { ta } from "element-plus/es/locales.mjs";

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
  address: string;
  createTime: string;
  selected?: boolean;
}

const tableData = ref<User[]>([]);
const tableRef = ref<TableInstance>();
const loading = ref(false);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(100);

const selectedIds = ref<Set<number>>(new Set());

// 分页数据
const paginatedData = computed(() => {
  const start = (currentPage.value - 1) * pageSize.value;
  const end = start + pageSize.value;
  return tableData.value.slice(start, end);
});

// 全选/半选状态
const allSelected = ref(false);
const isIndeterminate = computed(() => {
  return selectedIds.value.size > 0 && selectedIds.value.size < total.value;
});

const updateSelectStatus = () => {
  const currentPageIds = paginatedData.value.map((i) => i.id);
  const selectedCount = currentPageIds.filter((id) =>
    selectedIds.value.has(id)
  ).length;
  allSelected.value =
    selectedCount === currentPageIds.length && currentPageIds.length > 0;
};

// 行选中变化
const handleRowSelect = (row: User) => {
  if (row.selected) selectedIds.value.add(row.id);
  else selectedIds.value.delete(row.id);
  updateSelectStatus();
};

// 全选/取消全选当前页
const handleSelectAll = (val: boolean) => {
  if (val) {
    tableData.value.forEach((item) => {
      selectedIds.value.add(item.id);
      item.selected = true;
    });
  } else {
    selectedIds.value.clear();
    tableData.value.forEach((item) => {
      item.selected = false;
    });
  }
  updateSelectStatus();
};

// 分页切换时更新行选中状态
const updateCurrentPageSelection = () => {
  nextTick(() => {
    paginatedData.value.forEach((item) => {
      item.selected = selectedIds.value.has(item.id);
    });
    updateSelectStatus();
  });
};

// 分页事件
const handleSizeChange = (val: number) => {
  pageSize.value = val;
  currentPage.value = 1;
  updateCurrentPageSelection();
};

const handleCurrentChange = (val: number) => {
  currentPage.value = val;
  updateCurrentPageSelection();
};

// 批量删除
const handleDeleteSelected = () => {
  tableData.value = tableData.value.filter(
    (item) => !selectedIds.value.has(item.id)
  );
  selectedIds.value.clear();
  updateCurrentPageSelection();
  total.value = tableData.value.length;
};

// 模拟数据
const generateMockData = (count: number) => {
  const data: User[] = [];
  for (let i = 1; i <= count; i++) {
    data.push({
      id: i,
      name: `用户${i}`,
      age: Math.floor(Math.random() * 50) + 18,
      email: `user${i}@example.com`,
      address: `北京市朝阳区街道${i}号`,
      createTime: new Date(
        Date.now() - Math.floor(Math.random() * 7 * 24 * 60 * 60 * 1000)
      ).toLocaleDateString(),
    });
  }
  return data;
};

const getTableData = () => {
  loading.value = true;
  setTimeout(() => {
    tableData.value = generateMockData(total.value);
    updateCurrentPageSelection();
    loading.value = false;
  }, 300);
};

onMounted(() => {
  getTableData();
});
</script>

<style scoped>
.table-container {
  padding: 20px;
}

.toolbar {
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.selection-info {
  color: #606266;
  font-size: 14px;
}
</style>
相关推荐
一只小风华~19 小时前
Vue.js 核心知识点全面解析
前端·javascript·vue.js
2022.11.7始学前端19 小时前
n8n第七节 只提醒重要的待办
前端·javascript·ui·n8n
徐小夕19 小时前
知识库创业复盘:从闭源到开源,这3个教训价值百万
前端·javascript·github
xhxxx19 小时前
函数执行完就销毁?那闭包里的变量凭什么活下来!—— 深入 JS 内存模型
前端·javascript·ecmascript 6
L、21819 小时前
统一日志与埋点系统:在 Flutter + OpenHarmony 混合架构中实现全链路可观测性
javascript·华为·智能手机·electron·harmonyos
VX:Fegn089519 小时前
计算机毕业设计|基于springboot + vue音乐管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
十一.36619 小时前
103-105 添加删除记录
前端·javascript·html
涔溪20 小时前
微前端中History模式的路由拦截和传统前端路由拦截有什么区别?
前端·vue.js
陳陈陳20 小时前
闭包、栈堆与类型之谜:JS 内存机制全解密,面试官都惊了!
前端·javascript
Tzarevich20 小时前
从栈与堆到闭包:深入 JavaScript 内存机制
javascript·面试