vue3+element-plus 表格全选和跨页勾选,以及全选全部功能

目录

背景描述

实现效果

详细开发

1.模拟数据和页面布局

2.跨页勾选和点击勾选功能

3.表头全选

[4. 全选全部](#4. 全选全部)

(1)全选后禁用表格勾选(简单)

(2)真正意义上的全选全部(难)

总结


背景描述

表格的全选、部分勾选、跨页勾选、本页全选,这几个功能,有很多实现的方法,先说如何保留勾选状态:

1.在表格的数据源中添加一个用于标记选中状态的属性,通常为 selected, 当用户单击表格中的某一行复选框时,更新该行的**selected** 属性,使用table的select。

2. 借助表格的三个事件,回调函数的selection会记住当前勾选的行。

本篇是根据第二种方法实现的。


实现效果

最终实现的效果如下:

1.多页下勾选,第一页勾选3条,第二页勾选2条,返回第一条,依旧显示勾选的3条

2.单页全选和取消全选

3.手动取消勾选后,本页的全选(表头那里)的中间状态被取消------借助element-plus直接实现了,如果是手写的话需要考虑这个问题,同样的如果需要是实现全选所有的功能,也需要考虑这步。

4.全选全部(最难的部分) ------这里是通过全选所有后,禁用表格的勾选框和隐藏表头的勾选框,给接口传一个标志全选的参数来实现这个功能的 ,最简单粗暴的方式。(如果是按钮代表勾选则不用考虑这些)

当然【全选所有】这个功能如果真正实现,需要考虑很多交互,在后面说具体方式。


详细开发

先建一个文件,index.vue

1.模拟数据和页面布局

全部代码

javascript 复制代码
<template>
  <el-card class="card-style">
    <div class="mt-1">
      <h2 class="fwb-mb-1">批量全选功能</h2>
    </div>
    <el-row style="margin: 10px 0">
      <el-col :span="12">
        <el-checkbox v-model="checkAll" @change="checkAllChange">全选所有</el-checkbox>
      </el-col>
    </el-row>
    <el-table
      ref="tableRef"
      :data="tableData.slice((params.page - 1) * params.pageSize, params.page * params.pageSize)"
      class="table-small-custom"
      :row-key="(row) => row.id"
      height="calc(100vh - 271px)"
      @select="selectChange"
      @select-all="selectAllChange"
      @selection-change="handleSelectionChange"
    >
      <!-- :header-cell-class-name="leftHeaderStyle" -->
      <!-- :selectable="handleSelectable" -->

      <el-table-column type="selection" width="30" :reserve-selection="true" />
      <el-table-column type="index" width="70" label="序号" align="center">
        <template #default="scope">
          <span v-text="getIndex(scope.$index)"></span>
        </template>
      </el-table-column>
      <el-table-column prop="id" label="id" min-width="160" align="center"></el-table-column>
    </el-table>
    <el-pagination
      v-model:current-page="params.page"
      v-model:page-size="params.pageSize"
      class="pg-block"
      layout="total, sizes, prev, pager, next, jumper"
      :total="pageTotal"
      :page-sizes="['3', '5']"
      background
      small
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
    />
  </el-card>
</template>

<script setup>
import { ref, reactive, defineProps, computed, defineEmits, onMounted, inject } from 'vue'
import axios from '@/utils/request.js'
import { ElMessage, ElMessageBox } from 'element-plus'

let tableData = ref([])
let pageTotal = ref(0)
let params = reactive({
  page: 1,
  pageSize: 3
})

onMounted(async () => {
  getListData()
})

const getListData = async () => {
  //接口数据
  tableData.value = [{ id: 12 }, { id: 13 }, { id: 14 }, { id: 15 }, { id: 16 }, { id: 17 }, { id: 18 }]
  pageTotal.value = tableData.value.length
}

const checkAll = ref(false)
const checked = ref([])
const handleSelectable = (row, index) => {
  return !checkAll.value
}
const selectAllChange = (selection) => {
  console.log('表头全选', selection)
  //处理数据
  //。。。
}

const selectChange = (selection, row) => {
  console.log('勾选', selection, row)
  //处理数据
  //。。。
}
const handleSelectionChange = (selection) => {
  //处理数据
  //。。。
  checked.value = selection.map((item) => item.id)
}
const leftHeaderStyle = ({ row, column, rowIndex, columnIndex }) => {
  if (rowIndex == 0 && columnIndex === 0 && checkAll.value) {
    return 'selectAllBtnDis'
  }
}

// 为下面全选所有功能
const tableRef = ref(null)
const checkAllChange = (val) => {
  //全选
  if (val) {
    tableRef.value.clearSelection()
    tableRef.value.toggleAllSelection()
  }
}

const getIndex = (index) => {
  return (params.page - 1) * params.pageSize + index + 1
}
const handleSizeChange = (val) => {
  params.page = 1
  params.pageSize = val
  getListData()
}
const handleCurrentChange = (val) => {
  params.page = val
  getListData()
}
</script>

<style lang="scss" scoped>
:deep(.selectAllBtnDis .cell) {
  visibility: hidden;
}
</style>

这里tableData虽然模拟的是前端分页,但是和后端分页效果一样,勾选功能同样适应

2.跨页勾选和点击勾选功能

element-plus已经支持跨页勾选了,只需要这两个属性:

javascript 复制代码
:row-key="(row) => row.id"

:reserve-selection="true"

实现效果就如 【实现效果】里第一条。

3.表头全选

javascript 复制代码
const selectAllChange = (selection) => {
  console.log('表头全选', selection)
  //处理数据
  //。。。
}

这里可以处理需要用的数据,当然 手动勾选的时候也要处理数据(selectChange ),并且根据打印参数的顺序,如果调用表格的 toggleAllSelection 方法来全选表格,selectChange里也会处理顺序,所以,在这一步处理数据是最好的。

关于表格的toggleAllSelection ,是用于切换表格的全选和全不选,所以一个表格多次调用就会出现先全选再全不选。之前写翻页默认全选 的功能时,用了这个方法,发现有个bug,就是前面那种情况,所以后来 改成了------foreach表格数据然后toggleRowSelection,效果一样。

还有如果翻页默认全选,那么可以先用clearSelection ,再toggleAllSelection

4. 全选全部

(1)全选后禁用表格勾选(简单)

这种就是通过全选后,禁用表格的勾选,借助**:selectable="handleSelectable" ,如果全选了,则表格不能勾选。**

javascript 复制代码
  <el-table-column type="selection" width="30" :reserve-selection="true" :selectable="handleSelectable" />

const handleSelectable = (row, index) => {
  return !checkAll.value
}

并且表头不能被勾选,也就是本页全选,有几种实现方式,要么表头的勾选禁用,要么是表头的勾选隐藏掉,禁用这个应该能实现,但是没有找到方法 ,因为数据为空时,表头就是禁用的:

所以我只好隐藏表头的勾选框:

通过给table加了一个表头的样式 :header-cell-class-name="leftHeaderStyle"

javascript 复制代码
const leftHeaderStyle = ({ row, column, rowIndex, columnIndex }) => {
  if (rowIndex == 0 && columnIndex === 0 && checkAllPatient.value) {
    return 'selectAllBtnDis'
  }
}


:deep(.selectAllBtnDis .cell) {
  visibility: hidden;
}

实现效果:

(2)真正意义上的全选全部(难)

如果要实现真正意义的全选所有,也就是跨页全选,有两种前提:

第一种是前端分页的背景下,直接全选所有后,直接给所有数据加一个selected的属性,或者,已勾选的数据里是全部数据,翻页的时候,遍历当页数据,然后toggleRowSelection。

第二种是后端分页情景下的全选所有。

那么前端无法获取全部数据,自然也翻页后无法知道当前选中哪些,是否全选了,虽然element-plus已经支持记住勾选的数据的功能,但是也很实现这个交互,需要考虑以下几个问题:

  • 全选所有后,当前checkbox是√形式,这种,并且当页的表格被勾选,这个简单,借助【先用clearSelection ,再**toggleAllSelection】**就可以实现。
  • 全选所有后,翻页默认全选,则,翻页的时候需要调用一下上面那一步。
  • 以上两步,都需要记住数据,无所谓,反正handleSelectionChange时会处理数据
  • 全选所有后取消全选,那么就需要clearSelection,翻页时也需要。
  • 全选全部后,取消勾选某一个行或者点表头来取消当页勾选,那么【全选全部】 的checkbox是-的方式,代表已经全选过,但是当前用户手动取消掉一些。那么实现这个功能,则需要考虑,怎么传递数据
  • 比如在第一页全选所有了,那么后面十几页都是被勾选的 ,如果你没有翻页,自然无法获取后面 的数据,传参时如果需要实现上面这个功能,可以和后端沟通,全选时传一个标志,然后再取消勾选时,记住当前取消勾选的数据,传给后端,他们处理数据时就【全部数据-被取消勾选的数据】,这种方式比较便捷
  • 上面时在勾选全部的基础上的一些交互和数据处理,如果是用户手动勾选/手动全选本页 ,一共十三条数据,全部勾选了,那么【全选全部】被勾选,这个好实现,只需要对比seleced数据的长度和total就行,之后再取消就也跟上面逻辑一样。

以上差不多是实现的主要难点,目前我查找解决方案,也大多是给这种方式,如果有其他方式,可以在评论区告知。


总结

这个功能,需要考虑很多交互的逻辑,因为我写的是【全选全部】是一个checkbox的勾选框,所以要考虑取消勾选的功能,自然就有了上面真正实现时的难点。但是如果这个功能是通过一个按钮控制的,点击按钮就代表全选所有操作,那么自然不用考虑取消勾选和禁用的逻辑,因为全选所有时,就已经走完批量全选的流程了。两种实现方式根据业务具体的调整,这次也是为了记录实现这个功能时遇到的问题和思考。

关于最后阐述的【全选全部】功能的难点,确实我现阶段没有好的实现方式,只想到那一种,如果有其他的方式,评论区可以指导一下,感谢~

相关推荐
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端