当前位置: 首页 > news >正文

实现 element-plus 表格多选时按 shift 进行连选的功能

前言

element-plus表格提供了多选功能,可单击勾选一条数据,可全选。
现在有个很合理的需求,希望实现类似于文件系统中shift连续选择功能,并且在表格排序后,依照排序后的顺序连选。


一、el-table 多选表格基本使用

1、el-table 相关事件、方法

  1. 插入多选项

<el-table-column type="selection" />

  1. 表格事件
事件名说明回调参数
select当用户手动勾选数据行的 Checkbox 时触发的事件selection, row
select-all当用户手动勾选全选 Checkbox 时触发的事件selection
selection-change当选择项发生变化时会触发该事件selection
  1. 表格方法
方法名说明参数
clearSelection用于多选表格,清空用户的选择-
getSelectionRows返回当前选中的行
toggleRowSelection用于多选表格,切换某一行的选中状态, 如果使用了第二个参数,则可直接设置这一行选中与否row, selected
toggleAllSelection用于多选表格,切换全选和全不选-
  1. table-column 属性

selectable: 仅对 type=selection 的列有效,类型为 Function,Function 的返回值用来决定这一行的 CheckBox 是否可以勾选。(类型:function(row, index)

2、el-table 多选表格示例

<template><el-table:data="tableData"@selection-change="handleSelectionChange"><el-table-column type="selection" /><!-- other columns --></el-table>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getTableData } from '@/api/demo.js'const tableData = ref([])
const selectedRows = ref([])onMounted(() => {getData()
})const getData = () => {getTableData().then(res => {tableData.value = res.data ?? []})
}const handleSelectionChange = (selection) => {selectedRows.value = selection
}
</script>

二、实现

由于该功能可能会应用到很多页面中,最好是提供一个统一的公共方法,在页面中引入使用

1、分析

基本过程:

> 记录上一次点击的数据;记录 shift 状态
> 组件挂载后,监听 shift 键的 keydown, keyup 事件,更新 shift 状态;组件销毁前取消相关监听
> 监听 el-table@select 事件,对比上一次点击与本次点击,计算待连选数据列表后,使用 toggleRowSelection 方法进行连续勾选

2、实现

根据分析,初步创建方法
注意: 为了方便理解思路,下面的示例中仅包含关键代码,完整代码在最后

el-table-multi-select.js:

import { ref, readonly, watch, onMounted, onBeforeUnmount } from 'vue'export function elTableMultiSelect(tableEl) {// 表格数据const tableData = ref([])// 选中数据列表const selectedRows = ref([])// 下标记录const lastIdx = ref(-1)// shift标识const shiftFlag = ref(false)onMounted(() => {// el-table 表格排序不会体现在绑定的数据列表上// 监听 el-table 组件内部状态存储中的表格数据(避免表格排序后连选不连续的bug)watch(tableEl.store?.states?.data, (newVal) => {tableData.value = newVal.map((item,idx) => {item.index = idxreturn item})}, { immediate: true })// Shift监听/取消监听document.addEventListener('keydown', handleKeyDown)document.addEventListener('keyup', handleKeyUp)})// 取消Shift监听onBeforeUnmount(() => {document.removeEventListener('keydown', handleKeyDown)document.removeEventListener('keyup', handleKeyUp)})// Shift事件处理function handleKeyDown({ key }) {if(key !== 'Shift') returnif(shiftFlag.value) returnshiftFlag.value = true}function handleKeyUp({ key }) {if(key !== 'Shift') returnif(!shiftFlag.value) returnshiftFlag.value = falselastIdx.value = -1}// el-table@selectfunction handleTbSelect(selection, row) {updateSelection(selection)// 若未按 shift,更新 lastIdxif(!shiftFlag.value) {if(selection.find(r => r.index === row.index)) lastIdx.value = row.indexreturn}// 若 lastIdx 无有效值,记录本次下标if(lastIdx.value === -1) {lastIdx.value = row.indexreturn}// 若 lastIdx 有值,自动勾选中间rowslet [start, end] = [lastIdx.value, row.index]if(start > end) [start, end] = [end, start]// TODO: toggleRowSelection// ...}// el-table@selection-changefunction handleTbSelectionChange(selection) {updateSelection(selection)}// 更新 selectedRowsfunction updateSelection(selection) {selectedRows.value = selection}return {selectedRows: readonly(selectedRows),handleTbSelect,handleTbSelectionChange}
}

组件中引入使用
demo.vue:

<template><el-table:data="tableData"@select="handleTbSelect"@selection-change="handleTbSelectionChange"ref="demoTable"><el-table-column type="selection" /><!-- other columns --></el-table>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getTableData } from '@/api/demo.js'
import { elTableMultiSelect } from '@/use/el-table-multi-select'const demoTable = ref()
const tableData = ref([])
// const selectedRows = ref([]) // 从公共方法中导出const {selectedRows,handleTbSelect,handleTbSelectionChange
} = elTableMultiSelect(demoTable)onMounted(() => {getData()
})const getData = () => {getTableData().then(res => {tableData.value = res.data ?? []})
}// 从公共方法中导出
// const handleSelectionChange = (selection) => {
//   selectedRows.value = selection
// }

3、小结

注意:在下面的完整代码中,本人监听了 el-table 组件内部状态存储信息(tableEl.store.states.data),未公布在官网。随着版本的更新,有失效的风险。建议锁定 element-plus 版本号或者确定所使用的版本仍有效。

不监听表格绑定的数据本身,是因为el-table排序后,不会体现在绑定的数据上,也就是说,排序后,连选功能还是按照排序前的顺序来进行连选的。

三、代码与演示

在线演示

工具方法完整代码:

import { ref, readonly, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'/*** 工具类: el-table 可多选表格,增加shift连选功能* * @param {string|Element} tableRef 选项式API中,传表格ref字符串;setup中,传表格对象* @param {Function} [checkRowSelectable] 禁选方法(可选),对应el-table-column selectable属性值* @returns {Object} {*   selectedRows: 多选结果列表,*   handleTbSelect: el-table@select,*   handleTbSelectionChange: el-table@selection-change,*   clearSelection: 清空多选结果列表* }* @example* // 一、引入* * import { elTableMultiSelect } from '@/use/el-table-multi-select'* * // 二、template* * // el-table 相关属性方法*   @select="handleTbSelect"*   @selection-change="handleTbSelectionChange"*   ref="multiSelectTable"* * // 三、方法调用:* * ------------------------1、选项式API:------------------------* * // data() 相关变量声明:* selectedRows: [],* handleTbSelect: undefined,* handleTbSelectionChange: undefined* * // created() 中解构赋值:* ;({*   selectedRows: this.selectedRows,*   handleTbSelect: this.handleTbSelect,*   handleTbSelectionChange: this.handleTbSelectionChange* } = elTableMultiSelect.call(this, 'multiSelectTable', this.enableSelection)) // 传表格ref字符串* // methods:* enableSelection(row, rowIndex) {*   return !row.suspected_detection_seq* }* * ------------------------2、组合式API:------------------------* * const multiSelectTable = ref()* const {*   selectedRows, handleTbSelect, handleTbSelectionChange* } = elTableMultiSelect(multiSelectTable, enableSelection) // 传表格ref对象* * function enableSelection(row, rowIndex) {*   return !row.suspected_detection_seq* }*/
export function elTableMultiSelect(tableRef, checkRowSelectable) {// 表格数据const tableData = ref([])// 选中数据列表const selectedRows = ref([])// 下标记录const lastIdx = ref(-1)// shift标识const shiftFlag = ref(false)let tableEl                    // 表格对象const tbFlag = ref(false)      // 标识:表格挂载完毕const mountedFlag = ref(false) // 标识:组件挂载完毕const isSetup = typeof(tableRef) !== 'string'isSetup && watch(tableRef, (newVal) => {if(newVal) {tableEl = newValtbFlag.value = true}}, { deep: true, immediate: true })onMounted(() => {mountedFlag.value = trueif(!isSetup) {tbFlag.value = truetableEl = this.$refs[tableRef]}// Shift监听/取消监听document.addEventListener('keydown', handleKeyDown)document.addEventListener('keyup', handleKeyUp)})// 取消Shift监听onBeforeUnmount(() => {document.removeEventListener('keydown', handleKeyDown)document.removeEventListener('keyup', handleKeyUp)})// Shift事件处理function handleKeyDown({ key }) {if(key !== 'Shift') returnif(shiftFlag.value) returnshiftFlag.value = true}function handleKeyUp({ key }) {if(key !== 'Shift') returnif(!shiftFlag.value) returnshiftFlag.value = falselastIdx.value = -1}// 表格挂载 & 组件挂载 后, 添加 tableData 监听事件const tbMountedWatcher = watch([tbFlag, mountedFlag], ([tf, mf]) => {if(tf && mf) {// el-table 表格排序不会体现在绑定的数据列表上// 监听 el-table 组件内部状态存储中的表格数据(避免表格排序后连选不连续的bug)watch(tableEl.store?.states?.data, (newVal) => {// console.log('watch el-table store', newVal.length)tableData.value = newVal.map((item,idx) => {item.index = idxreturn item})}, { immediate: true })tbMountedWatcher() // 取消监听}})// toggleRowSelection 会触发 handleTbSelectionChange// onprogress 控制shift多选时,只触发一次 handleTbSelectionChange// (handleTbSelectionChange 为同步执行方法)const onprogress = ref(false)/*** 当选择项发生变化时会触发该事件* @param {Array} selection selected rows*/function handleTbSelectionChange(selection) {if(!onprogress.value) updateTbSelection(selection)}/*** 当用户手动勾选数据行的 Checkbox 时触发的事件* @param {Array} selection selected rows* @param {Object} row table row data* @returns */function handleTbSelect(selection, row) {updateTbSelection(selection)if(!shiftFlag.value) {if(selection.find(r => r.index === row.index)) lastIdx.value = row.indexreturn}// lastIdx为-1时,记录本次下标if(lastIdx.value === -1) {lastIdx.value = row.indexreturn}// lastIdx 有值,自动勾选中间rowslet [start, end] = [lastIdx.value, row.index]if(start > end) [start, end] = [end, start]nextTick(() => {const temp = []for(let i = start; i <= end; i++) {const tmp = tableData.value[i]if(selectedRows.value.find(r => r.index === tmp.index)) continueif(!checkRowSelectable1(tmp)) continuetemp.push(tmp)}onprogress.value = truefor(let i = 0, len = temp.length; i < len; i++) {if(i === len - 1) onprogress.value = falsetableEl.toggleRowSelection(temp[i], true)}})}// 更新 selectedRowsfunction updateTbSelection(selection) {selectedRows.value = selection}// 清空 selectedRowsfunction clearSelection() {selectedRows.value = []}function checkRowSelectable1(row, rowIndex) {return typeof(checkRowSelectable) === 'function'? checkRowSelectable(row, rowIndex): true}return {selectedRows: readonly(selectedRows),handleTbSelect,handleTbSelectionChange,clearSelection}
}
http://www.lryc.cn/news/7294.html

相关文章:

  • 华为OD机试真题JAVA实现【考古学家】真题+解题思路+代码(20222023)
  • Spring3之基于Aspect实现AOP
  • buctoj-寒假集训进阶训练赛(二十二)
  • 华为OD机试真题JAVA实现【静态扫描最优成本】真题+解题思路+代码(20222023)
  • 汽车装配工厂立库物料运送线PLC无线应用
  • Python雪花代码
  • Numpy基础与实例——人工智能基础
  • MQTT的工作原理
  • iOS开发:UINavigationController自定义返回按钮,系统导航支持侧滑返回
  • 【Kafka进阶】-- unclean.leader.election.enable参数的内涵
  • 基于redis实现分布式锁
  • C#开发的OpenRA动态加载插件DLL里的类实现
  • 网站代理是什么?有什么需要注意的?
  • 动态库和静态库的区别
  • C/C++路径去除前缀
  • Vue2之Vue-cli应用及组件基础认识
  • C 学习笔记 —— 声明、定义、初始化
  • 机械狗控制算法
  • 向量与矩阵 导数和偏导数 特征值与特征向量 概率分布 期望方差 相关系数
  • 记录--前端实现登录拼图验证
  • 【Go语言基础】Go语言中的map集合详细使用(附带源码)
  • C++11 lambda
  • 【新】华为OD机试 - 分苹果(Python)
  • Python 模块
  • gdb调试功能从零到会(Linux详解)
  • 【C语言学习笔记】:数组、指针相关面试题
  • go语言环境配置 项目启动
  • Springboot 使用插件 自动生成Mock单元测试 Squaretest
  • 「JVM 执行引擎」栈架构的字节码的解释执行引擎
  • SSM项目-商城后台管理系统