ant-design踩坑:Cascader级联选择
Cascader 级联选择 遇到的问题
要点
- 级联选择 数据中 isLeaf: false 可以控制是否选中【false 表示不选中】,触发 loadData 函数
- 级联选择 数据中 如果当前层不是最终级【就是你要 id 的那层】,children 一定不能为[],否则会导致组件选中错误层级,不会触发 loadData 函数
详细
交代说明
公司开发后台管理系统,涉及一个地级区域选择的功能,实现效果如下
后台给的接口是根据参数查询省,然后市…,如下
查看官网文档
通过官网示例,了解到 采用 动态加载选项 示例的方式,使用 loadData 实现动态加载选项。
按照官网的介绍,结合实际接口,我们需要 每次动态修改 根据返回 数据进行 数据拼接。
编码
- 当然后台数据返回的字段与组件预制不同,我们可以借助 fieldNames 属性进行自定义字段。
- 编码 测试组件 时候,你会发现点击第一层的数据就会直接选中【我们要的是最后一层,通信商的 id】。查阅属性说明未果。但是通过示例后发现,数据中 isLeaf: false 可以控制是否选中,从而触发 loadData。
- 貌似准备就绪。然后,愉快的编码
- 点击非 type 是 3 的一层,进行接口调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const cascaderLoadData = selectedOptions => { const targetOption = selectedOptions[selectedOptions.length - 1] const { id, type } = targetOption targetOption.loading = true const newType = type + 1 if (type !== 3) { getDict({ [newType === 2 ? 'regionId' : 'cityId']: id, webId: id, type: newType }) } }
|
- 数据拼接,上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
saveVPNAddressDict(state, action) { const { params: { type, webId }, res, } = action.payload; const { VPNAddressDict } = state;
const pushList = (arr, typeNum) => { return arr ? arr .map(item => { if (!item) { return null; } return { ...item, loading: false, isLeaf: typeNum === 3, children: null, }; }) .filter(item => item) : []; };
let dicts = []; const dict = pushList(res, type); switch (type) { case 1: dicts = [...dict]; break; case 2: dicts = VPNAddressDict.map(item => { if (item.id === webId) { return { ...item, loading: false, children: [...dict], }; } return item; }); break; case 3: dicts = VPNAddressDict.map(items => { const list = items && items.children ? items.children : []; const children = list.map(item => { if (item.id === webId) { return { ...item, loading: false, children: [...dict], }; } return item; }); return { ...items, loading: false, isLeaf: false, children, }; }); break; default: dicts = []; break; } return { ...state, VPNAddressDict: dicts, };
|
- 然后按照示例使用组件
- 基本完成后。测试发现,如果你依次点击 【 广东 > 广州 > 移动 】( 选中最后一层),再次选择 【北京】 组件直接选中了 【北京】(直接选中第一层)。多次测试发现只要不点击最后一层,那么不会出现这个问题。
- 分析:根据 bug 出现的情况,可以判断,是执行了 saveVPNAddressDict 动态拼接函数 type= 3 的运营商数据拼接出现的问题。
- 检查代码未发现明显错误。通过打印数据发现,【北京】数据的 children 是个空数组。 凭借多年开发的直觉[🤦 好吧,我也不知道我是怎么知道的],推测 children 数据问题。
- 验证:自造一条假数据,直接给组件测试使用。数据如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const options = [ { value: '北京', label: '北京', isLeaf: false, children: [] }, { value: '广东', label: '广东', isLeaf: false, children: [] } ]
|
验证结果发现,children 字段如果是数组,会导致直接选中,不会触发 loadData。
8.修正。那么在函数执行时候,如果没被选中的 children 显示为 null。 修正如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| case 3: dicts = VPNAddressDict.map(items => { const list = items && items.children ? items.children : []; const children = list.map(item => { if (item.id === webId) { return { ...item, loading: false, children: [...dict], }; } return item; }); return { ...items, loading: false, isLeaf: false, children:children.length?children:null, }; }); break;
|
总结
- 级联选择 数据中 isLeaf,children 两个字段直接影响 是否被选中,loadData 是否会触发。