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>
相关推荐
码界奇点14 小时前
基于SpringBoot+Vue的前后端分离外卖点单系统设计与实现
vue.js·spring boot·后端·spring·毕业设计·源代码管理
不吃香菜的猪15 小时前
使用@vue-office/pdf时,pdf展示不全
javascript·vue.js·pdf
wuhen_n15 小时前
TypeScript的对象类型:interface vs type
前端·javascript·typescript
css趣多多15 小时前
props,data函数,computed执行顺序
前端·javascript·vue.js
一个不称职的程序猿15 小时前
构建优雅的 Vue.js 表情包选择器:一个功能丰富且可定制的 Emoji Picker 组件
前端·javascript·vue.js
无风听海15 小时前
AngularJS中$q.when()的用法
javascript·ecmascript·angular.js
Amumu1213815 小时前
Vue核心(二)
前端·javascript·vue.js
墨轩尘16 小时前
qiankun的简单使用
前端·vue.js·前端框架
2501_9444241216 小时前
Flutter for OpenHarmony游戏集合App实战之记忆翻牌配对消除
android·java·开发语言·javascript·windows·flutter·游戏
2501_9445264216 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 设置功能实现
android·javascript·flutter·游戏·harmonyos