資料繫結之無法檢測的資料更改
Vue元件內是雙向繫結,元件間(比如父子通訊)是單向繫結(react無論元件內外都是單向資料繫結),但有三種情況下,更改元件內的資料不會自動重新整理檢視
1:Vue不能檢測到已有物件屬性的新增或刪除
錯誤寫法:this.$data.test.a=xxx
正確寫法:vue.set(object,key,value)
或 Object.assign()
示例:
<script> export default{ name:'Item', data(){ return{ pagition:{ } } }, create(){ this.getList() } getList(){ //request請求 getCurrentList(data).then(res=>{ //可以賦值,但不會引起檢視重新整理 this.pagition.size=res.size this.pagtion.current=res.current //正確寫法 this.$set(this.pagition,'size',res.size) this.$set(this.pagition,'current',res.current) //也可以直接複製 this.pagition=Object.assign({},{size:res.size,current:res.current}) }) } } </script>
如:
1. this.$set(this.test,’a’,xxx)
或 Vue.set(this.test,’a’,xxx)
2. this.test=Object.assign({},this.test,{a:xxx})
2:通過改動兩種方式改動陣列時,Vue檢測不到變動
1.利用索引直接設定一個項
2.修改陣列長度
2.1 利用索引直接設定一個項,不能直接觸發狀態更新。
錯誤寫法:this.trees[idx]=’x’
正確寫法:this.$set(this.trees,idx,’x’)
或 this.trees.splice(idx,1,’x’)
2.2 改變陣列長度
錯誤寫法:this.trees.length=2;
正確寫法:this.trees.splice(2);
總結:
-
1.只有在元件data中已經定義的物件的屬性直接賦值才可以引起檢視重新整理,對於物件的新增屬性,需要使用
$set
賦值或者對data中已存在物件進行整體賦值才能重新整理檢視 -
2.物件新增屬性時直接賦值時,watch無法監聽。watch可以監聽$set引起的變動,因為watch內部監聽的是資料的setter,已存在的屬性在data初始化時已經綁定了getter/setter
-
3.對於能夠已經在data中宣告過的屬性,可以直接進行賦值。雖然此時使用
$set
也可以。但是此時$set
沒有直接賦值效能好(因為已存在屬性賦值只會呼叫內部setter,而$set
原理:當你把一個普通的JavaScript物件傳給Vue例項的data選項,Vue將遍歷此物件所有的屬性,並使用Object.defineProperty把這些屬性全部轉為getter/setter。Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是為什麼 Vue 不支援 IE8 以及更低版本瀏覽器。
這些getter/setter對使用者來說是不可見的,但是在內部他們讓vue追蹤依賴,在屬性被訪問和修改時通知變化。每個元件例項都有相應的watcher例項物件,它會在組建渲染的過程中把屬性記錄為依賴,之後當依賴項的setter被呼叫時,會通知watcher重新計算,從而致使它關聯的元件得以更新。
屬性的刪除用$delete,用js的delete
關鍵字不會引起檢視重新整理,因為
$delete不會呼叫資料的setter
拓展:
可以直接引起檢視重新整理的賦值的js的API(對data中已存在的屬性而言)
push:資料尾插入
pop:尾刪除
unshift:頭插入
shift:頭刪除
splice:插入並刪除
...
這些js的api會操作呼叫它的物件,會直接修改原資料,vue預設對它們進行了特殊處理。呼叫這些api會在內部呼叫資料的setter,從而引發檢視重新整理
settter的工作流程
能否用watch實現物件和陣列內屬性的直接修改導致檢視自動重新整理?
物件和陣列內屬性的直接修改不能重新整理檢視,是因為vue內監聽資料的層級是一級,不會監聽data中宣告的資料裡的資料,因此在watch中依然不行,如果是直接對data中資料進行賦值或者使用特定api,則沒有必要使用watch。
watch應用場景:假如v-model 輸入框繫結一個變數a 可以輸入改變變數a 另一個文字繫結變數b ,他倆不是一個變數 但是b又隨著a變化而變化,這樣的話就用到watch了
vue中元件間(父子,兄弟),為什麼不是雙向繫結?
如果父子元件通訊是雙向的話 則父變子變,子變父變,子父改變無窮盡也,可能會死迴圈。兄弟元件也一樣