首頁 > web前端 > js教程 > 主體

[Vue] v-model 綁定物件不即時更新

做棵大树
發布: 2020-07-14 09:42:01
原創
170 人瀏覽過

原文連結:做棵大樹

在最近參與的一個專案中,前端用到了vue.js 框架,期間有個功能需要動態的向一個被綁定的物件中新增屬性。但在實際應用中問題出現了:在物件中新增屬性後,與物件綁定的元件內容卻未發生變化,必須再次刷新元件,其內容才會變成變更後的內容。

起初我以為是屬性沒有加入成功,因為在我的印像中 v-model 是雙向綁定的,不會出現不更新的狀態。在我查看 Devtools 中的監控後,發現對應的物件確實添加了指定的屬性。

於是,我前去查看了官方文檔,找到了官方給出的解釋:Vue.js如何追蹤變化

#

官方解釋

#當你把一個普通的JavaScript 物件傳入Vue 實例作為data 選項,Vue 將遍歷此物件所有的property,並使用Object.defineProperty 把這些property 全部轉為getter/setterObject.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是 Vue 不支援 IE8 以及更低版本瀏覽器的原因。

每個元件實例都對應一個 watcher 實例,它會在元件渲染的過程中把「接觸」過的資料 property 記錄為依賴。 之後當依賴項的 setter 觸發時,會通知 watcher,從而使它關聯的元件重新渲染。

[Vue] v-model 綁定物件不即時更新
官方解釋圖例

#偵測變化的注意事項

#由於JavaScript 的限制,Vue 無法偵測陣列和物件的變化。儘管如此我們還是有一些辦法來迴避這些限制並保證它們的回應性。

對於物件

#Vue 無法偵測 property 的新增或移除。由於 Vue 會在初始化實例時對 property 執行 getter/setter 轉化,所以 property 必須在 data 物件上存在才能讓 Vue 將它轉換為響應式的。例如:

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">var vm = new Vue({<br/>  data:{<br/>    a:1<br/>  }<br/>})<br/><br/>// `vm.a` 是响应式的<br/><br/>vm.b = 2<br/>// `vm.b` 是非响应式的<br/></code>
登入後複製

對於已經建立的實例,Vue 不允許動態新增根層級的回應式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法為嵌套物件新增響應式 property。例如,對於:

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">Vue.set(vm.someObject, <span class="hljs-string" style="color: #D69D85; line-height: 26px;">&#39;b&#39;</span>, 2)<br/></code>
登入後複製

您也可以使用vm.$set 實例方法,這也是全域Vue.set 方法的別名:

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">this.<span class="hljs-variable" style="color: #BD63C5; line-height: 26px;">$set</span>(this.someObject,<span class="hljs-string" style="color: #D69D85; line-height: 26px;">&#39;b&#39;</span>,2)<br/></code>
登入後複製

有時你可能需要為已有物件賦值多個新property,例如使用Object.assign()_.extend()。但是,這樣新增到物件上的新 property 不會觸發更新。在這種情況下,你應該用原始物件與要混合進去的物件的 property 一起建立一個新的物件。

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`<br/>this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })<br/></code>
登入後複製

這是對於物件賦值的解決方式,在採用了官方的解決方案 this.$set(object, key, value) 後確實實現了即時更新的效果。同時對於陣列等情況,可查看 餘下官方文件

為什麼會這樣呢?

如官方所說「由於JavaScript 的限制,Vue 無法偵測陣列和物件的變化。」 ,但為什麼會這樣呢?

借用 Segmentfault UKer 的回答:

ECMAScript中有两种属性:数据属性访问器属性; 数据属性的描述符为:Configurable,Enumerable,Writable,Value; 访问器属性的描述符为:Configurable, Enumerable,set,get。

当我们使用new Vue(obj),其内部发生了大体如下代码的转换,即,将数据属性转换为了访问器属性

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;"><span class="hljs-keyword" style="color: #569CD6; line-height: 26px;">function</span> Vue(obj){<br/>    obj.data.keys().forEach((prop, index) => {<br/>      Object.defineProperty(obj.data, prop, {<br/>        <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">set</span></span>(){<br/>          //可以在此处进行事件监听<br/>        },<br/>        <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">get</span></span>(){<br/>    <br/>        }<br/>      })<br/>    })<br/>    <span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">return</span> obj;<br/> }<br/></code>
登入後複製

但是当我们后面再次使用普通的赋值,仅仅是赋值了一个数据属性的,这个属性是不会具有访问器属性的事件监听功能的。

至此,v-model 绑定数据不实时更新的问题方才得到了解决。


[Vue] v-model 綁定物件不即時更新
[Vue] v-model 綁定物件不即時更新

以上是[Vue] v-model 綁定物件不即時更新的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
1
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!