詳解Vue計(jì)算屬性和偵聽(tīng)屬性

前言

一些初學(xué)者可能對(duì)計(jì)算屬性和偵聽(tīng)屬性的使用場(chǎng)景感到困惑不解呵萨,本文主要介紹兩者的用法箱吕、使用場(chǎng)景及其兩者的區(qū)別脑豹。 本文的代碼請(qǐng)猛戳github博客坐慰,紙上得來(lái)終覺(jué)淺,大家動(dòng)手多敲敲代碼鲤孵!

計(jì)算屬性

1.介紹

計(jì)算屬性是自動(dòng)監(jiān)聽(tīng)依賴值的變化壶栋,從而動(dòng)態(tài)返回內(nèi)容,監(jiān)聽(tīng)是一個(gè)過(guò)程普监,在監(jiān)聽(tīng)的值變化時(shí)贵试,可以觸發(fā)一個(gè)回調(diào),并做一些事情凯正。它有以下幾個(gè)特點(diǎn):

  • 數(shù)據(jù)可以進(jìn)行邏輯處理毙玻,減少模板中計(jì)算邏輯。
  • 對(duì)計(jì)算屬性中的數(shù)據(jù)進(jìn)行監(jiān)視
  • 依賴固定的數(shù)據(jù)類型(響應(yīng)式數(shù)據(jù))

計(jì)算屬性由兩部分組成:get和set廊散,分別用來(lái)獲取計(jì)算屬性和設(shè)置計(jì)算屬性桑滩。默認(rèn)只有g(shù)et,如果需要set允睹,要自己添加运准。另外set設(shè)置屬性,并不是直接修改計(jì)算屬性缭受,而是修改它的依賴胁澳。

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      //this.fullName = newValue 這種寫法會(huì)報(bào)錯(cuò)
      var names = newValue.split(' ')
      this.firstName = names[0]//對(duì)它的依賴進(jìn)行賦值
      this.lastName = names[names.length - 1]
    }
  }
}

現(xiàn)在再運(yùn)行 vm.fullName = 'John Doe' 時(shí),setter 會(huì)被調(diào)用米者,vm.firstName 和 vm.lastName 也會(huì)相應(yīng)地被更新韭畸。

2.計(jì)算屬性 vs 普通屬性

可以像綁定普通屬性一樣在模板中綁定計(jì)算屬性,在定義上有區(qū)別:計(jì)算屬性的屬性值必須是一個(gè)函數(shù)蔓搞。

data:{ //普通屬性
  msg:'浪里行舟',
},
computed:{ //計(jì)算屬性
  msg2:function(){ //該函數(shù)必須有返回值胰丁,用來(lái)獲取屬性,稱為get函數(shù)
    return '浪里行舟';
  },
  reverseMsg:function(){
  //可以包含邏輯處理操作喂分,同時(shí)reverseMsg依賴于msg,一旦msg發(fā)生變化隘马,reverseMsg也會(huì)跟著變化
    return this.msg.split(' ').reverse().join(' ');
 }
}  

3.計(jì)算屬性 vs 方法

兩者最主要的區(qū)別:computed 是可以緩存的,methods 不能緩存妻顶;只要相關(guān)依賴沒(méi)有改變,多次訪問(wèn)計(jì)算屬性得到的值是之前緩存的計(jì)算結(jié)果蜒车,不會(huì)多次執(zhí)行讳嘱。網(wǎng)上有種說(shuō)法就是方法可以傳參,而計(jì)算屬性不能酿愧,其實(shí)并不準(zhǔn)確沥潭,計(jì)算屬性可以通過(guò)閉包來(lái)實(shí)現(xiàn)傳參:

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

偵聽(tīng)屬性

Vue 提供了一種更通用的方式來(lái)觀察和響應(yīng) Vue 實(shí)例上的數(shù)據(jù)變動(dòng):偵聽(tīng)屬性watch。watch中可以執(zhí)行任何邏輯嬉挡,如函數(shù)節(jié)流钝鸽,Ajax異步獲取數(shù)據(jù)汇恤,甚至操作 DOM(不建議)。

1.常規(guī)用法

<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 //用于監(jiān)聽(tīng)e對(duì)象內(nèi)部值的變化
    }
  }
};
</script>
復(fù)制代碼

2.使用 watch 的深度遍歷和立即調(diào)用功能

使用 watch 來(lái)監(jiān)聽(tīng)數(shù)據(jù)變化的時(shí)候除了常用到 handler 回調(diào)拔恰,其實(shí)其還有兩個(gè)參數(shù)因谎,便是:

  • deep 設(shè)置為 true 用于監(jiān)聽(tīng)對(duì)象內(nèi)部值的變化
  • immediate 設(shè)置為 true 將立即以表達(dá)式的當(dāng)前值觸發(fā)回調(diào)
<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 對(duì)象中 a 屬性的值,我們可以觸發(fā)其 watch 中的 handler 回調(diào)輸出新的對(duì)象颜懊,而如果不加 deep: true财岔,我們只能監(jiān)聽(tīng) obj 的改變,并不會(huì)觸發(fā)回調(diào)河爹。同時(shí)我們也添加了 immediate: true 配置匠璧,其會(huì)立即以 obj 的當(dāng)前值觸發(fā)回調(diào)。 我們?cè)倏匆粋€(gè)實(shí)際工作中常遇到的場(chǎng)景:組件創(chuàng)建的時(shí)候我們獲取一次列表的數(shù)據(jù)咸这,同時(shí)監(jiān)聽(tīng)input框夷恍,每當(dāng)發(fā)生變化的時(shí)候重新獲取一次篩選后的列表。

created(){
    this.fetchPostList()
},
watch: {
    searchInputValue(){
        this.fetchPostList()
    }
}

有沒(méi)有辦法優(yōu)化一下呢媳维?

watch: {
    searchInputValue:{
        handler: 'fetchPostList',
        immediate: true
    }
}

首先酿雪,在watchers中,可以直接使用函數(shù)的字面量名稱侨艾;其次执虹,聲明immediate:true表示創(chuàng)建組件時(shí)立馬執(zhí)行一次。

兩者之間對(duì)比

從上面流程圖中唠梨,我們可以看出它們之間的區(qū)別:

  • watch:監(jiān)測(cè)的是屬性值袋励, 只要屬性值發(fā)生變化,其都會(huì)觸發(fā)執(zhí)行回調(diào)函數(shù)來(lái)執(zhí)行一系列操作当叭。
  • computed:監(jiān)測(cè)的是依賴值茬故,依賴值不變的情況下其會(huì)直接讀取緩存進(jìn)行復(fù)用,變化的情況下才會(huì)重新計(jì)算蚁鳖。

除此之外磺芭,有點(diǎn)很重要的區(qū)別是:計(jì)算屬性不能執(zhí)行異步任務(wù),計(jì)算屬性必須同步執(zhí)行醉箕。也就是說(shuō)計(jì)算屬性不能向服務(wù)器請(qǐng)求或者執(zhí)行異步任務(wù)钾腺。如果遇到異步任務(wù),就交給偵聽(tīng)屬性讥裤。watch也可以檢測(cè)computed屬性放棒。

接下去我們看個(gè)用watch來(lái)實(shí)現(xiàn)防抖的例子:直到用戶停止輸入超過(guò)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);
    }
  }
};
復(fù)制代碼

總結(jié)

計(jì)算屬性適合用在模板渲染中间螟,某個(gè)值是依賴了其它的響應(yīng)式對(duì)象甚至是計(jì)算屬性計(jì)算而來(lái);而偵聽(tīng)屬性適用于觀測(cè)某個(gè)值的變化去完成一段復(fù)雜的業(yè)務(wù)邏輯。

  • computed能做的厢破,watch都能做荣瑟,反之則不行
  • 能用computed的盡量用computed

歡迎關(guān)注公眾號(hào):前端工匠,你的成長(zhǎng)我們一起見(jiàn)證摩泪!

作者:浪里行舟
鏈接:https://juejin.im/post/5d01a81d51882559ef78e498

求點(diǎn)贊笆焰,求關(guān)注~


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市加勤,隨后出現(xiàn)的幾起案子仙辟,更是在濱河造成了極大的恐慌,老刑警劉巖鳄梅,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叠国,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡戴尸,警方通過(guò)查閱死者的電腦和手機(jī)粟焊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)孙蒙,“玉大人项棠,你說(shuō)我怎么就攤上這事】媛停” “怎么了香追?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)坦胶。 經(jīng)常有香客問(wèn)我透典,道長(zhǎng),這世上最難降的妖魔是什么顿苇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任峭咒,我火速辦了婚禮,結(jié)果婚禮上纪岁,老公的妹妹穿的比我還像新娘凑队。我一直安慰自己,他們只是感情好幔翰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布漩氨。 她就那樣靜靜地躺著,像睡著了一般遗增。 火紅的嫁衣襯著肌膚如雪才菠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天贡定,我揣著相機(jī)與錄音,去河邊找鬼可都。 笑死缓待,一個(gè)胖子當(dāng)著我的面吹牛蚓耽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播旋炒,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼步悠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了瘫镇?” 一聲冷哼從身側(cè)響起鼎兽,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铣除,沒(méi)想到半個(gè)月后谚咬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尚粘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年择卦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郎嫁。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秉继,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泽铛,到底是詐尸還是另有隱情尚辑,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布盔腔,位于F島的核電站杠茬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铲觉。R本人自食惡果不足惜澈蝙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撵幽。 院中可真熱鬧灯荧,春花似錦、人聲如沸盐杂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)链烈。三九已至厉斟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間强衡,已是汗流浹背擦秽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人感挥。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓缩搅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親触幼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子硼瓣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容