如图所示,这是个常见的多选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;
}