成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解Vue中的Computed和Watch

開發 前端
作為一名Vue開發者,雖然在項目中頻繁使用過computed和watch,但從來沒有系統的學習過,總覺著對這兩個知識點有些一知半解。

[[376061]]

本文轉載自微信公眾號「不知名寶藏程序媛  」,作者小土豆 。轉載本文請聯系不知名寶藏程序媛  公眾號。  

 1. 前言

作為一名Vue開發者,雖然在項目中頻繁使用過computed和watch,但從來沒有系統的學習過,總覺著對這兩個知識點有些一知半解。

如果你也和我一樣,就一起來回顧和總結一下這兩個知識點吧。

本篇非源碼分析,只是從兩者各自的用法、特性等做一些梳理。

2. Vue中的computed

Vue中的computed又叫做計算屬性,Vue官網中給了下面這樣一個示例。

模板中有一個message數據需要展示:

  1. <template> 
  2.   <div id="app"
  3.     {{message}} 
  4.   </div> 
  5. </template> 
  6. <script> 
  7. export default { 
  8.   name'App'
  9.   data() { 
  10.     return { 
  11.       message: 'Hello' 
  12.     } 
  13.   } 
  14. </script> 

假如此時有一個需求:對message進行反轉并展示到模板中。

那最簡單的實現方式就是直接在模板中做這樣的轉化:

  1. <template> 
  2.   <div id="app"
  3.     <p>{{message}}</p> 
  4.     <p>{{message.split('').reverse().join('')}}</p> 
  5.   </div> 
  6. </template> 

那這個時候,Vue官方告訴我們:過多的邏輯運算會讓模板變得重且難以維護,而且這種轉化無法復用,并指導我們使用計算屬性-computed來實現這個需求。

  1. export default { 
  2.   name'App'
  3.   computed: { 
  4.     reverseMessage: function(){ 
  5.       return this.message.split('').reverse().join(''); 
  6.     } 
  7.   }, 
  8.   data() { 
  9.     return { 
  10.       message: 'Hello' 
  11.     } 
  12.   } 

在以上代碼中我們定義了一個計算屬性:reverseMessage,其值為一個函數并返回我們需要的結果。

之后在模板中就可以像使用message一樣使用reverseMessage。

  1. <template> 
  2.   <div id="app"
  3.     <p>{{message}}</p> 
  4.     <p>{{reverseMessage}}</p> 
  5.   </div> 
  6. </template> 

那么此時有人肯定要說了,我用methods也能實現呀。確實使用methods也能實現此種需求,但是在這種情況下我們的計算屬性相較于methods是有很大優勢的,這個優勢就是計算屬性存在緩存。

如果我們使用methods實現前面的需求,當message的反轉結果有多個地方在使用,對應的methods函數會被調用多次,函數內部的邏輯也需要執行多次;而計算屬性因為存在緩存,只要message數據未發生變化,則多次訪問計算屬性對應的函數只會執行一次。

  1. <template> 
  2.   <div id="app"
  3.     <p>{{message}}</p> 
  4.     <p>第一次訪問reverseMessage:{{reverseMessage}}</p> 
  5.     <p>第二次訪問reverseMessage:{{reverseMessage}}</p> 
  6.     <p>第三次訪問reverseMessage:{{reverseMessage}}</p> 
  7.     <p>第四次訪問reverseMessage:{{reverseMessage}}</p> 
  8.   </div> 
  9. </template> 
  10.  
  11. <script> 
  12. export default { 
  13.   name'App'
  14.   computed: { 
  15.     reverseMessage: function(value){ 
  16.       console.log(" I'm reverseMessage" ) 
  17.       return this.message.split('').reverse().join(''); 
  18.     } 
  19.   }, 
  20.   data() { 
  21.     return { 
  22.       message: 'Hello' 
  23.     } 
  24.   } 
  25. </script> 

運行項目,查看結果,會發現計算屬性reverseMessage對應的函數只執行了一次。

圖片

 

3. Vue中的watchVue

中的watch又名為偵聽屬性,它主要用于偵聽數據的變化,在數據發生變化的時候執行一些操作。

  1. <template> 
  2.   <div id="app"
  3.     <p>計數器:{{counter}}</p> 
  4.     <el-button type="primary" @click="counter++"
  5.       Click 
  6.     </el-button> 
  7.   </div> 
  8. </template> 
  9.  
  10. <script> 
  11. export default { 
  12.   name'App'
  13.   data() { 
  14.     return { 
  15.       counter: 0 
  16.     } 
  17.   }, 
  18.   watch: { 
  19.     /** 
  20.      * @name: counter 
  21.      * @description:  
  22.      *   監聽Vue data中的counter數據 
  23.      *   當counter發生變化時會執行對應的偵聽函數 
  24.      * @param {*} newValue counter的新值 
  25.      * @param {*} oldValue counter的舊值 
  26.      * @return {*} None 
  27.      */ 
  28.     counter: function(newValue, oldValue){ 
  29.       if(this.counter == 10){ 
  30.         this.counter = 0; 
  31.       } 
  32.     } 
  33.   } 
  34. </script> 

我們定義了一個偵聽屬性counter,該屬性偵聽的是Vue data中定義counter數據,整個的邏輯就是點擊按鈕counter加1,當counter等于10的時候,將counter置為0。

上面的代碼運行后的結果如下:

 

圖片

 

Vue官網很明確的建議我們這樣使用watch偵聽屬性:當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。

4. computed和watch之間的抉擇

看完以上兩部分內容,關于Vue中computed和watch的基本用法算是掌握了。但實際上不止這些,所以接下來我們在來進階學習一波。

這里我們還原Vue官網中的一個示例,示例實現的功能大致如下:

 

圖片

 

該功能可以簡單的描述為:在firstName和lastName數據發生變化時,對fullName進行更新,其中fullName的值為firstName和lastName的拼接。

首先我們使用watch來實現該功能:watch偵聽firstName和lastName,當這兩個數據發生變化時更新fullName的值。

  1. <template> 
  2.   <div id="app"
  3.     <p>firstName: <el-input v-model="firstName" placeholder="請輸入firstName"></el-input></p> 
  4.     <p>lastName: <el-input v-model="lastName" placeholder="請輸入lastName"></el-input></p> 
  5.     <p>fullName: {{fullName}}</p> 
  6.   </div> 
  7. </template> 
  8.  
  9. <script> 
  10. export default { 
  11.   name'App'
  12.   data() { 
  13.     return { 
  14.       firstName: ''
  15.       lastName: ''
  16.       fullName: '(空)' 
  17.     } 
  18.   }, 
  19.   // 使用watch實現 
  20.   watch: { 
  21.     firstName: function(newValue) { 
  22.       this.fullName = newValue + ' ' + this.lastName; 
  23.     }, 
  24.     lastName: function(newValue){ 
  25.       this.fullName = this.firstName + ' ' + newValue; 
  26.     } 
  27.   } 
  28. </script> 

接著我們在使用computed來實現:定義計算屬性fullName,將firstName和lastName的值進行拼接并返回。

  1. <template> 
  2.   <div id="app"
  3.     <p>firstName: <el-input v-model="firstName" placeholder="請輸入firstName"></el-input></p> 
  4.     <p>lastName: <el-input v-model="lastName" placeholder="請輸入lastName"></el-input></p> 
  5.     <p>fullName: {{fullName}}</p> 
  6.   </div> 
  7. </template> 
  8.  
  9. <script> 
  10. export default { 
  11.   name'App'
  12.   data() { 
  13.     return { 
  14.       firstName: ''
  15.       lastName: '' 
  16.     } 
  17.   } 
  18.   computed: { 
  19.     fullName: function() { 
  20.       return this.firstName + ' ' + this.lastName; 
  21.     } 
  22.   }  
  23. </script> 

我們發現computed和watch都可以實現這個功能,但是我們在對比一下這兩種不同的實現方式:

  1. // 使用computed實現 
  2. computed: { 
  3.   fullName: function() { 
  4.     return this.firstName + ' ' + this.lastName; 
  5.   } 
  6. },  
  7. // 使用watch實現 
  8. watch: { 
  9.   firstName: function(newValue) { 
  10.     this.fullName = newValue + ' ' + this.lastName; 
  11.   }, 
  12.   lastName: function(newValue){ 
  13.     this.fullName = this.firstName + ' ' + newValue; 
  14.   } 

對比之下很明顯的會發現發現computed的實現方式更簡潔高級。

所以在日常項目開發中,對于computed和watch的使用要慎重選擇:

 

圖片

 

這兩者選擇和使用沒有對錯之分,只是希望能更好的使用,而不是濫用。

5. 計算屬性進階

接下來我們在對計算屬性的內容進行進階學習。

>>> 5.1 計算屬性不能和Vue Data屬性同名

在聲明計算屬性的時候,計算屬性是不能和Vue Data中定義的屬性同名,否則會出現錯誤:The computed property "xxxxx" is already defined in data。

如果有閱讀過Vue源碼的同學對這個原因應該會比較清楚,Vue在初始化的時候會按照:initProps-> initMethods -> initData -> initComputed -> initWatch這樣的順序對數據進行初始化,并且會通過Object.definedProperty將數據定義到vm實例上,在這個過程中同名的屬性會被后面的同名屬性覆蓋。

通過打印組件實例對象,可以很清楚的看到props、methods、data、computed會被定義到vm實例上。

>>> 5.2 計算屬性的set函數

在前面代碼示例中,我們的computed是這么實現的:

  1. computed: { 
  2.   reverseMessage: function(){ 
  3.     return this.message.split('').reverse().join(''); 
  4.   } 
  5. }, 

這種寫法實際上是給reverseMessage提供了一個get方法,所以上面的寫法等同于:

  1. computed: { 
  2.   reverseMessage: { 
  3.     // 計算屬性的get方法 
  4.     get: function(){ 
  5.       return this.message.split('').reverse().join(''); 
  6.     } 
  7.   } 
  8. }, 

除此之外,我們也可以給計算屬性提供一個set方法:

  1. computed: { 
  2.   reverseMessage: { 
  3.     // 計算屬性的get方法 
  4.     get: function(){ 
  5.       return this.message.split('').reverse().join(''); 
  6.     }, 
  7.     setfunction(newValue){ 
  8.        // set方法的邏輯 
  9.     } 
  10.   } 
  11. }, 

只有我們主動修改了計算屬性的值,set方法才會被觸發。

關于計算屬性的set方法在實際的項目開發中暫時還沒有遇到,不過經過一番思考,做出來下面這樣一個示例:

 

圖片

 

這個示例是分鐘和小時之間的一個轉化,利用計算屬性的set方法就能很好實現:

  1. <template> 
  2.   <div id="app"
  3.     <p>分鐘<el-input v-model="minute" placeholder="請輸入內容"></el-input></p> 
  4.     <p>小時<el-input v-model="hours" placeholder="請輸入內容"></el-input></p> 
  5.   </div> 
  6. </template> 
  7.  
  8. <script> 
  9. export default { 
  10.   name'App'
  11.   data() { 
  12.     return { 
  13.       minute: 60, 
  14.     } 
  15.   }, 
  16.   computed: { 
  17.     hours:{ 
  18.       get: function() { 
  19.         return this.minute / 60; 
  20.       }, 
  21.       setfunction(newValue) { 
  22.         this.minute = newValue * 60; 
  23.       } 
  24.     } 
  25.   }  
  26. </script> 

>>> 5.3 計算屬性的緩存

前面我們總結過計算屬性存在緩存,并演示相關的示例。那計算屬性的緩存是如何實現的呢?

關于計算屬性的緩存這個知識點需要我們去閱讀Vue的源碼實現,所以我們一起來看看源碼吧。

相信大家看到源碼這個詞就會有點膽戰心驚,不過不用過分擔心,文章寫到這里的時候考慮到本篇文章的內容和側重點,所以不會詳細去解讀計算屬性的源碼,著重學習計算屬性的緩存實現,并且點到為止。

那如果你沒有仔細解讀過Vue的響應式原理,那建議忽略這一節的內容,等對源碼中的響應式有一定了解之后在來看這一節的內容會更容易理解。(我自己之前也寫過的一篇相關文章:1W字長文+多圖,帶你了解vue2.x的雙向數據綁定源碼實現,點擊文末閱讀原文即可查看)

關于計算屬性的入口源代碼如下:

  1. /* 
  2. * Vue版本:v2.6.12 
  3. * 代碼位置:/vue/src/core/instance/state.js 
  4. */ 
  5. export function initState (vm: Component) { 
  6.   // ......省略...... 
  7.   const opts = vm.$options 
  8.   // ......省略...... 
  9.   if (opts.computed) initComputed(vm, opts.computed) 
  10.   // ......省略                                                                       ...... 

接著我們來看看initComputed:

  1. /* 
  2. * Vue版本:v2.6.12 
  3. * 代碼位置:/vue/src/core/instance/state.js 
  4. * @params: vm        vue實例對象 
  5. * @params: computed  所有的計算屬性 
  6. */ 
  7. function initComputed (vm: Component, computed: Object) { 
  8.   
  9.   /*  
  10.   * Object.create(null):創建一個空對象 
  11.   * 定義的const watchers是用于保存所有計算屬性的Watcher實例 
  12.   */ 
  13.   const watchers = vm._computedWatchers = Object.create(null
  14.   
  15.   // 遍歷計算屬性 
  16.   for (const key in computed) { 
  17.     const userDef = computed[key
  18.     /* 
  19.     * 獲取計算屬性的get方法  
  20.     * 計算屬性可以是function,默認提供的是get方法 
  21.     * 也可以是對象,分別聲明get、set方法 
  22.     */ 
  23.     const getter = typeof userDef === 'function' ? userDef : userDef.get 
  24.     
  25.     /*  
  26.     * 給計算屬性創建watcher 
  27.     * @params: vm       vue實例對象  
  28.     * @params: getter   計算屬性的get方法 
  29.     * @params: noop      
  30.           noop是定義在 /vue/src/shared/util.js中的一個函數 
  31.           export function noop (a?: any, b?: any, c?: any) {} 
  32.     * @params: computedWatcherOptions 
  33.     *     computedWatcherOptions是一個對象,定義在本文件的167行 
  34.     *     const computedWatcherOptions = { lazy: true } 
  35.     */ 
  36.     watchers[key] = new Watcher( 
  37.       vm, 
  38.       getter || noop, 
  39.       noop, 
  40.       computedWatcherOptions 
  41.     ) 
  42.     // 函數調用 
  43.     defineComputed(vm, key, userDef) 
  44.   } 

在initComputed這個函數中,主要是遍歷計算屬性,然后在遍歷的過程中做了下面兩件事:

  • 第一件:為計算屬性創建watcher,即new Watcher
  • 第二件:調用defineComputed方法

那首先我們先來看看new Watcher都做了什么。

為了方便大家看清楚new Watcher的作用,我將Watcher的源碼進行了簡化,保留了一些比較重要的代碼。

同時代碼中重要的部分都添加了注釋,有些注釋描述的可能有點重復或者啰嗦,但主要是想以這種重復的方式讓大家可以反復琢磨并理解源碼中的內容,方便后續的理解 ~

  1. /* 
  2. * Vue版本:v2.6.12 
  3. * 代碼位置: /vue/src/core/observer/watcher.js 
  4. * 為了看清楚Watcher的作用 
  5. * 將源碼進行簡化,所以下面是一個簡化版的Watcher類 
  6. * 同時部分代碼順序有所調整 
  7. */ 
  8. export default class Watcher { 
  9.   constructor ( 
  10.     vm: Component, 
  11.     expOrFn: string | Function
  12.     cb: Function
  13.     options?: ?Object, 
  14.   ) { 
  15.     // vm為組件實例 
  16.     this.vm = vm   
  17.     // expOrFn在new Watcher時傳遞的參數為計算屬性的get方法 
  18.     // 將計算屬性的get方法賦值給watcher的getter屬性 
  19.     this.getter = expOrFn 
  20.     // cb為noop:export function noop (a?: any, b?: any, c?: any) {} 
  21.     this.cb = cb   
  22.     // option在new Watcher傳遞的參數值為{lazy: true}  
  23.     // !!操作符即將options.lazy強轉為boolean類型 
  24.     // 賦值之后this.lazy的值為true 
  25.     this.lazy = !!options.lazy  
  26.     // 賦值之后this.dirty的值true 
  27.     this.dirty = this.lazy  
  28.      
  29.     /* 
  30.     * 在new Watcher的時候因為this.lazy的值為true 
  31.     * 所以this.value的值還是undefined 
  32.     */ 
  33.     this.value = this.lazy ? undefined : this.get() 
  34.   } 
  35.   get () {  
  36.     const vm = this.vm 
  37.     /* 
  38.     * 在構造函數中,計算屬性的get方法賦值給了watcher的getter屬性 
  39.     * 所以該行代碼即調用計算屬性的get方法,獲取計算屬性的值 
  40.     */ 
  41.     value = this.getter.call(vm, vm) 
  42.     return value 
  43.   } 
  44.   evaluate () { 
  45.     /* 
  46.     * 調用watcher的get方法 
  47.     * watcher的get方法邏輯為:調用計算屬性的get方法獲取計算屬性的值并返回 
  48.     * 所以evaluate函數也就是獲取計算屬性的值,并賦值給watcher.value 
  49.     * 并且將watcher.dirty置為false,這個dirty是實現緩存的關鍵 
  50.     */  
  51.     this.value = this.get() 
  52.     this.dirty = false 
  53.   } 

看了這個簡化版的Watcher以后,想必我們已經很清楚的知道了Watcher類的實現。

那接下來就是關于緩存的重點了,也就是遍歷計算屬性做的第二件事:調用defineComputed函數:

  1. /* 
  2. * Vue版本:v2.6.12 
  3. * 代碼位置:/vue/src/core/instance/state.js 
  4. * @params: target  vue實例對象 
  5. * @params: key     計算屬性名 
  6. * @params: userDef 計算屬性定義的function或者object 
  7. */ 
  8. export function defineComputed ( 
  9.   target: any
  10.   key: string, 
  11.   userDef: Object | Function 
  12. ) {   
  13.  
  14.   // ......暫時省略有關sharedPropertyDefinition的代碼邏輯...... 
  15.    
  16.   /* 
  17.   * sharedPropertyDefinition本身是一個對象,定義在本文件31行: 
  18.   * const sharedPropertyDefinition = { 
  19.   *   enumerable: true
  20.   *   configurable: true
  21.   *   get: noop, 
  22.   *   set: noop 
  23.   * } 
  24.   * 最后使用Object.defineProperty傳入對應的參數使得計算屬性變得可觀測 
  25.   */ 
  26.   Object.defineProperty(target, key, sharedPropertyDefinition) 

defineComputed方法最核心也只有一行代碼,也就是使用Object.defineProperty將計算屬性變得可觀測。

那么接下來我們的關注點就是調用Object.defineProperty函數時傳遞的第三個參數:sharedPropertyDefinition。

sharedPropertyDefinition是定義在當前文件中的一個對象,默認值如下:

  1. const sharedPropertyDefinition = { 
  2.   enumerable: true
  3.   configurable: true
  4.   get: noop, 
  5.   set: noop 

前面貼出來的defineComputed源碼中,我注釋說明省略了一段有關sharedPropertyDefinition的代碼邏輯,那省略的這段源代碼就不展示了,它的主要作用就是在對sharedPropertyDefinition.get和sharedPropertyDefinition.set進行重寫,重寫之后sharedPropertyDefinition的值為:

  1. const sharedPropertyDefinition = { 
  2.   enumerable: true
  3.   configurable: true
  4.   get: function(){ 
  5.       // 獲取計算屬性對應的watcher實例 
  6.       const watcher = this._computedWatchers && this._computedWatchers[key
  7.       if (watcher) { 
  8.         if (watcher.dirty) { 
  9.           watcher.evaluate() 
  10.         } 
  11.         if (Dep.target) { 
  12.           watcher.depend() 
  13.         } 
  14.         return watcher.value 
  15.       } 
  16.     } 
  17.   }, 
  18.   // set對應的值這里寫的是noop 
  19.   // 但是我們要知道set真正的值是我們為計算屬性提供的set函數 
  20.   // 千萬不要理解錯了哦  
  21.   set: noop,   

那sharedPropertyDefinition.get函數的邏輯已經非常的清晰了,同時它的邏輯就是計算屬性緩存實現的關鍵邏輯:在sharedPropertyDefinition.get函數中,先獲取到計算屬性對應的watcher實例;然后判斷watcher.dirty的值,如果該值為false,則直接返回watcher.value;否則調用watcher.evaluate()重新獲取計算屬性的值。

關于計算屬性緩存的源碼分析就到這里,相信大家對計算屬性的緩存實現已經有了一定的認識。不過僅僅是了解這些還不夠,我們應該去通讀計算屬性的完整源碼實現,才能對計算屬性有一個更通透的認識。

6. 偵聽屬性進階

>>> 6.1 handler

前面我們是這樣實現偵聽屬性的:

  1. watch: { 
  2.   counter: function(newValue, oldValue){ 
  3.     if(this.counter == 10){ 
  4.       this.counter = 0; 
  5.     } 
  6.   } 

那上面的這種寫法等同于給counter提供一個handler函數:

  1. watch: { 
  2.   counter: { 
  3.     handler: function(newValue, oldValue){ 
  4.       if(this.counter == 10){ 
  5.         this.counter = 0; 
  6.       } 
  7.     } 
  8.   } 

>>> 6.2 immediate

正常情況下,偵聽屬性提供的函數是不會立即執行的,只有在對應的vue data發生變化時,偵聽屬性對應的函數才會執行。

那如果我們需要偵聽屬性對應的函數立即執行一次,就可以給偵聽屬性提供一個immediate選項,并設置其值為true。

  1. watch: { 
  2.   counter: { 
  3.     handler: function(newValue, oldValue){ 
  4.       if(this.counter == 10){ 
  5.         this.counter = 0; 
  6.       } 
  7.     }, 
  8.     immediate: true 
  9.   } 

>>> 6.3 deep

如果我們對一個對象類型的vue data進行偵聽,當這個對象內的屬性發生變化時,默認是不會觸發偵聽函數的。

  1. <template> 
  2.   <div id="app"
  3.     <p><el-input v-model="person.name" placeholder="請輸入姓名"></el-input></p> 
  4.     <p><el-input v-model="person.age" placeholder="請輸入年齡"></el-input></p> 
  5.   </div> 
  6. </template> 
  7. <script> 
  8. export default { 
  9.   name'App'
  10.   data() { 
  11.     return { 
  12.       person: { 
  13.         name'jack'
  14.         age: 20 
  15.       } 
  16.     } 
  17.   }, 
  18.   watch: { 
  19.     person: function(newValue){ 
  20.       console.log(newValue.name + ' ' + newValue.age); 
  21.     } 
  22.   } 
  23. </script> 

監聽對象類型的數據,偵聽函數沒有觸發:

 

圖片

 

通過給偵聽屬性提供deep: true就可以偵聽到對象內部屬性的變化:

  1. watch: { 
  2.   person: { 
  3.     handler: function(newValue){ 
  4.       console.log(newValue.name + ' ' + newValue.age); 
  5.     }, 
  6.     deep: true 
  7.   } 
圖片

 

不過仔細觀察上面的示例會發現這種方式去監聽Object類型的數據,Object數據內部任一屬性發生變化都會觸發偵聽函數,那如果我們想單獨偵聽對象中的某個屬性,可以使用下面這樣的方式:

  1. watch: { 
  2.   'person.name'function(newValue, oldValue){ 
  3.       // 邏輯 
  4.    } 

7.總結

到此本篇文章就結束了,內容非常的簡單易懂,在此將以上的內容做以總結:

 

圖片

 

學無止境,除了基礎的內容之外,很多特性的實現原理也是我們應該關注的東西,但是介于本篇文章輸出的初衷,所以對原理實現并沒有完整的分析,后面有機會在總結~

原文鏈接:https://mp.weixin.qq.com/s/frWBXTa-EnhkGFn6c1X5NQ

 

責任編輯:武曉燕 來源: 不知名寶藏程序媛
相關推薦

2022-07-14 08:22:48

Computedvue3

2024-03-08 10:38:07

Vue響應式數據

2021-12-08 09:09:33

Vue 3 Computed Vue2

2023-11-28 17:49:51

watch?computed?性能

2023-03-29 14:25:08

Vue.js前端框架

2022-06-09 08:28:27

Vue3watchwatchEffec

2022-06-26 00:00:02

Vue3響應式系統

2023-12-11 07:34:37

Computed計算屬性Vue3

2021-12-07 05:44:45

Vue 3 Watch WatchEffect

2024-10-17 16:08:36

SQL 查詢SQL

2022-04-11 08:03:30

Vue.jscomputed計算屬性

2024-05-27 08:39:17

Vue3變量響應式

2022-04-12 08:08:57

watch函數options封裝

2025-04-07 08:50:36

2024-03-22 08:57:04

Vue3Emoji表情符號

2024-03-21 08:34:49

Vue3WebSocketHTTP

2009-06-25 15:20:28

CollectionMap

2015-03-20 15:26:03

Apple Watch續航

2024-04-08 07:28:27

PiniaVue3狀態管理庫

2021-06-26 06:29:14

Vue 2Vue 3開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区四区免费观看 | 最新日韩在线视频 | 国产欧美一区二区三区免费 | 国产精品日韩在线 | av中文字幕在线观看 | 麻豆久久久久 | 在线中文字幕国产 | 久久久久国产一区二区三区 | 欧美一区二区在线看 | 国产精品18久久久 | 一级片在线观看 | 日韩喷潮| 日韩乱码在线 | 自拍偷拍3p | 成人免费淫片aa视频免费 | 日韩成人在线播放 | 色精品视频 | 九九热久久免费视频 | 亚洲视频在线看 | 久久久tv| 久久久高清| 久久电影一区 | 国产精品久久久久久久久久软件 | 亚洲免费成人 | www久久爱 | 国产亚洲一区二区三区在线 | 四虎永久免费影院 | 国产欧美精品一区二区三区 | 一区二区三区亚洲视频 | 国产毛片久久久久久久久春天 | 婷婷色在线 | 91精品免费 | 日韩精品久久一区 | 免费一级黄色录像 | 欧美在线视频a | 伊人网综合 | 中文字幕一区二区三区四区五区 | 午夜影院操 | 99精品免费 | 久草视频2 | 日韩欧美在线一区二区 |