Vue.$set 失效的坑 問題發現及解決方案
偶然在項目中發現Vue.$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;"> <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 { data:{ } } }, 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.js 源碼片段 /** * 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 = (target: any).__ob__ if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance 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) ob.dep.notify() return val }
可以發現 在defineReactive之前 判斷瞭key是否存在於對象之內 若存在就跳過瞭
坑就在這 多次翻閱Vue.$set文檔並未發現$set不能為已存在的key添加監測對象
刪除 data[props.value] = ” 改為 onValueChange(”) 完美解決問題
總結
Vue.$set之前一定要對象內key不存在 不然隻會更新值 並不會為該Key添加響應監測
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 前端vue2 element ui高效配置化省時又省力
- vue實現省市區的級聯選擇
- 關於element-ui select 下拉框位置錯亂問題解決
- vue 動態添加el-input的實現邏輯
- VUE多個下拉框實現雙向聯動效果