[1]data [2]computed [3]methods [4]watch ...
前面的話
一般地,當模板內容較簡單時,使用data選項配合表達式即可。涉及到複雜邏輯時,則需要用到methods、computed、watch等方法。本文將詳細介紹Vue實例對象的數據選項
data
data是Vue實例的數據對象。Vue將會遞歸將data的屬性轉換為getter/setter,從而讓data屬性能響應數據變化
[註意]不應該對data
屬性使用箭頭函數
<div id="app"> {{ message }} </div>
<script> var values = {message: 'Hello Vue!'} var vm = new Vue({ el: '#app', data: values }) console.log(vm); </script>
Vue實例創建之後,可以通過vm.$data
訪問原始數據對象
console.log(vm.$data);
Vue實例也代理了data對象上所有的屬性
<script> var values = {message: 'Hello Vue!'} var vm = new Vue({ el: '#app', data: values }) console.log(vm.$data === values);//true console.log(vm.message);//'Hello Vue!' console.log(vm.$data.message);//'Hello Vue!' </script>
被代理的屬性是響應的,也就是說值的任何改變都是觸發視圖的重新渲染。設置屬性也會影響到原始數據,反之亦然
但是,以_
或$
開頭的屬性不會被Vue實例代理,因為它們可能和Vue內置的屬性或方法衝突。可以使用例如vm.$data._property
的方式訪問這些屬性
<script> var values = { message: 'Hello Vue!', _name: '小火柴' } var vm = new Vue({ el: '#app', data: values }) console.log(vm._name);//undefined console.log(vm.$data._name);//'小火柴' </script>
computed
計算屬性函數computed將被混入到Vue實例中。所有getter和setter的this上下文自動地綁定為Vue實例
[註意]不應該使用箭頭函數來定義計算屬性函數
下麵是關於computed的一個例子
<div id="example"> <p>原始字元串: "{{ message }}"</p> <p>反向字元串: "{{ reversedMessage }}"</p> </div>
<script> var vm = new Vue({ el: '#example', data: { message: '小火柴' }, computed: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script>
結果如下
這裡聲明瞭一個計算屬性 reversedMessage
。提供的函數將用作屬性 vm.reversedMessage
的 getter
console.log(vm.reversedMessage) // -> '柴火小' vm.message = 'Goodbye' console.log(vm.reversedMessage) // -> 'eybdooG'
vm.reversedMessage
的值始終取決於 vm.message
的值。可以像綁定普通屬性一樣在模板中綁定計算屬性。當 vm.message
發生改變時,所有依賴於 vm.reversedMessage
的綁定也會更新
結果如下圖所示,vm.reversedMessage依賴於vm.message的值,vm.reversedMessage本身並不能被賦值
【setter】
計算屬性預設只有 getter ,不過在需要時也可以提供一個 setter
<script> var vm = new Vue({ data: { a: 1 }, computed: { // 僅讀取,值只須為函數 aDouble: function () { return this.a * 2 }, // 讀取和設置 aPlus: { get: function () { return this.a + 1 }, set: function (v) { this.a = v - 1 } } } }) console.log(vm.aPlus);//2 vm.aPlus = 3 console.log(vm.a);//2 console.log(vm.aDouble);//4 </script>
methods
通過調用表達式中的 methods 也可以達到同樣的效果
[註意]不應該使用箭頭函數來定義methods函數
<div id="example"> <p>原始字元串: "{{ message }}"</p> <p>反向字元串: "{{ reversedMessage() }}"</p> </div>
<script> var vm = new Vue({ el: '#example', data: { message: '小火柴' }, methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script>
【緩存】
對於最終的結果,兩種方式確實是相同的
然而,不同的是計算屬性是基於它們的依賴進行緩存的。計算屬性只有在它的相關依賴發生改變時才會重新求值。這就意味著只要 message
還沒有發生改變,多次訪問 reversedMessage
計算屬性會立即返回之前的計算結果,而不必再次執行函數
相比而言,只要發生重新渲染,method 調用總會執行該函數。如下所示
<div id="example"> <p>計算屬性: "{{ time1 }}"</p> <p>methods方法: "{{ time2() }}"</p> </div>
<script> var vm = new Vue({ el: '#example', computed:{ time1: function () { return (new Date()).toLocaleTimeString() } }, methods: { time2: function () { return (new Date()).toLocaleTimeString() } } }) </script>
假設有一個性能開銷比較大的的計算屬性A,它需要遍歷一個極大的數組和做大量的計算。可能有其他的計算屬性依賴於 A 。如果沒有緩存,將不可避免的多次執行A的getter!如果不希望有緩存,則用 method 替代
watch
Vue提供了一種通用的方式來觀察和響應Vue實例上的數據變動:watch屬性。watch屬性是一個對象,鍵是需要觀察的表達式,值是對應回調函數,回調函數得到的參數為新值和舊值。值也可以是方法名,或者包含選項的對象。Vue實例將會在實例化時調用$watch()
,遍歷watch對象的每一個屬性
[註意]不應該使用箭頭函數來定義 watch 函數
<div id="app"> <button @click="a++">a加1</button> <p>{{ message }}</p> </div>
<script> var vm = new Vue({ el: '#app', data: { a: 1, message:'' }, watch: { a: function (val, oldVal) { this.message = 'a的舊值為' + oldVal + ',新值為' + val; } } }) </script>
上面代碼中,當a的值發生變化時, 通過watch的監控,使message輸出相應的內容
【$watch】
除了使用數據選項中的watch方法以外,還可以使用實例對象的$watch方法, 該方法的返回值是一個取消觀察函數,用來停止觸發回調
<div id="app"> <button @click="a++">a加1</button> <p>{{ message }}</p> </div>
<script> var vm = new Vue({ el: '#app', data: { a: 1, message:'' } }) var unwatch = vm.$watch('a',function(val, oldVal){ if(val === 10){ unwatch(); } this.message = 'a的舊值為' + oldVal + ',新值為' + val; }) </script>
上面的代碼中,當a的值更新到10時,觸發unwatch(),來取消觀察。點擊按鈕時,a的值仍然會變化,但是不再觸發watch的回調函數