Vue.js-05:第五章 - 計算屬性與監聽器
一、前言
在 Vue 中,我們可以很方便的將資料使用插值表示式( Mustache 語法)的方式渲染到頁面元素中,但是插值表示式的設計初衷是用於簡單運算,即我們不應該對差值做過多的操作。當我們需要對差值做進一步的處理時,這時,我們就應該使用到 Vue 中的計算屬性來完成這一操作。同時,當差值資料變化時執行非同步或開銷較大的操作時,我們可以通過採用監聽器的方式來達到我們的目的。
學習系列目錄地址:https://www.cnblogs.com/danvic712/p/9549100.html
倉儲地址:https://github.com/Lanesra712/VueTrial/blob/master/Chapter01-Rookie/watcher.html
二、乾貨合集
1、計算屬性
計算屬性,一般是用來描述一個屬性值依賴於另一個的屬性值,當我們使用插值表示式將計算屬性繫結到頁面元素上時,計算屬性會在依賴的屬性值的變化時自動的更新 DOM 元素。例如在下面的程式碼中,我們在 computed 中,定義了一個 reversedMessage 屬性,它可以根據我們的 data 中的 message 屬性的變化自動的獲取到反轉後的 message 的屬性值。
<div id="app"> 輸入的值:<input type="text" v-model="message"><br/> 反轉的值:{{reversedMessage}} </div> <script> var vm = new Vue({ el: '#app', data: { message: '' }, computed: { reversedMessage: function () { //這裡的 this 指向 當前的 vm 例項 return this.message.split('').reverse().join('') } }, methods: {} }) </script>
可能你會發覺,這裡的寫法和我們定義方法時很相似,我們完全也可以在 methods 中定義一個方法來實現這個需求。原來,計算屬性的本質就是一個方法,只不過,我們在使用計算屬性的時候,是把計算屬性的名稱直接當做屬性來使用,而並不會把計算屬性當做一個方法去呼叫。
那麼,為什麼我們還要去使用計算屬性而不是去定義一個方法呢?原來,計算屬性是基於它們的依賴進行快取的。即只有在相關依賴發生改變時它們才會重新求值。例如在上面的例子中,只要 message 的屬性值沒有發生改變,無論任何使用我們使用到 reversedMessage 屬性,都會立即返回之前的計算結果,而不必再次執行函式。
反之,如果你使用方法的形式實現,當你使用到 reversedMessage 方法時,無論 message 屬性是否發生了改變,方法都會重新執行一次,這無形中增加了系統的開銷。當然,你也可以自己在方法中實現根據依賴進行快取,嗯,如果你不嫌煩的話。。。
在上面的案例中,對於 reversedMessage 這個計算屬性來說,我們主要的目的是為了獲取屬性的值,即使用的是計算屬性的 getter 方法。不過,如果你需要使用到計算屬性的 setter 方法時,我們也是可以為計算屬性提供一個 setter 方法的。
<div id="app"> 輸入的值:<input type="text" v-model="message"><br /> 反轉的值:{{reversedMessage}} </div> <script> var vm = new Vue({ el: '#app', data: { message: '' }, computed: { reversedMessage: { get: function () { return this.message.split('').reverse().join('') }, set: function (value) { this.message = value.split('').reverse().join('') } } }, methods: {} }) </script>
在上面的程式碼中,我們為計算屬性 reversedMessage 增加了一個 setter 方法:通過設定 reversedMessage 的值,同樣進行反轉操作,並最終將結果賦值給屬性 message。
2、監聽屬性
在 vue 中,我們不光可以使用計算屬性的方式來監聽資料的變化,還可以使用 watch 監聽器的方法來監測某個資料發生的變化。不同的是,計算屬性僅僅是對於依賴資料的變化後進行的資料操作,而 watch 更加側重於對於監測中的某個資料發生變化後所執行的一系列的業務邏輯操作。
監聽器以 key-value 的形式定義,key 是一個字串,它是需要被監測的物件,而 value 則可以是字串(方法的名稱)、函式(可以獲取到監聽物件改變前的值以及更新後的值)或是一個物件(物件內可以包含回撥函式的其它選項,例如是否初始化時執行監聽 immediate,或是是否執行深度遍歷 deep,即是否對物件內部的屬性進行監聽)。
1)回撥值為函式方法
在下面的例子中,我們監聽了 message 屬性的變化,根據屬性的變化後執行了回撥方法,打印出了屬性變化前後的值。
<div id="app"> 輸入的值:<input type="text" v-model="message"> </div> <script> var vm = new Vue({ el: '#app', data: { message: '' }, computed: {}, watch: { //回撥為未建立的方法 'message': function (newValue, oldValue) { console.log(`新值:${newValue} --------- 舊值:${oldValue}`) } }, methods: {} }) </script>
同樣的,我們可以通過方法名稱指明回撥為已經定義好的方法。
<div id="app"> 輸入的值:<input type="text" v-model="message"> </div> <script> var vm = new Vue({ el: '#app', data: { message: '' }, computed: {}, watch: { //回撥為已建立好的方法 'message': 'recording' }, methods: { recording: function (newValue, oldValue) { console.log(`method記錄:新值:${newValue} --------- 舊值:${oldValue}`) } } }) </script>
2)回撥值為物件
當我們監聽的回撥值為一個物件時,我們不僅可以設定回撥函式,還可以設定一些回撥的屬性。例如,在下面的例子中,我們監聽了 User 這個物件,同時執行了執行深度遍歷,這時,當我們監聽到 User.name 這個屬性發生改變的時候,我們就可以執行我們的回撥函式。注意,深度遍歷預設為 false,當不啟用深度遍歷時,我們是無法監聽到物件的內部屬性的變化的。
<div id="app"> 使用者姓名:<input type="text" v-model="User.name"> </div> <script> var vm = new Vue({ el: '#app', data: { message: '', User: { name: 'zhangsan', gender: 'male' } }, computed: {}, watch: { //回撥為物件 'User': { handler: function (newValue, oldValue) { console.log(`物件記錄:新值:${newValue.name} --------- 舊值:${oldValue.name}`) }, deep: true } }, methods: {} }) </script>
可能你發現了,為什麼 newValue 與 oldValue 都是一樣的啊?原來,當我們監聽的資料為物件或陣列時,newValue 和 oldValue 是相等的,因為物件和陣列都為引用型別,這兩個的形參指向的也是同一個資料物件。同時,如果我們不啟用深度遍歷,我們將無法監聽到對於 User 物件中 name 屬性的變化。
<div id="app"> 使用者姓名:<input type="text" v-model="User.name"> </div> <script> var vm = new Vue({ el: '#app', data: { message: '', User: { name: 'zhangsan', gender: 'male' } }, computed: {}, watch: { //回撥為物件 'User': { handler: function (newValue, oldValue) { console.log(`物件記錄:新值:${newValue.name} --------- 舊值:${oldValue.name}`) }, deep: false } }, methods: {} }) </script>
三、總結
1、計算屬性的結果會被快取起來,只有依賴的屬性發生變化時才會重新計算,必須返回一個數據,主要用來進行純資料的操作。
2、監聽器主要用來監聽某個資料的變化,從而去執行某些具體的回撥業務邏輯,不僅僅侷限於返回資料。