當你把一個普通的JavaScript對象傳給Vue實例的data選項,Vue將遍歷此對象所有的屬性,並使用Object.defineProperty把這些屬性全部轉為getter/setter。Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器。
這些getter/setter對用戶來說是不可見的,但是在內部他們讓vue追蹤依賴,在屬性被訪問和修改時通知變化。每個組件實例都有相應的watcher實例對象,它會在組建渲染的過程中把屬性記錄為依賴,之后當依賴項的setter被調用時,會通知watcher重新計算,從而致使它關聯的組件得以更新。
對象更改檢測
在一個組件實例中,只有在data里初始化的數據才是響應的,Vue不能檢測到對象屬性的添加或刪除,沒有在data里聲明的屬性不是響應的。
Vue不允許在已經創建的實例上動態添加根級響應式屬性,但是可以使用$set方法將相應屬性添加到嵌套的對象上。
例子一:屬性a是已經聲明了的,是響應的;屬性b沒有提前聲明,因此改變了屬性b的值的時候,如果直接賦值 this.form.b = 'desc' , 雖然打印出來的值是改變了的,但是視圖並沒有更新。需要用Vue.set(object, key, value) 【或 this.$set(object,key,value)】 方法將響應屬性添加到嵌套的對象上。注意:object 必須是在data中已經聲明的對象。
...... <section> <p>動態添加嵌套屬性1:</p> <p>a的值{{form.a}}</p> <p>b的值{{form.b}}</p> <el-button @click="changeA">改變A</el-button> <el-button @click="changeB">改變B</el-button> </section>
....... export default { name: "layout", data(){ return { form:{ a:''//初始化 } } }, methods:{ changeA(){ this.form.a = 1 }, changeB(){
//this.form.b = 'desc' //無效 this.$set(this.form,'b','desc')//動態添加
//或者 Vue.set(vm.form,'b','desc') } } } </script>
例子二:Vue.set(object,key,value)方法一次只能添加一個屬性,如果需要向嵌套對象上添加多個屬性,可以用Object.assign方法。object.assign方法用於將所有可枚舉屬性的值從一個或多個源對象復制到目標對象,並返回目標對象。
vm.object = Object.assign( { } , vm.object , {a:' 1 ', b:' 2 ' }) 注:object必須是已經聲明的對象
...... <section> <p>object.assign方法</p> <p>{{form3.f1}}</p> <p>{{form3.f2}}</p> <el-button @click="changeForm3">添加多個屬性</el-button> </section> ...... export default { name: "layout", data(){ return { form3:{} } }, methods:{ changeForm3(){ this.form3 = Object.assign({},this.form3,{f1:'f1',f2:'f2'}) } } }
數組渲染問題
通過改動兩種方式改動數組時,Vue檢測不到變動:1.利用索引直接設置一個項;2.修改數組長度。
例子三:利用索引直接設置一個項,不能直接觸發狀態更新。
<p v-for="(item,index) in trees" @click="changeMe(index)">這個是{{item}}</p> export default { name: "layout", data(){ return { trees:['a','b','c'] } }, methods:{ changeMe(idx){ //this.trees[idx] = 'x'//無響應 this.$set(this.trees,idx,'x')//有響應
//this.trees.splice(idx,1,'x')//有響應
}
} }
例子四:改變數組長度
<p v-for="(item,index) in trees">這個是{{item}}</p> <el-button @click="changeLength">改變長度</el-button> export default { name: "layout", data(){ return { trees:['a','b','c'] } }, methods:{ changeLength(){ //this.trees.length = 2//無響應 this.trees.splice(2)//有響應 } } }