1. 程式人生 > 實用技巧 >資料繫結之無法檢測的資料更改

資料繫結之無法檢測的資料更改

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

    會先對值進行setter繫結,然後在呼叫settter,多走了一步)

原理:當你把一個普通的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中元件間(父子,兄弟),為什麼不是雙向繫結?

如果父子元件通訊是雙向的話 則父變子變,子變父變,子父改變無窮盡也,可能會死迴圈。兄弟元件也一樣