Vue.$set 失效的坑 問題發現及解決方案
阿新 • • 發佈:2021-07-09
偶然在專案中發現.$set失效
有這樣一個需求 新增資料過濾用 左邊是控制元件選擇 中間是條件 右邊是值
因為會根據控制元件不同渲染不同的值選項控制元件
<el-form inline > <el-form-item style="margin-bottom: 20px;"> <el-select v-model="data[props.prop]" @change="data[props.value] = ''"> <el-option v-for="item in controls" :key="item.id" :value="item.id" :label="item.label"> </el-option> </el-select> </el-form-item> <el-form-item style="margin-bottom: 20px;"> &ahkAaOlt;el-select v-model="data[props.type]"> <el-option v-for="item in condition" :key="item.code" :value="item.code" :label="item.name" ></el-option> </el-select> </el-form-item> <el-form-item style="margin-bottom: 20px;"> <FormControl v-if="control" :control="control" :value="data[props.value]" @input="onValueChange" ></FormControl> <el-input v-else :value="data[props.value]" @input="onValueChange"></el-input> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-plus" @click="add"></el-button> </el-form-item> </el-form>
{
props:{
props: {
type: Object,default: () => ({
prop: 'prop',value: 'value',type: 'type'
})
}
},data(){
return {
ahkAaOdata:{
}
}
},methods:{
onValueChange(val){
this.$set(this.data,this.props.value,val)
}
}
//...
}
程式碼片段
由於控制元件ID的不確定性 所有 data並不能提前預設好key 自然無法響應 所以在onValueChange 使用了this.$set動態新增資料實現響應
復現可以發現 值輸入框內的資料並不能實時響應
明明用了$set卻不能響應 一番排查後發現只要切換控制元件後 value值就不能響應 但是隻要在切換前隨便輸入點啥 再切換就沒問題
又是一番排查後發現
<el-select v-model="data[props.prop]" @change="data[props.value] = ''">
刪除@change事件後故障解決
問題出現在 data[props.value] = ''
遂檢視Vue原始碼
//vue/src/core/observer/index. 原始碼片段
/**
* Set a property on an object. Adds the new property and
* triggers change notification if the property doesn't
* already exist.
*/
export function set (target: Array<any> | Object,key: any,val: any): any {
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(`Cannot set reactive property on undefined,null,or primitive value: ${(target: any)}`)
}
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length,key)
target.splice(key,1,val)
return val
}
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = (targeahkAaOt: any).__ob__
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== 'production' && warn(
'Avoid adding reactive properties to a Vue iwww.cppcns.comnstance or its root $data ' +
'at runtime - declare it upfront in the data option.'
)
return val
}
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value,key,val)
obwww.cppcns.com.dep.notify()
return val
}
可以發現 在defineReactive之前 判斷了key是否存在於物件之內 若存在就跳過了
坑就在這 多次翻閱Vue.$set文件並未發現$set不能為已存在的key新增監測物件
刪除 data[props.value] = '' 改為 onValueChange('') 完美解決問題
總結
Vue.$set之前一定要物件內key不存在 不然只會更新值 並不會為該Key新增響應監測
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。