最近开发遇见一个需求,一棵五个层级的tree,点击任意节点加载该节点下的学生数据。本身这个需求是容易实现的,根据节点进行分页嘛~
但做成查询条件后,被告知要支持分页,当跨页选择数据和反显数据时,就遇到了困难
组件一次请求最多两百条数据,支持当前页全选,选择的班级和学生按照tag的样式展示在上方。
1.选择的学生数据存储在window.localStorage中,el-table的select-change事件将回传数据行,存储在localStorage之前要去重,否则数据量爆炸将使浏览器崩溃。
<el-table
ref="multipleTable"
v-loading="loading"
max-height="288px"
border
stripe
empty-text="没有数据"
:data="pageData ? pageData.list : []"
@selection-change="handleSelectionChange"
@select="cancelCheck"
@select-all="checkAll"
>
/**
* 学生选择切换 根据用户选中的学生,渲染到已选学生列表
* 每次改变勾选都会触发多次,将选择的列表逐个传递
* */
handleSelectionChange(v) {
// console.log('变化了');
this.showCommit = false;
if (!v) return false;
// console.log('用户当前选择的学生111', v);
const oldChecked = JSON.parse(window.localStorage.getItem('tempCheckedStudentIds')) || [];
let temp = null;
if (this.isFiltering) {
temp = oldChecked.concat(v);
} else {
if (v.length) {
if (oldChecked && oldChecked.length) {
temp = this.getTemp(oldChecked.concat(v));
} else {
temp = v;
}
} else {
temp = this.getTemp(oldChecked.concat(v));
}
}
this.isFiltering = false;
window.localStorage.setItem('tempCheckedStudentIds', JSON.stringify(temp));
this.getCheckedStudentIds(temp);
},
// 取消选择时触发,将学生名字取消,id从中删除
cancelCheck(selection, row) {
this.deleteStudentId([row]);
},
// 表格全选框改变时取消,这里主要用在该分页数据全部取消时,弥补上两个方法监测不到
checkAll(selection) {
if (selection.length === 0) {
this.deleteStudentId(this.pageData.list);
}
},
//将取消选择的数据从localStorage删除掉,为了做选择学生的交互效果,否则不用这么麻烦
deleteStudentId(list) {
const oldChecked = JSON.parse(window.localStorage.getItem('tempCheckedStudentIds')) || [];
if (oldChecked.length === 0) {
return false;
}
for (let j = 0; j < list.length; j++) {
for (let i = 0; i < oldChecked.length; i++) {
if (oldChecked[i].subjectId === list[j].subjectId) {
oldChecked.splice(i, 1);
}
}
}
window.localStorage.setItem('tempCheckedStudentIds', JSON.stringify(oldChecked));
this.getCheckedStudentIds(oldChecked);
}
// 数组去重
getTemp(list) {
const tempList = [];
const ids = [];
list.forEach(item => {
if (item.hasOwnProperty('subjectId')) {
if (!ids.includes(item['subjectId'])) {
ids.push(item['subjectId']);
tempList.push(item);
}
}
});
return tempList;
},
/**
* 切换成员表格成员选中状态
* */
toggleSelection(list) {
if (list && list.length) {
list.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
this.$forceUpdate();
},
/**
* 获取当前选中的所有成员id
* @param temp 临时存储的用户对象
* */
getCheckedStudentIds(temp) {
const {
ids,
names
} = this.setCheckedByKey(temp);
this.checkedStudentIds = ids;
this.showCheckedStudentName = names.length ? names.join(',') : '';
setTimeout(() => {
this.showCommit = true;
}, 300);
},
/**
* 通过指定类型过滤数据,数组去重
* @param list
* */
setCheckedByKey(list) {
const ids = [];
const names = [];
list.forEach(item => {
if (item.hasOwnProperty('subjectId')) {
if (!ids.includes(item['subjectId'])) {
ids.push(item['subjectId']);
names.push(item['subjectName']);
}
}
});
return {
ids,
names
};
}
最后,记得在打开弹窗组件的时候把数据全部传回来渲染。
子组件向父组件传值的时候,将选择的所有学生即window.localStorage的数据转存之后再清除,打开子组件再回传。是因为打开组件时只加载了第一页分页,而关闭弹窗前无法确定用户选择了哪些分页的数据,我们必须加载它们并且渲染,所以备份一次选择的数据。
this.paging();
this.loading = false;
window.localStorage.setItem('tempCheckedStudentIds', JSON.stringify(this.localStorageList));
this.getCheckedStudentIds(this.localStorageList);
this.$nextTick(() => {
this.toggleSelection(this.checkedStudentList);
});