目录
背景描述
实现效果
详细开发
1.模拟数据和页面布局
2.跨页勾选和点击勾选功能
3.表头全选
4. 全选全部
(1)全选后禁用表格勾选(简单)
(2)真正意义上的全选全部(难)
总结
背景描述
表格的全选、部分勾选、跨页勾选、本页全选,这几个功能,有很多实现的方法,先说如何保留勾选状态:
1.在表格的数据源中添加一个用于标记选中状态的属性,通常为 selected,
当用户单击表格中的某一行复选框时,更新该行的 selected
属性,使用table的select。
2. 借助表格的三个事件,回调函数的selection会记住当前勾选的行。
本篇是根据第二种方法实现的。
实现效果
最终实现的效果如下:
1.多页下勾选,第一页勾选3条,第二页勾选2条,返回第一条,依旧显示勾选的3条
2.单页全选和取消全选
3.手动取消勾选后,本页的全选(表头那里)的中间状态被取消——借助element-plus直接实现了,如果是手写的话需要考虑这个问题,同样的如果需要是实现全选所有的功能,也需要考虑这步。
4.全选全部(最难的部分)——这里是通过全选所有后,禁用表格的勾选框和隐藏表头的勾选框,给接口传一个标志全选的参数来实现这个功能的 ,最简单粗暴的方式。(如果是按钮代表勾选则不用考虑这些)
当然【全选所有】这个功能如果真正实现,需要考虑很多交互,在后面说具体方式。
详细开发
先建一个文件,index.vue
1.模拟数据和页面布局
全部代码
<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-tableref="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-paginationv-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']"backgroundsmall@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 = 1params.pageSize = valgetListData()
}
const handleCurrentChange = (val) => {params.page = valgetListData()
}
</script><style lang="scss" scoped>
:deep(.selectAllBtnDis .cell) {visibility: hidden;
}
</style>
这里tableData虽然模拟的是前端分页,但是和后端分页效果一样,勾选功能同样适应
2.跨页勾选和点击勾选功能
element-plus已经支持跨页勾选了,只需要这两个属性:
:row-key="(row) => row.id":reserve-selection="true"
实现效果就如 【实现效果】里第一条。
3.表头全选
const selectAllChange = (selection) => {console.log('表头全选', selection)//处理数据//。。。
}
这里可以处理需要用的数据,当然 手动勾选的时候也要处理数据(selectChange),并且根据打印参数的顺序,如果调用表格的 toggleAllSelection方法来全选表格,selectChange里也会处理顺序,所以,在这一步处理数据是最好的。
关于表格的toggleAllSelection,是用于切换表格的全选和全不选,所以一个表格多次调用就会出现先全选再全不选。之前写翻页默认全选的功能时,用了这个方法,发现有个bug,就是前面那种情况,所以后来 改成了——foreach表格数据然后toggleRowSelection,效果一样。
还有如果翻页默认全选,那么可以先用clearSelection,再toggleAllSelection。
4. 全选全部
(1)全选后禁用表格勾选(简单)
这种就是通过全选后,禁用表格的勾选,借助:selectable="handleSelectable" ,如果全选了,则表格不能勾选。
<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"
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的勾选框,所以要考虑取消勾选的功能,自然就有了上面真正实现时的难点。但是如果这个功能是通过一个按钮控制的,点击按钮就代表全选所有操作,那么自然不用考虑取消勾选和禁用的逻辑,因为全选所有时,就已经走完批量全选的流程了。两种实现方式根据业务具体的调整,这次也是为了记录实现这个功能时遇到的问题和思考。
关于最后阐述的【全选全部】功能的难点,确实我现阶段没有好的实现方式,只想到那一种,如果有其他的方式,评论区可以指导一下,感谢~