您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“vue2響應式雙向綁定在對象或數組新增屬性頁面無響應怎么解決”,內容詳細,步驟清晰,細節處理妥當,希望這篇“vue2響應式雙向綁定在對象或數組新增屬性頁面無響應怎么解決”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
vue2 中可以將數據與視圖進行綁定,修改 data 對象的屬性值將引起對應視圖的改變。
Vue2的數據視圖綁定是通過JS特性這一語法實現,其使用中存在數據屬性丟失的這 一 bug,主要針對 對象或數組 屬性丟失。
使用 antv 的 a-select (下拉框)組件,使用 v-mode 綁定對象 的值,但是 對象之前是沒有賦值的,是一個 空對象 ,這就導致了 頁面視圖不刷新 ,但是 屬性值有變化 ,這可以說是 vue2 的一個缺陷。
// 空對象 queryParam: { },
方法一 (設置初始值)
給 綁定的對象 賦初始值 null 或者 ' '
queryParam: { approveStatus : null , },
如果是普通 輸入框 input ,這樣的方法沒什么問題,但是 我的頁面使用 a-select 下拉框,默認有提示消息( placeholder),如果 賦初始值 為空 ,下拉框會填充空白內容 ,覆蓋之前的提示消息 ,這樣的頁面 會比較不美觀且不友好
<a-select v-model="queryParam.approveStatus" placeholder="審核狀態" :allowClear="true"> <a-select-option v-for="status of videoApproveStatus" :key="status.id"> {{ status.text }} </a-select-option> </a-select> <a-select v-model="queryParam.videotypeid" placeholder="視頻類型" :allowClear="true"> <a-select-option v-for="d in videotype" :key="d.myid"> {{ d.name }} </a-select-option> </a-select>
雖然這種方法可以解決綁定對象屬性丟失問題,但是如果給 每個屬性設置 初始值 為 null,那么所有的下拉框都是空白 , 可以看到 下拉框 賦初始值 為 null ,頁面的效果非常不友好 ,沒有提示信息 ,所有這種方法不推薦
方法二 (創建一個新的對象,替換原對象)
這種方法可以用于需要添加多個新屬性,再把原對象與新屬性合并到新對象中
Object.assign(目標對象,原對象, 新屬性)
this.queryParam = Object.assign({}, this.queryParam, obj)
我這里是 利用 a-select 下拉框 自帶的 下拉框 改變方法 ,@change ,該方法有兩個參數 value 和 option ,value 代表你改變的值 ,option (我也不太明白 ,反正里面東西很多),然后 我利用 這個 @change 方法 和 Object.assign(目標對象,原對象, 新屬性), 解決了狀態丟失問題 ,大家可以 參考下面的代碼 ,根據自己的實際情況進行調整 (每個人的情況都不一樣)
<a-select @change="handleChange" v-model="queryParam.approveStatus" placeholder="審核狀態" :allowClear="true"> <a-select-option v-for="status of videoApproveStatus" :key="status.id"> {{ status.text }} </a-select-option> </a-select>
handleChange(value,option) { if(option) { // 解決雙向綁定狀態丟失 this.queryParam = Object.assign({}, this.queryParam, option.context.queryParam) } else { return } },
JS的對象有兩種屬性進行描述 分別是數據屬性和訪問器屬性。
數據屬性有四個值:
[[Configurable]]
表示是否可以刪除定義,是否可以修改屬性,默認為true
[[Enumberable]]
是否可以迭代
[[Writable]]
是否可以被修改
[[Value]]
對象具體的值
而訪問器屬性也有四個值:
[[Configurable]]
表示是否可以刪除定義,是否可以修改屬性,默認為true
[[Enumberable]]
是否可以迭代
[[Get]]
獲取函數,讀取屬性值時使用
[[Set]]
設置函數,寫入屬性時調用
那么如何實現數據響應呢?
實現響應式的前提是可以捕捉到到數據的更改,獲取數據同理,這就需要利用JS對象的訪問器屬性,而更改這些屬性 就要用到JS中的一個方法 Object.defineProperty() 上述的屬性在更改時,哪怕更改一個屬性,所有屬性都會變為默認值。
具體使用方法如下:
let obj = {name:'Ton', age: 19} _value = obj.name Object.defineProperty(obj, name, { get(){ return _value }, set(newValue){ _value = newValue } })
方法的參數分別是 Object.defineProperty(對象名, 屬性名, {執行器})
而get 函數在讀取該對象屬性時調用,返回的值為讀取的值; set 函數會在設置新值時調用 傳入的newValue為新值。
在Vue中 會用data一個對象包裹所有的值,因此可以用遍歷的方法給每個屬性加上該方法。
將該邏輯封裝到一個函數中:
let data = { name: 'Ton', age: 19, salary: '10k' } Object.keys(data).forEach( key => { observe(data, key, data[key]) }) //形成閉包 內部的變量不會消失 function observe(obj, key, value){ Object.defineProperty(obj, key, { get(){ return value }, set(newValue){ value = newValue } }) }
這樣data中的所有變量都會被綁定,但如果嵌套對象或數組,內部的對象不會被檢測到。(可以用vue提供的 $set和 $delate 處理或 使用內部重寫的數組方法)
與標簽聯動的方法有許多,最簡單的是使用id 來綁定,而Vue中是使用指令的方式。
過程主要分兩步:
獲取dom
將數據放上去
... <div id="app"> <div v-test="name" class="box"></div> <div v-test="age" class="box"></div> </div> ... function compile(){ let app = document.getElementById('app') //獲取所有的子節點 值為3的是text節點 1為子標簽節點 app.childNodes.forEach( node => { if(node.nodeType === 1){ //遍歷該節點的屬性 找出 v-text //node.attributes是個類數組對象, 先轉化為數組 Array.from(node.attributes).forEach( key => { //解構對象 nodeName 找到屬性 let { nodeName, nodeValue } = key //如果存在 則修改值(關鍵步驟) if(nodeName === 'v-test'){ node.innerText = data[nodeValue] } }) } }) } compile() ...
此時可以獲取節點,并賦值數據,與數據劫持聯動,最終結果如下:
let data = { name: 'Ton', age: 19} //劫持數據 Object.keys(data).forEach(key => { observe(data, key, data[key]) }) //形成閉包 內部的變量不會消失 function observe(obj, key, value) { Object.defineProperty(obj, key, { get() { return value }, set(newValue) { value = newValue compile() } }) } //獲取元素 將數據放入 function compile(){ let app = document.getElementById('app') //獲取所有的子節點 包括很多節點 3 為text 節點 1為子標簽節點 app.childNodes.forEach( node => { if(node.nodeType === 1){ //遍歷該節點的屬性 找出 v-text //node.attributes是個類數組對象, 先轉化為數組 let result = Array.from(node.attributes).filter( key => { //結構屬性的 nodeName 找到屬性 let { nodeName } = key return nodeName === 'v-test' }) if(result){ node.innerText = data[result[0].nodeValue] } } }) } compile()
每次修改也會引起DOM元素的修改,實現響應式。
同v-test(v-on) 的不同,v-model要實現雙向綁定,即 input框輸入的值也需要傳回data。實現的邏輯前面是相同的,都需要獲取元素,但需要新增將input輸入框的內容,傳回。
let data = { name: 'Ton', age: 19} //劫持數據 Object.keys(data).forEach(key => { observe(data, key, data[key]) }) //形成閉包 內部的變量不會消失 function observe(obj, key, value) { Object.defineProperty(obj, key, { get() { return value }, set(newValue) { value = newValue compile() } }) } //獲取元素 將數據放入 function compile(){ let app = document.getElementById('app') //獲取所有的子節點 包括很多節點 3 為text 節點 1為子標簽節點 app.childNodes.forEach( node => { if(node.nodeType === 1){ //遍歷該節點的屬性 找出 v-text //node.attributes是個類數組對象, 先轉化為數組 let result = Array.from(node.attributes).filter( key => { //結構屬性的 nodeName 找到屬性 let { nodeName } = key return nodeName === 'v-model' }) if(result){ node.value = data[result[0].nodeValue] addEventLisener('input', e => { data[result[0].nodevalue] = e.target.value } ) } } }) } compile()
但目前的方法并不完美,需要添加一個防抖函數
let data = { name: 'Ton', age: 19} //劫持數據 Object.keys(data).forEach(key => { observe(data, key, data[key]) }) //形成閉包 內部的變量不會消失 function observe(obj, key, value) { Object.defineProperty(obj, key, { get() { return value }, set(newValue) { value = newValue compile() } }) } //獲取元素 將數據放入 function compile(){ let app = document.getElementById('app') //獲取所有的子節點 包括很多節點 3 為text 節點 1為子標簽節點 app.childNodes.forEach( node => { if(node.nodeType === 1){ //遍歷該節點的屬性 找出 v-text //node.attributes是個類數組對象, 先轉化為數組 let result = Array.from(node.attributes).filter( key => { //結構屬性的 nodeName 找到屬性 let { nodeName } = key return nodeName === 'v-model' }) if(result){ node.value = data[result[0].nodeValue] addEventLisener('input', debounce(handel, result[0].nodeValue) } } }) function debounce(fn, key, timer = 1000){ let t = null return function(){ if(t) { clearTimeout(t) } t= setTimeOut( _ => { t = null fn.call(this, key, arguments) },timer) } } function handel(key, event){ data[key] = event.target.value } } compile()
讀到這里,這篇“vue2響應式雙向綁定在對象或數組新增屬性頁面無響應怎么解決”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。