詳解Vue計算屬性和偵聽屬性

前言

一些初學者可能對計算屬性和偵聽屬性的使用場景感到困惑不解,本文主要介紹二者的用法、使用場景及其二者的區別。 本文的代碼請猛戳github博客,紙上得來終覺淺,你們動手多敲敲代碼!html

計算屬性

1.介紹

計算屬性是自動監聽依賴值的變化,從而動態返回內容,監聽是一個過程,在監聽的值變化時,能夠觸發一個回調,並作一些事情。它有如下幾個特色:前端

  • 數據能夠進行邏輯處理,減小模板中計算邏輯。
  • 對計算屬性中的數據進行監視
  • 依賴固定的數據類型(響應式數據)

計算屬性由兩部分組成:get和set,分別用來獲取計算屬性和設置計算屬性。默認只有get,若是須要set,要本身添加。另外set設置屬性,並非直接修改計算屬性,而是修改它的依賴。vue

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      //this.fullName = newValue 這種寫法會報錯
      var names = newValue.split(' ')
      this.firstName = names[0]//對它的依賴進行賦值
      this.lastName = names[names.length - 1]
    }
  }
}
複製代碼

如今再運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstName 和 vm.lastName 也會相應地被更新。git

2.計算屬性 vs 普通屬性

能夠像綁定普通屬性同樣在模板中綁定計算屬性,在定義上有區別:計算屬性的屬性值必須是一個函數。github

data:{ //普通屬性
  msg:'浪裏行舟',
},
computed:{ //計算屬性
  msg2:function(){ //該函數必須有返回值,用來獲取屬性,稱爲get函數
    return '浪裏行舟';
  },
  reverseMsg:function(){
  //能夠包含邏輯處理操做,同時reverseMsg依賴於msg,一旦msg發生變化,reverseMsg也會跟着變化
    return this.msg.split(' ').reverse().join(' ');
 }
}  
複製代碼

3.計算屬性 vs 方法

二者最主要的區別:computed 是能夠緩存的,methods 不能緩存;**只要相關依賴沒有改變,屢次訪問計算屬性獲得的值是以前緩存的計算結果,不會屢次執行。**網上有種說法就是方法能夠傳參,而計算屬性不能,其實並不許確,計算屬性能夠經過閉包來實現傳參:面試

:data="closure(item, itemName, blablaParams)"
computed: {
 closure () {
   return function (a, b, c) {
        /** do something */
        return data
    }
 }
}
複製代碼

偵聽屬性

Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變更:偵聽屬性watch。watch中能夠執行任何邏輯,如函數節流,Ajax異步獲取數據,甚至操做 DOM(不建議)。segmentfault

1.常規用法

<template>
  <div class="attr">
    <h1>watch屬性</h1>
    <h2>{{ $data }}</h2>
    <button @click="() => (a += 1)">修改a的值</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      a: 1,
      b: { c: 2, d: 3 },
      e: {
        f: {
          g: 4
        }
      },
      h: []
    };
  },
  watch: {
    a: function(val, oldVal) {
      this.b.c += 1;
    },
    "b.c": function(val, oldVal) {
      this.b.d += 1;
    },
    "b.d": function(val, oldVal) {
      this.e.f.g += 1;
    },
    e: {
      handler: function(val, oldVal) {
        this.h.push("浪裏行舟");
      },
      deep: true //用於監聽e對象內部值的變化
    }
  }
};
</script>
複製代碼

watch.gif

2.使用 watch 的深度遍歷和當即調用功能

使用 watch 來監聽數據變化的時候除了經常使用到 handler 回調,其實其還有兩個參數,即是:緩存

  • deep 設置爲 true 用於監聽對象內部值的變化
  • immediate 設置爲 true 將當即以表達式的當前值觸發回調
<template>
    <button @click="obj.a = 2">修改</button>
</template>
<script>
export default {
    data() {
        return {
            obj: {
                a: 1,
            }
        }
    },
    watch: {
        obj: {
            handler: function(newVal, oldVal) {
                console.log(newVal); 
            },
            deep: true,
            immediate: true 
        }
    }
}
</script>
複製代碼

以上代碼咱們修改了 obj 對象中 a 屬性的值,咱們能夠觸發其 watch 中的 handler 回調輸出新的對象,而若是不加 deep: true,咱們只能監聽 obj 的改變,並不會觸發回調。同時咱們也添加了 immediate: true 配置,其會當即以 obj 的當前值觸發回調。 咱們再看一個實際工做中常遇到的場景:組件建立的時候咱們獲取一次列表的數據,同時監聽input框,每當發生變化的時候從新獲取一次篩選後的列表。bash

created(){
    this.fetchPostList()
},
watch: {
    searchInputValue(){
        this.fetchPostList()
    }
}
複製代碼

有沒有辦法優化一下呢?服務器

watch: {
    searchInputValue:{
        handler: 'fetchPostList',
        immediate: true
    }
}
複製代碼

首先,在watchers中,能夠直接使用函數的字面量名稱;其次,聲明immediate:true表示建立組件時立馬執行一次。

二者之間對比

image.png

從上面流程圖中,咱們能夠看出它們之間的區別:

  • watch:監測的是屬性值, 只要屬性值發生變化,其都會觸發執行回調函數來執行一系列操做。
  • computed:監測的是依賴值,依賴值不變的狀況下其會直接讀取緩存進行復用,變化的狀況下才會從新計算。

除此以外,有點很重要的區別是:計算屬性不能執行異步任務,計算屬性必須同步執行。也就是說計算屬性不能向服務器請求或者執行異步任務。若是遇到異步任務,就交給偵聽屬性。watch也能夠檢測computed屬性。

接下去咱們看個用watch來實現防抖的例子:直到用戶中止輸入超過1秒後,才更新視圖。

<template>
  <div>
    {{ fullName }}
    <div>firstName: <input v-model="firstName" /></div>
    <div>lastName: <input v-model="lastName" /></div>
  </div>
</template>
<script>
import { setTimeout } from "timers";
export default {
  data: function() {
    return {
      firstName: "浪裏行舟",
      lastName: "前端工匠",
      fullName: "浪裏行舟 前端工匠"
    };
  },
  watch: {
    firstName: function(val) {
      clearTimeout(this.firstTimeout);
      this.firstTimeOut = setTimeout(() => {
        this.fullName = val + " " + this.lastName;
      }, 1000);
    },
    lastName: function(val) {
      clearTimeout(this.lastTimeout);
      this.lastTimeOut = setTimeout(() => {
        this.fullName = this.firstName + " " + val;
      }, 1000);
    }
  }
};
複製代碼

watch1.gif

總結

計算屬性適合用在模板渲染中,某個值是依賴了其它的響應式對象甚至是計算屬性計算而來;而偵聽屬性適用於觀測某個值的變化去完成一段複雜的業務邏輯。

  • computed能作的,watch都能作,反之則不行
  • 能用computed的儘可能用computed

歡迎關注公衆號:前端工匠,你的成長咱們一塊兒見證!

image

參考資料

相關文章
相關標籤/搜索