基于大佬的思路,封装成全局方法,以供各个页面使用
更多细节请看原文,原文链接:实现 element-plus 表格多选时按 shift 进行连选的功能_element-plus表格实现按shift键快捷多选-CSDN博客
1. 新建 elTableMultiSelect.js 文件(我放在 utils 中的)
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 = newVal tbFlag.value = true } }, { deep: true, immediate: true }) onMounted(() => { mountedFlag.value = true if(!isSetup) { tbFlag.value = true tableEl = 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') return if(shiftFlag.value) return shiftFlag.value = true } function handleKeyUp({ key }) { if(key !== 'Shift') return if(!shiftFlag.value) return shiftFlag.value = false lastIdx.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 = idx return 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._index return } // lastIdx为-1时,记录本次下标 if(lastIdx.value === -1) { lastIdx.value = row._index return } // lastIdx 有值,自动勾选中间rows let [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)) continue if(!checkRowSelectable1(tmp)) continue temp.push(tmp) } onprogress.value = true for(let i = 0, len = temp.length; i < len; i++) { if(i === len - 1) onprogress.value = false tableEl.toggleRowSelection(temp[i], true) } }) } // 更新 selectedRows function updateTbSelection(selection) { // selectedRows.value = selection // keep sequence if(selection!==undefined){ selectedRows.value = selection.slice(0).sort((a, b) => a._index - b._index) } } // 清空 selectedRows function clearSelection() { selectedRows.value = [] } function checkRowSelectable1(row, rowIndex) { return typeof(checkRowSelectable) === 'function' ? checkRowSelectable(row, rowIndex) : true } return { selectedRows: readonly(selectedRows), handleTbSelect, handleTbSelectionChange, clearSelection } }
2. main.js 文件
······ import { elTableMultiSelect } from "@/utils/elTableMultiSelect" app.config.globalProperties.elTableMultiSelect = elTableMultiSelect; ······
3. 使用页面
<el-table ref="mainTableRef" @selection-change="handleSelectionChange" @select="handleTbSelect" ······ > <el-table-column type="selection" width="55" align="center"/> <el-table-column ....../> </el-table> <script setup> const {proxy} = getCurrentInstance(); const mainTableRef = ref() // shift多选 const { handleTbSelect, handleTbSelectionChange } = proxy.elTableMultiSelect(mainTableRef) // 传表格ref对象 // 多选框选中数据 function handleSelectionChange(selection) { handleTbSelectionChange() // selection 就是选中的数据了 // 其他多选操作... } </script>