el-table
要实现按住shift键
快速勾选功能windows系统
的文件shift
按住选中功能github完整代码:https://github.com/shuirongshuifu/vue3-echarts5-example
<template>
<el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @select="selectFn" @select-all="selectAllFn">
<el-table-column type="selection" width="55" />
<el-table-column label="Date" width="120" />
<el-table-column property="name" label="Name" width="120" />
<el-table-column property="address" label="Address" show-overflow-tooltip />
</el-table>
</template>
// 数据
import { ref, onMounted, onBeforeUnmount, reactive } from 'vue'
const tableData = ref([
{
id: 1,
date: '2016-05-01',
name: '111',
address: 'No. 189, Grove St, Los Angeles',
},
...
])
onMounted(() => {
window.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
});
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKeyDown);
window.removeEventListener('keyup', onKeyUp);
});
const onKeyDown = (e) => {
if (e.key === 'Shift') {
clickInfo.isShiftPressed = true;
}
};
const onKeyUp = (e) => {
if (e.key === 'Shift') {
// 鼠标抬起,重置初始状态
clickInfo.isShiftPressed = false;
clickInfo.startRowIndex = -1
clickInfo.endRowIndex = -1
}
};
clickInfo
是收集到的信息
const clickInfo = reactive({
// 开始勾选的索引,初始没勾选为-1
startRowIndex: -1,
// 结束勾选的索引, 初始没勾选为-1
endRowIndex: -1,
// 是否按下shift键,初始没有摁下
isShiftPressed: false
})
当然还需要定义表格实例和勾选存储数组,如下:
const multipleTableRef = ref()
const multipleSelection = ref([])
注意,这里要使用select
和select-all
去控制,不使用selection-change
事件,因为要更灵活第去控制了,如下:
// 全选
const selectAllFn = (selection) => {
multipleSelection.value = selection
}
// 单选
const selectFn = (selection, row) => {
multipleSelection.value = selection
// Shift相关控制逻辑...
}
// 单选
const selectFn = (selection, row) => {
multipleSelection.value = selection
// 获取当前点击的是第几行
let i = tableData.value.findIndex((item) => item.id == row.id)
// Shift按下逻辑
if (clickInfo.isShiftPressed) {
// 初始没勾选,就赋值开始勾选索引
if (clickInfo.startRowIndex === -1) {
clickInfo.startRowIndex = i
}
// 初始勾选了,说明是第二次勾选
else {
// 赋值索引
clickInfo.endRowIndex = i
// 执行把中间段的表格勾选上逻辑
selectTable(clickInfo.startRowIndex, clickInfo.endRowIndex)
}
}
}
// 执行勾选逻辑
const selectTable = (startRowIndex, endRowIndex) => {
// 第一次勾选后,紧接着再次勾选,有可能往前勾选,也有可能往后勾选,所以要做一个大小区分
const startIndex = Math.min(startRowIndex, endRowIndex);
const endIndex = Math.max(startRowIndex, endRowIndex);
// 遍历去把中间段的勾选上
tableData.value.forEach((rowData, rowIndex) => {
// 若是中间项包含在已勾选的数组中去,就忽略之(这里我们用id为标识做区分)
if (multipleSelection.value.some((msItem) => msItem.id == rowData.id)) { }
// 若是不在勾选的数组中,在去看看要不勾选
else {
// 因为起始勾选和再次勾选的数据,已经保存到勾选数组中去了,所以不用管
if (rowIndex > startIndex && rowIndex < endIndex) {
// 只需把中间段的状态置为勾选,并丢到勾选数组中去就行了
multipleTableRef.value.toggleRowSelection(rowData, rowIndex > startIndex && rowIndex < endIndex)
multipleSelection.value.push(rowData)
}
}
})
}
el-table
也需要这个需求功能呢?复杂的概念简单化...
Mixin
这个可以概念hook也是一种复用的方式
,就是单独拎出来,哪里需要哪里引入,哪里使用即可我们思考一下,这个需求的什么东西可以单独拎出来呢?
clickInfo
信息也可以单独拎出来multipleSelection
塞值,也可以单独拎出来于是乎,我们就可以这样做了
useShiftQuickSelect.ts
文件hook/useShiftQuickSelect.ts
import { onMounted, onBeforeUnmount, reactive } from 'vue'
export function useShiftQuickSelect() {
onMounted(() => {
window.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
});
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKeyDown);
window.removeEventListener('keyup', onKeyUp);
});
const onKeyDown = (e) => {
if (e.key === 'Shift') {
clickInfo.isShiftPressed = true;
}
};
const onKeyUp = (e) => {
if (e.key === 'Shift') {
// Shift抬起重置
clickInfo.isShiftPressed = false;
clickInfo.startRowIndex = -1
clickInfo.endRowIndex = -1
}
};
const clickInfo = reactive({
startRowIndex: -1,
endRowIndex: -1,
isShiftPressed: false
})
/**
* tableData表格数据、multipleSelection勾选数组,multipleTableRef表格实例
* key用于进行对比的标识字段,一般都是每一行的唯一身份证即id
* */
const ctr = (tableData, multipleSelection, multipleTableRef, key) => {
// 获取当前点击的是第几行
let i = tableData.findIndex((item) => item.id == key)
// Shift按下逻辑
if (clickInfo.isShiftPressed) {
// 初始没勾选,就赋值开始勾选索引
if (clickInfo.startRowIndex === -1) {
clickInfo.startRowIndex = i
}
// 初始已经勾选,就说明是shift快速勾选
else {
// 索引赋值
clickInfo.endRowIndex = i
// 把开始索引和结束索引进行大小对比
const { startRowIndex, endRowIndex } = clickInfo
const startIndex = Math.min(startRowIndex, endRowIndex);
const endIndex = Math.max(startRowIndex, endRowIndex);
// 遍历操作
tableData.forEach((rowData, rowIndex) => {
// 若是这一项包含在已勾选的数组中去(已勾选),就忽略之;没勾选就控制其勾选
if (!multipleSelection.some((msItem) => msItem.id == rowData.id)) {
// 中间段勾选
if (rowIndex > startIndex && rowIndex < endIndex) {
// 改表格状态并存起来
multipleTableRef.toggleRowSelection(rowData, rowIndex > startIndex && rowIndex < endIndex)
multipleSelection.push(rowData)
}
}
})
}
}
}
return { ctr }
}
<template>
<el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @select="selectFn" @select-all="selectAllFn">
<el-table-column type="selection" width="55" />
<el-table-column label="Date" width="120">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column property="name" label="Name" width="120" />
<el-table-column property="address" label="Address" show-overflow-tooltip />
</el-table>
<button @click="look">查看已勾选的</button>
</template>
<script setup>
import { ref } from 'vue'
import { useShiftQuickSelect } from "@/hook/useShiftQuickSelect.js";
const tableData = ref([
{
id: 1,
date: '2016-05-01',
name: '111',
address: 'No. 189, Grove St, Los Angeles',
}
])
const multipleTableRef = ref()
const multipleSelection = ref([])
const look = () => {
console.log('multipleSelection', multipleSelection.value);
}
// 全选
const selectAllFn = (selection) => {
multipleSelection.value = selection
}
// 单选
const { ctr } = useShiftQuickSelect()
const selectFn = (selection, row) => {
multipleSelection.value = selection
// hook操作控制函数
ctr(tableData.value, multipleSelection.value, multipleTableRef.value, row.id)
}
</script>
ctr函数
传递一下参数,问题就解决了。A good memory is better than a bad pen. Write it down...