实战:低代码的场景-下拉选择关联(下)
前言
我知道这对你来说可能有些困难,但请相信我,你有足够的能力去克服它。
仔细看下去,相信能收获一些干货滴~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一、问题剖析
还没看过的,可以先移步去看看,看完在接着这篇。
后续需求的迭代,发现挺有意思的,继续输出😘。
我们先来回顾一下需求:
有一个表单,有
- 下拉框A,选项值为A1和A2
- 下拉框B,选项值为B1和B2
- 下拉框C,选项值为C1和C2
现在需要做关联关系的约束,不然在填报的时候 选项太多容易搞错。
比如通过低代码配置下拉框A,选了A1之后,触发下拉框B的选项值改变
下拉框B,选了B1之后,触发下拉框C的选项值改变。
丝滑入场 😋。
二、下次编辑进入,更新option
直到我认为万无一失的时候,新增的时候,关联修改了选项。
操作:
- A字段关联了B字段,把option(A1、A2)赋值给B
- B字段原本的option(B1、B2)
当我下次编辑的时候,字段B的option恢复原本的(B1、B2),而我编辑的值比如A1,在字段B中找不到A1,因为option被恢复原本的值。
我们需要在编辑进入的时候,也要去改变option是关联的选项。
因为编辑的时候,options没有更新,需手动触发
- this.fields:表单字段的配置
// 因为编辑的时候,options没有更新,需手动触发
this.fields.forEach(f =>{
// item是当前的值,添加notUpdateVal属性:代表不更新val,因为change内部会将val赋空
this.change({ config: f, item: this.formData[f.id], notUpdateVal: true })
})
三、需求迭代
以上是编辑/新建的情况下,现在需要列表的时候可以修改。
按理说���可以把上面编辑的那套逻辑搬过去。
代码如下:
change(data){
const dataControl = getV(data, 'config', 'config', 'dataControl')
// 关联关系,通过下拉选项选择 A,约束后面的可选择项
if(getV(dataControl, 'length')){
let obj = {}
for (let index = 0; index < dataControl.length; index++) {
const element = dataControl[index];
const f = this.fields.find(f => f.id == element.srcFormFieldKey && getV(f, 'slot', 'options'))
if(f.id == element.srcFormFieldKey && getV(f, 'slot', 'options')){
if(!getV(f, 'slot', 'options_backup', 'length')) f.slot.options_backup = JSON.parse(JSON.stringify(f.slot.options)) || [] // backup config
if(data.formData && data.formData[f.id] && !data.notUpdateVal) {
data.formData[f.id] = `` // update val
}
const isEqual = (element) => Array.isArray(data.item) ? data.item.includes(element.currentVal) : element.currentVal == data.item // 当前值和配置的值--是否相等
const opt = equals(f.slot.options, f.slot.options_backup) ? element.options : this.uniqueArray2(dataControl.filter(c => isEqual(c) ).map(m => m.options).flat()) // 判断当前的option是否和原始的一样,如果一样就直接赋值(第一次进入);否则,第二次就合并后去重
f.slot.options = isEqual(element) ? opt : f.slot.options_backup; // update config
getV(f, 'config', 'dataControl', 'length') && this.change({ config: f, notUpdateVal: data.notUpdateVal }) // 若为空,清空之前的数据
if(isEqual(element)) break;
}
}
}
},
基本没什么变化,唯一需要注意的点是:
A字段当前的值选了A1,把A1的option赋值给B字段
然后保存😊。
第二次编辑的时候,直接选择B字段,发现选项又恢复初始化了,但第一次编辑的时候,我们已经修改了A字段,把A1的option给B字段了。
可现在又初始化了。
预期:第二次编辑的时候,也要回显A1的option给B字段。
方案
我一开始的想法是:
因为编辑的时候,options没有更新,需手动触发
现在是列表,二维,需要遍历两层,拿到列,再到行
// 列
this.fields.forEach((f, fIndex) =>{
// 行
this.dataList.forEach(d =>{
this.change({ config: f, item: d[f.id], notUpdateVal: true })
})
})
可是,你忘记了一个点:
我们的整个表格的行,对应的都是一个列的配置。
上面的循环,数据再怎么循环,都是操作一个列的对象,不能想A数据的【名字--列】显示A1;
B数据的【名字--列】显示B1;
按照上面的写法,都是一样的。
所以,不可行 🤡。
不像我们的新建/编辑,只是操作一条数据,这里列表操作的是多条数据。
方案二
我们现在改变select的选项会去找他的下游,改变下游(孩子)的选项。
那我们是不是点击select的时候可以去寻找他的上游(父亲)
注意,这是两个事件:
- click点击:寻找上游
- change改变值:寻找下游
现在,我们来看看click事件是怎么寻找上游的。
template
可以看到我们的click事件,添加了native因为他是组件。
<item :conf="item" :row="scope.row"
@click.native="clickEdit({config: item, formData: scope.row})"
@change="(e) => change({item: e, config: item, formData: scope.row})" />
我们重点来看看clickEdit函数
- 遍历表格的配置,找到当前配置的上游(父亲)
- 我们dataControl配置的是数组,命中当前值才会选择option
- 寻找父亲当前命中的值
- 拿到之后去设置给孩子
总结:当前的数据的配置,去寻找他关联的父亲,找到父亲的选项,赋值给孩子。
clickEdit(data){
// this.fields:整个表格的配置
const fater_find = this.fields.find(f => {
const dataControl = getV(f, 'config', 'dataControl') // 关联的属性
if(getV(dataControl, 'length')){
// 找到父亲
return dataControl.find(d => d.srcFormFieldKey == data.config.id )
}
})
if(getV(fater_find, 'config', 'dataControl', 'length')){
// data.formData:数据
// 我们dataControl配置的是数组,命中当前值才会选择option
// 寻找父亲当前命中的值
const dataControl_find = fater_find.config.dataControl.find(f => f.currentVal == data.formData[fater_find.id])
if(getV(dataControl_find, 'options', 'length')){
// 拿到之后去设置给孩子
data.config.__slot__.options = dataControl_find.options
}
}
},
其实这些公共的方法,在我的github上有写过:ArrayTool
后记
这种类似的场景一般用于可视化低代码平台中。
会根据配置来动态渲染。
做好扩展性,遵守开闭原则。
当然,我们还要考虑安全性防XSS注入,防止外部嵌入,导致安全问题。
如果有其他更好的方法也欢迎评论区见,这里提供的只是诸多方法之一。
最后,祝君能拿下满意的offer。
👍 如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
原文链接
转载自:https://juejin.cn/post/7397022072058691594