一起學Vue之計算屬性和偵聽器

来源:https://www.cnblogs.com/hsiang/archive/2019/12/11/12020120.html
-Advertisement-
Play Games

在Vue開發中,模板內的表達式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。當你想要在模板中多次引用相同表達式時,就會更加難以處理。所以,對於任何複雜邏輯,你都應當使用計算屬性。本文主要講解Vue中的計算屬性和偵聽器,僅供學習分享使用,如有不足之前,還請... ...


概述

在Vue開發中,模板內的表達式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。當你想要在模板中多次引用相同表達式時,就會更加難以處理。所以,對於任何複雜邏輯,你都應當使用計算屬性。本文主要講解Vue中的計算屬性和偵聽器,僅供學習分享使用,如有不足之前,還請指正。

計算屬性

計算屬性步驟:

1. 在computed屬性中增加reverseMsg方法,如下所示:

 1 <script type="text/javascript">
 2     var vm = new Vue({
 3         el: '#app',
 4         data: {
 5             msg: 'welcome to vue world!!!'
 6 
 7         },
 8         computed: {
 9             reverseMsg: function() {
10                 // `this` 指向 vm 實例
11                 return this.msg.split('').reverse().join('');
12             }
13         }
14                 
15     });
16 </script>

2. 在Html中進行引用,你可以像綁定普通屬性一樣在模板中綁定計算屬性。

Vue 知道 vm.reverseMsg 依賴於 vm.msg,因此當 vm.msg 發生改變時,所有依賴 vm.reverseMsg 的綁定也會更新。如下所示:

1 <p>原始信息: {{ msg }}</p>
2 <p>計算屬性反轉信息: {{ reverseMsg }}</p>

採用表達式的方式 ,則是如下所示:

1 <span>{{ msg.split('').reverse().join('') }}</span>

在這個地方,模板不再是簡單的聲明式邏輯。你必須看一段時間才能意識到,這裡是想要顯示變數 msg 的翻轉字元串。此處對比一下,採用計算屬性的方式,則更加簡潔明瞭。

計算屬性緩存 vs 方法

你可能已經註意到我們可以通過在表達式中調用方法來達到同樣的效果,我們可以將同一函數定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同的。

如下所示,聲明一個方法:

 1 <script type="text/javascript">
 2     var vm = new Vue({
 3         el: '#app',
 4         data: {
 5             msg: 'welcome to vue world!!!'
 6         },
 7         methods: {
 8             reversedMsg: function() {
 9                 return this.msg.split('').reverse().join('');
10             }
11         }
12 
13     });
14 </script>

在Html中進行引用,如下所示:

1 <p>Reversed message: "{{ reversedMsg() }}"</p>

差異:不同的是計算屬性是基於它們的響應式依賴進行緩存的。 只在相關響應式依賴發生改變時它們才會重新求值。 這就意味著只要 msg 還沒有發生改變,多次訪問 reversedMsg計算屬性會立即返回之前的計算結果,而不必再次執行函數。 即:計算屬性只有當依賴屬性發生改變時,才重新計算,而函數需要每次都重新計算。
也同樣意味著下麵的計算屬性將不再更新,因為 Date.now() 不是響應式依賴:  相比之下,每當觸發重新渲染時,調用方法將總會再次執行函數。 

 1 <script type="text/javascript">
 2     var vm = new Vue({
 3         el: '#app',
 4         data: {
 5             msg: 'welcome to vue world!!!'
 6 
 7         },
 8         computed: {
 9             now: function() {
10                 return Date.now().toString();
11             }
12 
13         });
14 </script>

如下所示,將不會隨著時間的改變而觸發。

1 <p>{{now}}</p>

如果你不希望有緩存,請用方法來替代。

計算屬性 vs 偵聽屬性

如下所示:有兩個data屬性,firstName和lastName,fullName依賴說前兩個變化而變化。如果需要採用偵聽屬性,需要對firstName和lastName進行偵聽。

 1 <script type="text/javascript">
 2     var vm = new Vue({
 3         el: '#app',
 4         data: {
 5             firstName: 'Foo',
 6             lastName: 'Bar',
 7             fullName: 'Foo Bar',
 8         },
10         computed: {
11             fullName2: function() {
12                 return this.firstName + ' ' + this.lastName;
13             }
15         },
16         watch: {
17             firstName: function(val) {
18                 this.fullName = val + ' ' + this.lastName;
19             },
20             lastName: function(val) {
21                 this.fullName = this.firstName + ' ' + val;
22             }
24         }
26     });
27 </script>

上面代碼是命令式且重覆的。將它與計算屬性的版本進行比較。

1 <div id="demo">{{ fullName }}</div>
2 <div id="demo">{{ fullName2 }}</div>

如上所示:fullName採用偵聽屬性,fullName2採用計算屬性,對比一下,好得多了,不是嗎?

計算屬性的 setter

計算屬性預設只有 getter ,不過在需要時你也可以提供一個 setter :如下所示:

 1 fullName3: {
 2     //getter
 3     get: function() {
 4         return this.firstName + ' ' + this.lastName;
 5     },
 6     //setter
 7     set: function(newValue) {
 8         console.log('newValue=' + newValue);
 9         var names = newValue.split(' ');
10         this.firstName = names[0];
11         this.lastName = names[names.length - 1];
12     }
13 }

在UI中引用的方式是一樣的。當fullName3的值發生改變時,將更新firstName和lastName。

1 <p>{{fullName3}}</p>

偵聽器

雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。這就是為什麼 Vue 通過 watch 選項提供了一個更通用的方法,來響應數據的變化。當需要在數據變化時執行非同步或開銷較大的操作時,這個方式是最有用的。如下所示:

 1 <script type="text/javascript">
 2     var vm = new Vue({
 3         el: '#app',
 4         data: {
 5             question: '',
 6             answer: 'I cannot give you an answer until you ask a question!'
 7 
 8         },
 9         watch: {
10             // 如果 `question` 發生改變,這個函數就會運行
11             question: function(newQuestion, oldQuestion) {
12                 if (newQuestion == '') {
13                     this.answer = 'Waiting for you to stop typing...';
14                 } else {
15                     this.answer = '請回答';
16                 }
17             }
18         }
19     });
20 </script>

在頁面中綁定屬性

1 <p>Ask a yes/no question:
2     <input v-model="question">
3 </p>
4 <p>{{ answer }}</p>

在這個示例中,使用 watch 選項允許我們執行非同步操作 (訪問一個 API),限制我們執行該操作的頻率,併在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。

在本示例中用的全部代碼 ,如下所示:

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="utf-8">
  5         <title>一起學Vue之計算屬性和偵聽器</title>
  6         <!-- 開發環境版本,包含了有幫助的命令行警告 -->
  7         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  8     </head>
  9     <body>
 10         <div id="app">
 11             <span>{{msg}}</span>
 12             <h2>計算屬性</h2>
 13             <!-- 
 14              模板內的表達式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。例如:
 15              -->
 16             <br />
 17             <span>
 18                 {{ msg.split('').reverse().join('') }}
 19             </span>
 20             <!-- 
 21             在這個地方,模板不再是簡單的聲明式邏輯。你必須看一段時間才能意識到,這裡是想要顯示變數 msg 的翻轉字元串。
 22             當你想要在模板中多次引用此處的翻轉字元串時,就會更加難以處理。
 23             所以,對於任何複雜邏輯,你都應當使用計算屬性
 24              -->
 25             <p>原始信息: {{ msg }}</p>
 26             <p>計算屬性反轉信息: {{ reverseMsg }}</p>
 27             <!-- 
 28             這裡我們聲明瞭一個計算屬性 reverseMsg。我們提供的函數將用作屬性 vm.reverseMsg 的 getter 函數: 
 29              -->
 30             <!-- 
 31              你可以像綁定普通屬性一樣在模板中綁定計算屬性。Vue 知道 vm.reverseMsg 依賴於 vm.msg,
 32              因此當 vm.msg 發生改變時,所有依賴 vm.reverseMsg 的綁定也會更新。
 33               -->
 34             <h2>計算屬性緩存 vs 方法</h2>
 35             <p>Reversed message: "{{ reversedMsg() }}"</p>
 36             <!-- 
 37             你可能已經註意到我們可以通過在表達式中調用方法來達到同樣的效果: 
 38             -->
 39             <!-- 
 40             我們可以將同一函數定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同的。
 41             然而,不同的是計算屬性是基於它們的響應式依賴進行緩存的。 
 42             只在相關響應式依賴發生改變時它們才會重新求值。
 43             這就意味著只要 msg 還沒有發生改變,多次訪問 reversedMsg 計算屬性會立即返回之前的計算結果,而不必再次執行函數。
 44             即:計算屬性只有當依賴屬性發生改變時,才重新計算,而函數需要每次都重新計算。
 45              -->
 46             <!-- 
 47             也同樣意味著下麵的計算屬性將不再更新,因為 Date.now() 不是響應式依賴: 
 48             相比之下,每當觸發重新渲染時,調用方法將總會再次執行函數。
 49             如果你不希望有緩存,請用方法來替代
 50              -->
 51             <p>{{now}}</p>
 52             <h2>計算屬性 vs 偵聽屬性</h2>
 53             <div id="demo">{{ fullName }}</div>
 54             <!-- 
 55              上面代碼是命令式且重覆的。將它與計算屬性的版本進行比較:
 56              -->
 57             <div id="demo">{{ fullName2 }}</div>
 58             <!-- 
 59              好得多了,不是嗎?
 60              -->
 61             <h2>計算屬性的 setter</h2>
 62             <!-- 
 63              計算屬性預設只有 getter ,不過在需要時你也可以提供一個 setter :
 64              -->
 65             <p>{{fullName3}}</p>
 66             <h2>偵聽器</h2>
 67             <!-- 
 68              雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。
 69              這就是為什麼 Vue 通過 watch 選項提供了一個更通用的方法,來響應數據的變化。
 70              當需要在數據變化時執行非同步或開銷較大的操作時,這個方式是最有用的。
 71              -->
 72             <p>Ask a yes/no question:
 73                 <input v-model="question">
 74             </p>
 75             <p>{{ answer }}</p>
 76             <!-- 
 77              在這個示例中,使用 watch 選項允許我們執行非同步操作 (訪問一個 API),
 78              限制我們執行該操作的頻率,併在我們得到最終結果前,設置中間狀態。
 79              這些都是計算屬性無法做到的。
 80              -->
 81         </div>
 82         <script type="text/javascript">
 83             var vm = new Vue({
 84                 el: '#app',
 85                 data: {
 86                     msg: 'welcome to vue world!!!',
 87                     firstName: 'Foo',
 88                     lastName: 'Bar',
 89                     fullName: 'Foo Bar',
 90                     question: '',
 91                     answer: 'I cannot give you an answer until you ask a question!'
 92 
 93 
 94                 },
 95                 methods: {
 96                     reversedMsg: function() {
 97                         return this.msg.split('').reverse().join('')
 98                     }
 99                 },
100                 computed: {
101                     reverseMsg: function() {
102                         // `this` 指向 vm 實例
103                         return this.msg.split('').reverse().join('');
104                     },
105                     now: function() {
106                         return Date.now().toString();
107                     },
108                     fullName2: function() {
109                         return this.firstName + ' ' + this.lastName;
110                     },
111                     fullName3: {
112                         //getter
113                         get: function() {
114                             return this.firstName + ' ' + this.lastName;
115                         },
116                         //setter
117                         set: function(newValue) {
118                             console.log('newValue=' + newValue);
119                             var names = newValue.split(' ');
120                             this.firstName = names[0];
121                             this.lastName = names[names.length - 1];
122                         }
123                     }
124                 },
125                 watch: {
126                     firstName: function(val) {
127                         this.fullName = val + ' ' + this.lastName;
128                     },
129                     lastName: function(val) {
130                         this.fullName = this.firstName + ' ' + val;
131                     },
132                     // 如果 `question` 發生改變,這個函數就會運行
133                     question: function(newQuestion, oldQuestion) {
134                         if (newQuestion == '') {
135                             this.answer = 'Waiting for you to stop typing...';
136                         } else {
137                             this.answer = '請回答';
138                         }
139                     }
140 
141                 }
142 
143             });
144         </script>
145     </body>
146 </html>
View Code

備註

暴虎馮河,死而無悔者,吾不與也;必也,臨事而懼,好謀而成者也。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 Hello我又來了,快年底了,作為一個有抱負的碼農,我想給自己攢一個年終總結。自上上篇寫了手動搭建Redis集群和MySQL主從同步(非Docker)和上篇寫了動手實現MySQL讀寫分離and故障轉移之後,索性這次把資料庫中最核心的也是最難搞懂的內容,也就是索引,分享給大家。 這篇博客我會談談 ...
  • ###第一周:R基礎 rm(list = ls()) #ctr+L###矩陣相乘,函數diag()a=matrix(1:12,nrow=3,ncol=4)b=matrix(1:12,nrow=4,ncol=3)a%*%ba=matrix(1:16,nrow=4,ncol=4)diag(a)#返回對角 ...
  • ORACLE資料庫中,我們會使用一些SQL語句找出存在隱式轉換的問題SQL,其中網上流傳的一個SQL語句如下,查詢V$SQL_PLAN的欄位FILTER_PREDICATES中是否存在INTERNAL_FUNCTION: SELECT SQL_ID, PLAN_HASH_VALUEFROM V$SQ... ...
  • 在安裝neo4j之前,需要安裝Java JRE,並配置Java開發環境,然後安裝neo4j服務。 一、CentOS下安裝 1.下載Neo4j 去官網下載最新的neo4j,選擇社區版。地址:https://neo4j.com/download/other-releases/#releases 將本地下 ...
  • Frida介面功能介紹 Frida是個so級別的hook框架,它可以幫助開發、安全人員對指定的進程的so模塊進行分析。它主要提供了功能簡單的Python介面和功能豐富的JS介面,使得hook函數和修改so可以編程化,介面中包含了主控端與目標進程的交互介面。 目標進程的交互介面分為: JS介面 功能包 ...
  • 13. 高效繪圖 高效繪圖 不必要的效率考慮往往是性能問題的萬惡之源。 ——William Allan Wulf 在第12章『速度的曲率』我們學習如何用Instruments來診斷Core Animation性能問題。在構建一個iOS app的時候會遇到很多潛在的性能陷阱,但是在本章我們將著眼於有關 ...
  • Frida是什麼 我覺得官網已經說得很清楚了。簡單的說就是一款動態代碼檢測工具,可用於各種主流操作系統,這裡主要討論的是動態檢測Android系統裡面代碼運行情況。 Android版的Frida環境的搭建主要分為兩個部分,一部分是運行在Android機器上的代理工具 ,另一部分是Windows系統用 ...
  • 本來之前覺得Android項目優化系列的文章基本整理完畢了,但是近期看了一下《阿裡Android開發手冊》有了很多收穫,想再整理一篇,下麵就開始吧。 先在這裡列一下之前整理的文章及鏈接: Android 項目優化(一):項目代碼規範優化 Android 項目優化(二):啟動頁面優化 Android ...
一周排行
    -Advertisement-
    Play Games
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...