目录
需求:
前段时间,接到了一个需求:在选择框中选中某个下拉菜单时,对应的输入框就得自动填上对应的值。比如在药品名称中选取了生理盐水,下栏的药品单位和药品用法就会自动填上对应的值
img
img
出现 BUG:
接到这个需求后,我就想到用 v-model 去改变值,但是实现选中菜单自动填写对应的值后,心想用户想修改某个值怎么办?于是我测试时,发现自动填写的值删除不了,重新选取药品名称也无法改变了。那岂不是相当于写死了?
Bug 代码复现
<el-form-item v-for="(drug, index) in dynamicValidateForm.drugs" :key="index">
<el-form-item>
<el-row :gutter="12">
<el-col :span='11'>
<el-select v-model="drug.name" clearable filterable placeholder="药品名称" @change="selectDrug($event,index)">
<el-option v-for="item in drugs" :key="item.id" :label="item.药品名称"
:value="item.药品名称" >
</el-option>
</el-select>
</el-col>
<el-col :span='7'>
<el-input placeholder="药品剂量" v-model="drug.amount" type='number'>
</el-input>
</el-col>
<el-col :span='4'>
<el-button @click.prevent="removeDrug(drug)" round type="danger"
icon="el-icon-delete">删除</el-button>
</el-col>
</el-row>
<el-row :gutter="12">
<el-col :span='6'>
<el-input placeholder="药品单位" v-model="drug.unit">
</el-input>
</el-col>
<el-col :span='6'>
<el-input placeholder="用法" v-model="drug.method">
</el-input>
</el-col>
<el-col :span='6'>
<el-input placeholder="频率" v-model="drug.freq">
</el-input>
</el-col>
<el-col :span='6'>
<el-input placeholder="使用时机" v-model="drug.use">
</el-input>
</el-col>
</el-row>
</el-form-item>
</el-form-item>
data () {
return {
dynamicValidateForm: {
domains: [{
value: ''
}],
nursings: [],
drugs: [],
email: ''
},
}
},
methods: {
selectDrug(e, index) {
const _this = this;
this.drugs.forEach(ele => {
if( ele.药品名称 === e ) {
_this.dynamicValidateForm.drugs[index].unit === ele.默认单位)
_this.dynamicValidateForm.drugs[index].method === ele.默认用法)
}
})
},
}
解决问题:
然后我查看了官方文档终于明白了:Vue 在实例创建之后添加新的属性到实例上,它不会触发视图更新。
解决方法1:
由此Vue实例创建时,unit 和 method 在dynamicValidateForm中未声明,因此 Vue 就无法对属性执行 getter 和 setter 方法转化过程,以至于dynamicValidateForm 属性不是响应式的,因此无法触发视图更新。所以我们得声明 dynamicValidateForm 这两个对象的属性,如:
data () {
return {
dynamicValidateForm: {
domains: [{
value: ''
}],
nursings: [],
drugs: [],
email: ''
unit: '', // 在 dynamicValidateForm 中声明 unit
method: '' // 在 dynamicValidateForm 中声明 method
},
}
},
methods: {
selectDrug(e, index) {
const _this = this;
this.drugs.forEach(ele => {
if( ele.药品名称 === e ) {
_this.dynamicValidateForm.drugs[index].unit === ele.默认单位)
_this.dynamicValidateForm.drugs[index].method === ele.默认用法)
}
})
},
}
解决方法2
我们可以使用 Vue 的全局 API : $set()赋值:
data () {
return {
dynamicValidateForm: {
domains: [{
value: ''
}],
nursings: [],
drugs: [],
email: ''
},
}
},
methods: {
selectDrug(e, index) {
const _this = this;
this.drugs.forEach(ele => {
if( ele.药品名称 === e ) {
_this.$set( _this.dynamicValidateForm.drugs[index],'unit', ele.默认单位)
_this.$set( _this.dynamicValidateForm.drugs[index],'method', ele.默认用法)
}
})
},
}
关于 $set() 的补充:
官方文档:向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi') 注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。