
如图所示,这是个常见的多选todolist
不过这里多了个要求,弹窗上下页面切换的时候需要保留勾选结果
这其实也不难,但是如果每次都手动写一遍却有点恼人,这次捋一下思路,并把核心代码记录一下,方便下次翻找
核心思想
- 在服务器返回的数据之外再维护一个列表A,存储被钩上的数据
- 在请求接口时候给服务器返回数据钩上已选的
- 点击全选或者单个勾选(或取消勾选)时候再次把当前页面的勾选数据同步给列表A
- 那如何同步呢?重点,后面针对性说同步函数
弹窗封装
data数据说明
- data对应的数据有;
- params: 外部传入接口请求的参数;
- single: 是否单选;
- pickedArr:承接外部传入的已选中元素数组后变成已选元素数组
- selectedItems:弹窗内已选中的元素数组;
- form: 弹窗内查询列表的参数;
1.对外提供show方法来调用,接受几个参数,
1.1config.single是否支持单选
1.2.params 接口请求需要的额外参数
1.3.外面已选的列表(最好是完整列表,数组元素包括id和对应的文字)
1.4 根据1.3进行一些过滤(有时候弹窗是个二级弹窗,需要根据params参数进行置空或过滤)最后把过滤后的数组作为当前弹窗已勾选列表来存储数据
show函数程序入口
-
初始化配置参数
-
初始化已选数据
-
请求列表
-
显示弹窗
function show(config) {
this.showMaterialPopup = true;
const { params, single, pickedArr } = config;
//配置参数覆盖
// Array.isArray(filterids) ? (this.filterids = []) : (this.filterids = []);
params ? (this.params = params) : (this.params = {});
single ? (this.single = true) : (this.single = false);
Array.isArray(pickedArr) ? (this.pickedArr = pickedArr) : (this.pickedArr = []);
///////
//初始化弹窗的已选数据
///////
const firstPickItem = this.pickedArr[0];
//根据params和已选中的第一个做一些判断或者过滤
//这里的代码是个二级弹窗,可以参考,
if (firstPickItem && firstPickItem.materialId && firstPickItem.materialId == params.materialId) {
//把传入已选上的元素的checked都钩上
this.selectedItems = this.pickedArr.map((item) => {
item.checked = true; //够上了
return { ...item };
});
} else {
//不符合要求的话,就忽略传入的已选中元素
this.selectedItems = [];
}//初始化列表查询数据 this.form.pageNum = 1; //查询列表数据 this.getList();
}
getList函数
-
获取元素时候,给【服务器返回的数据list】做勾选初始化
-
这里就处理了点击上下页面和第一次加载时候可以钩上已选数据
//获取元素时候,给【服务器返回的数据list】做勾选初始化
//这里就处理了点击上下页面和第一次加载时候可以钩上已选数据
function getlList() {
//合并请求参数
listAJAXFN({ ...this.form, ...this.params }).then((res) => {
if (res.code == 200) {
let { rows, total, size } = res.data;
// 创建选中序列号的Set,用于O(1)快速查找
//数组转set,方便快速判断
const selectArrSet = new Set(this.pickedArr.map((item) => item.id));
// 在单次迭代中处理所有行
rows = rows.map((item) => {
//如果已选元素里有这个元素,就钩上
item.checked = selectArrSet.has(item.id);
return item;
});
this.list = rows.filter((item) => !this.filterids.includes(item.id));
}
});
}
同步函数
-
1.把本页勾选了的数据给外面传入已勾选的数据对应勾选上
-
2.把本页存在且勾选了,但是外层传入的数组里面没有元素找出来合并到已选数据上面
-
3.全选或者单个勾选(取消或者够上)时候调用就可以了
//更新已选择的序列号
//在勾选过程中
function updateselectedSerialNumWhenPick() {
//步骤一
//判断有没有勾选上,针对外面已有选中数据
// 合并checked属性到this.pickedArr中存在的元素
this.pickedArr.forEach((aItem) => {
//从本页勾选的数组中找到外层传入的勾选数据进行匹配
//如果存在就给他勾选(因为进入页面后,用户可能取消掉了也有可能)
//这里只勾选就好了,不需要管不勾选的,不勾选的也不是我们想要的
const matchingBItem = this.list.find((bItem) => bItem.id === aItem.id);
if (matchingBItem) {
aItem.checked = matchingBItem.checked;
}
});
//步骤二,针对本页勾选的,但是外层数据没有传入的数据,
//要把它们找出来,并合并到一选数组里面
// 获取当前页面中中有而a中没有的元素
//够上了,且外面已勾选的没有它的数组
const uniqueToB = this.list.filter((item) => item.checked).filter((bItem) => !this.pickedArr.some((aItem) => aItem.id === bItem.id));
//更新已选中数据
this.pickedArr = [...this.pickedArr, ...uniqueToB];
}
确认函数
把已选好的数组里面的checked过滤下,传递出去,外面直接接收就行了
onMulitComfirm() {
//从已选元素里面拿
const arr =this.pickedArr.filter((item) => item.checked);
if (arr.length == 0) {
this.$u.toast('请勾选序列号');
return;
}
this.$emit('choose', this.material, arr);
this.showMaterialPopup = false;
}