项目需求 后台表单是前台自建的 控件自然也要自建 自然就有各种选项
其中选择框 就有单选多选选项 项目使用的element-ui 自然就用的el-select
由于数据库并没有类似数组的字段 选择框使用varchar 而el-select多选时却需要使用数组 所以在编辑时 需要将值转成数组再赋值给el-select的value
<template>
<el-select
:value="data"
@change="val => $emit('input', String(val))"
:disabled="control.disabled == '1'"
:multiple="control.multiple == '1'"
:allow-create="control.allow_create == '1'"
:style="css"
:size="size"
filterable
default-first-option
clearable
>
<el-option
v-for="option in options"
:key="option.value"
:label="option.label"
:value="option.value">
<slot :option="option"></slot>
<!-- <component v-if="slotsEx" :is="slotsEx" :option="option"></component> -->
</el-option>
</el-select>
</template>
<script>
export default {
computed:{
data(){
if(this.control.multiple == '1' && this.value && this.value.split){
return this.value.split(',')
}else{
if(this.control.multiple == '1'){
return []
}else{
return this.value
}
}
}
}
}
</script>
data根据控件属性 control.multiple 动态计算
由于我们的数组数据是使用逗号分隔符 所以直接使用String可以提交数据就可以 单选多选的时候 都可以提交正确的数据
单独使用的时候 多选单选都没有问题 但是由于配置的时候 需要实时切换 切换的时候 就报了错
errorLog.js:17 TypeError: Cannot read property 'value' of undefined
at VueComponent.getValueKey (index.js:1)
at Proxy.boundFn (vue.esm.js:188)
at index.js:1
at Proxy.renderList (vue.esm.js:3673)
at Proxy.n (index.js:1)
at VueComponent.Vue._render (vue.esm.js:4437)
at VueComponent.updateComponent (vue.esm.js:2755)
at Watcher.get (vue.esm.js:3105)
at Watcher.run (vue.esm.js:3182)
at flushSchedulerQueue (vue.esm.js:2944) "render"
错误栈都在Vue内部
查看el-select源码(element\packages\select\src\select.vue )后 推测应该是触发multiple更改后value值还未计算 select已经开始响应渲染 而此时value值还未被计算成数组 导致内部出错
查看官方文档后并未发现有multiple动态更改的方法,也不好大改el-select控件 随后想到可以在更改multiple后重新渲染组件
查看官方文档 可使用 $forceUpdate
强制更新组件
使用后发现 效果并不理想 原因 $forceUpdate
只能控制重渲染 并不能控制渲染过程
虽然该错误并不多影响实际使用 一个好的猴子不能就此放弃
随后想到可以使用v-if控制渲染 在multiple改变时停止渲染 待value计算完毕后重新渲染组件
由于javascript是队列机制 可以使用setTimeout 将函数推至队列末尾 即可实现value计算后重新渲染组件
由于只有在编辑控件的时候 才会触发重新渲染 所以在实际使用中并不会触发 不会有性能问题
<el-select
v-if="update"
...more
></el-select>
<script>
{
data(){
return {
update: true
}
},
watch:{
'control.multiple'(){
this.update = false
setTimeout(()=>{
this.update = true
})
}
}
}
</script>
完美解决
总结
善用setTimeout 0 遇到解决不了的问题 可以通过翻阅文档、源码、另辟蹊径等方法解决