需求背景,定制需求,列表分页+数量限制提交
前提条件:由于历史项目升级到vue3+element-plus ,故此写法还是偏于vue2的声明写法,没有用到组合式
有过研究的小伙伴们,肯定发现了,element 和element-plus中对于跨页选择保持勾选这个操作,源码进行更改,如果用element的话,用row-key + reserve-selection 即可达到切换分页时,记住之前分页的数据内容,但是element-plus可不行。
下面在线模拟一波
然后同样的后端分页使用element,切换分页时也可以达到记忆之前勾选内容,但是element-plus按照这种方式并不能实现。
先来看一波element-plus实现的样例:
这边我设置勾选上限25个,后端分页,切换分页记住之前选择,并达到上限之后,复选框禁用,搭配上全选功能也实现限制。
前提准备:
1.使用row-key定唯一字段、reserve-selection在type=selection勾选框栏(开启跨页记录) 使用selectable属性来控制是否可以勾选
2.尝试@select和@select-change 两个方法,发现select-change不记录跨页数据,故而采用@select,勾选单个勾选框触发的事件,可以知道当前点击行的row信息
3. @select-all 方法全选该页所有项,参数是目前选中的数据,开启跨页记录(含跨页数据)
实现思路:
1.单个选择时,判断选中的行数据是否存在选中数据数组中(currentSelection),不存在就加入存在就剔除
2.全部选择时:分两种情况 @select-all = handlerSelectAll(val)
a: val 为空 取消当前页勾选,并且其他页都没有数据 ===> 直接维护currentSelection 置空即可
b: val有数据 分两种情况
b1: 当前页的全选
比较当前页tableData和val差集(diff),如果tableData的数据都在val中,说明是全选,将差集添加到currentSelection即可
b2: 其他页有数据勾选,当前页取消全选
如果tableData的数据在val中不存在,则为取消全选,从currentSelection 剔除这些数据即可
上述分析中再加入上限设置,全选时判断,增加差集过程中,currentSelection + diff 和 上限(maxLength) 作对比,超过限制就截断,不足就直接添加
分析完毕:下面是展示代码
<el-table
v-show="!tableLoading && tableData.length"
max-height="330"
ref="multipleTable"
:data="tableData"
class="userCameraTable"
row-class-name="rowClassName"
header-row-class-name="headerRowClassName"
border
row-key="deviceId"
@select="handlerSelect"
@select-all="handlerSelectAll"
>
<el-table-column
label
width="50"
type="selection"
v-if="!isShowDetail"
:selectable="handlerSelectable"
:reserve-selection="true"
/>
....
handlerSelectable(row) {
// 检查当前行是否已被选择
const isChecked = this.currentSelection.includes(row.deviceId)
// 如果当前行已被选择,则允许取消选择
if (isChecked) {
return true
} else {
// 如果当前行未被选择,并且已选择的行数超过max,则禁止选择新的行
return this.currentSelection.length < this.maxLength
}
},
handlerSelect(val, row) {
this.currentSelection.indexOf(row.deviceId) === -1
? this.currentSelection.push(row.deviceId)
: this.currentSelection.splice(this.currentSelection.indexOf(row.deviceId), 1)
},
handlerSelectAll(val) {
if (val.length) {
// 进来此处说明:
// 1 当前页的全选 2 其他页有数据然后当前页的取消全选
// 比较全选或者取消全选与当前页的数据,得到差集
// 如果tableData中的数据在val中不存在,则说明是取消全选,需要从currentSelection中移除
// 如果tableData中所有的数据都在val中存在,则说明是全选,需要将差集添加到currentSelection中
const isAllSelect = this.tableData.every(item =>
val.some(valItem => valItem.deviceId === item.deviceId)
)
if (isAllSelect) {
// 全选中新增的差集
const diff = val.filter(
item => !this.currentSelection.some(deviceId => deviceId === item.deviceId)
)
if (this.currentSelection.length + diff.length > this.maxLength) {
this.currentSelection = this.currentSelection.concat(
diff.splice(0, this.maxLength - this.currentSelection.length)
.map(item => item.deviceId))
diff.forEach(item => this.$refs.multipleTable.toggleRowSelection(item, false))
} else {
this.currentSelection = this.currentSelection.concat(diff.map(item => item.deviceId))
}
} else {
this.currentSelection = this.currentSelection.filter(
deviceId => !this.tableData.some(item => item.deviceId === deviceId)
)
}
} else {
// 进来此处说明:
// 其他页并无勾选数据,且当前页取消勾选
this.currentSelection = []
}
},
// getTableData
async getCameraList() {
...
const res = await this.$api.getCameraListByGroup(data)
if (res.cameraList && res.cameraList.length) {
this.totalNum = res.pageInfo.totalNum
this.tableData = res.cameraList
// 需要这部分,每当切换分页获取新一页的tableData时,双循环遍历把当前tableData中有存在维护已选数据中的id手动设置勾选
if (this.currentSelection.length) {
this.$nextTick(() => {
this.currentSelection.forEach(row => {
this.tableData.forEach(item => {
if (item.deviceId === row) {
this.$refs.multipleTable?.toggleRowSelection(item, true)
}
})
})
})
} else {
this.$refs.multipleTable?.clearSelection()
}
this.$nextTick(() => {
this.$refs.multipleTable?.doLayout()
this.$refs.multipleTable?.setScrollTop(0)
})
}
...
}
}
至于打开弹框再回显数据,就让后端返参,返回所有的勾选数据,前端直接赋值ids给currentSelection即可。