Vue學(xué)習(xí)——計(jì)算屬性

概述

通常我們會(huì)在模版中綁定表達(dá)式,但如果表達(dá)式的邏輯過(guò)于復(fù)雜指攒,則模版會(huì)變得臃且難以維護(hù)。

例:Mustache語(yǔ)法中的表達(dá)式調(diào)用了三個(gè)方法來(lái)最終實(shí)現(xiàn)字符串的反轉(zhuǎn)

<div id="app">
    <p>{{message.split('').reverse().join('')}}</p>
</div>

定義計(jì)算屬性

表達(dá)式的邏輯過(guò)于復(fù)雜的時(shí)候盛垦,都應(yīng)當(dāng)考慮使用計(jì)算屬性纪蜒。計(jì)算屬性是以函數(shù)形式蹭秋,在Vue實(shí)例的選項(xiàng)對(duì)象的computed選項(xiàng)中定義。我們將上面字符串反轉(zhuǎn)的功能使用計(jì)算屬性來(lái)實(shí)現(xiàn)堤撵。

代碼示例如下:

<div="app">
    <p>原始字符串:{{message}}</p>
    <p>計(jì)算后的反轉(zhuǎn)字符串:{{reversedMessage}}</p>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello!'
        },
        computed: {
            // 計(jì)算屬性的getter
            reversedMessage: function() {
                return this.message.split('').reverse().join('')
            }
        }
    });
</script>

我們聲明了一個(gè)計(jì)算屬性reversedMessage仁讨,給出的函數(shù)將用作屬性vm.reversedMessage的getter函數(shù)。

當(dāng)message屬性的值改變時(shí)实昨,reversedMessage的值也會(huì)自動(dòng)更新洞豁,并且會(huì)自動(dòng)同步更新DOM部分。當(dāng)瀏覽器的控制臺(tái)窗口中修改vm.message的值荒给,可以發(fā)現(xiàn)reversedMessage的值也會(huì)隨之改變丈挟。

計(jì)算屬性默認(rèn)只有g(shù)etter,因此是不能直接修改計(jì)算屬性的志电,如果需要也可以提供一個(gè)setter曙咽。

代碼示例如下:

<div="app">
    <p>First name: <input type="text" v-model="firstName"></p>
    <p>Last name: <input type="text" v-model="lastName"></p>
    <p>{{fullName}}</p>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            firstName: 'John',
            lastName: 'Tierney'
        },
        computed: {
            fullName: {
                // getter
                get: function() {
                    return this.firstName + ' ' + this.lastName
                },
                // setter
                set: function(newName) {
                    var names = newName.split('')
                    this.firstName = names[0]
                    this.lastName = names[names.length - 1]
                }
            }
        },
    });
</script>
  • 任意修改firstName或者lastName的值,fullName的值也會(huì)自動(dòng)更新挑辆,這是調(diào)用它的getter函數(shù)來(lái)實(shí)現(xiàn)的例朱。在瀏覽器的控制臺(tái)窗口中輸入vm.fullName="Bruce Willis",可以看到firstName和lastName的值也同時(shí)發(fā)生了改變鱼蝉,這時(shí)調(diào)用fullName的setter函數(shù)來(lái)實(shí)現(xiàn)的洒嗤。

計(jì)算屬性緩存

復(fù)雜的表達(dá)式也可以放到方法中去實(shí)現(xiàn),然后在綁定表達(dá)式中調(diào)用方法即可魁亦。

例:使用方法實(shí)現(xiàn)字符串翻轉(zhuǎn)

<div="app">
    <p>原始字符串:{{message}}</p>
    <p>計(jì)算后的反轉(zhuǎn)字符串:{{reversedMessage}}</p>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello!'
        },
        methods: {
            // 計(jì)算屬性的getter
            reversedMessage: function() {
                return this.message.split('').reverse().join('')
            }
        }
    });
</script>

既然使用方法能實(shí)現(xiàn)與計(jì)算屬性相同的結(jié)果渔隶,那么為什么還要使用計(jì)算屬性呢?

因?yàn)橛?jì)算屬性是基于它的響應(yīng)式依賴(lài)進(jìn)行緩存的洁奈,只有在計(jì)算屬性的相關(guān)響應(yīng)式依賴(lài)發(fā)生改變時(shí)才會(huì)重新求值间唉。這就意味著只要message還沒(méi)有發(fā)生改變,多次訪問(wèn)reversedMessage計(jì)算屬性會(huì)立即返回之前的計(jì)算結(jié)果睬魂,而不會(huì)再次執(zhí)行函數(shù)终吼;而如果采用方法镀赌,那么不管什么時(shí)候訪問(wèn)reversedMessage()方法氯哮,該方法都會(huì)被調(diào)用。

例:同時(shí)使用方法和計(jì)算屬性

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>計(jì)算屬性</title>
    </head>
    <body>
        <div id="app">
            <p>原始字符串:{{message}}</p>
            <p>計(jì)算后的反轉(zhuǎn)字符串:{{reversedMessage}}</p>
            <p>方法調(diào)用后的反轉(zhuǎn)字符串:{{reversedMessage2()}}</p>
        </div>
        
        <script src="./vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    message: 'Hello!'
                },
                computed: {
                    // 計(jì)算屬性的getter
                    reversedMessage: function() {
                        alert("計(jì)算屬性")
                        return this.message.split('').reverse().join('')
                    }
                },
                methods: {
                    reversedMessage2: function() {
                        alert("方法")
                        return this.message.split('').reverse().join('')
                    }     
                }
            })
            let msg = vm.reversedMessage
            mst = vm.reversedMessage2()
        </script>
    </body>
</html>

我們?cè)谟?jì)算屬性reversedMessage的getter函數(shù)和方法reversedMessage2()中調(diào)用alert()語(yǔ)句顯示一個(gè)消息框商佛,在Vue實(shí)例構(gòu)建后喉钢,我們分別訪問(wèn)vm.reversedMessage計(jì)算屬性和調(diào)用vm.reversedMessage2()方法。

使用瀏覽器打開(kāi)該頁(yè)面良姆,可以依次看到“計(jì)算屬性”“方法”“方法”共三個(gè)消息框肠虽,前兩個(gè)消息框是模版中的Mustache標(biāo)簽被替換時(shí)顯示的,最后一個(gè)“方法”消息框是代碼最后調(diào)用vm.reversedMessage2()方法顯示的玛追,可以看到最后對(duì)vm.reversedMessage計(jì)算屬性的訪問(wèn)并沒(méi)有彈出消息框税课,這是因?yàn)樗蕾?lài)的message屬性并未發(fā)生改變闲延。

下面代碼中的計(jì)算屬性now在初次渲染后不會(huì)再更新,因?yàn)镈ate.now()不是響應(yīng)式依賴(lài)韩玩。

computed: {
    now: function() {
        return Date.now()
    }
}

v-for和v-if一起使用的替代方案

在前文的指令篇中垒玲,講到了將v-for和v-if一起使用,在渲染列表時(shí)找颓,根據(jù)v-if指令的條件判斷來(lái)過(guò)濾列表中不滿(mǎn)足條件的列表項(xiàng)合愈。實(shí)際上,這個(gè)功能也可以使用計(jì)算屬性來(lái)完成击狮。

修改前文代碼

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-for與計(jì)算屬性</title>
    </head>
    <body>
        <div id="app">
            <h1>已完成的工作計(jì)劃</h1>
            <ul>
                <li v-for="plan in completedPlans">
                    {{plan.content}}
                </li>
            </ul>
            <h1>未完成的工作計(jì)劃</h1>
            <ul>
                <li v-for="plan in incompletePlans">
                    {{plan.content}}
                </li>
            </ul>
        </div>
        
        <script src="./vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    plans: [
                        {content: 'planA', isComplete: false},
                        {content: 'planB', isComplete: true},
                        {content: 'planC', isComplete: false},
                        {content: 'planD', isComplete: true},
                        {content: 'planE', isComplete: false}
                    ]
                },
                computed: {
                    // 計(jì)算屬性的getter
                    completedPlans: function() {
                        return this.plans.filter(plan => plan.isComplete)
                    },
                    incompletePlans: function() {
                        return this.plans.filter(plan => !plan.isComplete)
                    }
                }
            })
        </script>
    </body>
</html>

這里不建議把v-for和v-if同時(shí)用在同一個(gè)元素上佛析,這是因?yàn)殡m然v-if指令只渲染了部分元素,但在每次重新渲染時(shí)仍然要遍歷整個(gè)列表彪蓬,而不論渲染的元素是否發(fā)生過(guò)改變寸莫。

采用計(jì)算屬性過(guò)濾后再遍歷,可以獲得如下好處:

  • 過(guò)濾后的列表只會(huì)在plans數(shù)組發(fā)生相關(guān)變化時(shí)才被重新計(jì)算寞焙,過(guò)濾更高效储狭。
  • 使用v-for="plan in completedPlans"之后,在渲染的時(shí)候只遍歷已完成的計(jì)劃捣郊,渲染更高效辽狈。
  • 解耦渲染層的邏輯,可維護(hù)性(對(duì)邏輯的更改和擴(kuò)展)更強(qiáng)呛牲。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刮萌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子娘扩,更是在濱河造成了極大的恐慌着茸,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琐旁,死亡現(xiàn)場(chǎng)離奇詭異涮阔,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)灰殴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)敬特,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人牺陶,你說(shuō)我怎么就攤上這事伟阔。” “怎么了掰伸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵皱炉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我狮鸭,道長(zhǎng)合搅,這世上最難降的妖魔是什么多搀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮灾部,結(jié)果婚禮上酗昼,老公的妹妹穿的比我還像新娘。我一直安慰自己梳猪,他們只是感情好麻削,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著春弥,像睡著了一般呛哟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匿沛,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天扫责,我揣著相機(jī)與錄音,去河邊找鬼逃呼。 笑死鳖孤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抡笼。 我是一名探鬼主播苏揣,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼推姻!你這毒婦竟也來(lái)了平匈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤藏古,失蹤者是張志新(化名)和其女友劉穎增炭,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拧晕,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隙姿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厂捞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片输玷。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蔫敲,靈堂內(nèi)的尸體忽然破棺而出饲嗽,到底是詐尸還是另有隱情炭玫,我是刑警寧澤奈嘿,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站吞加,受9級(jí)特大地震影響裙犹,放射性物質(zhì)發(fā)生泄漏尽狠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一叶圃、第九天 我趴在偏房一處隱蔽的房頂上張望袄膏。 院中可真熱鬧,春花似錦掺冠、人聲如沸沉馆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)斥黑。三九已至,卻和暖如春眉厨,著一層夾襖步出監(jiān)牢的瞬間锌奴,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工憾股, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鹿蜀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓服球,卻偏偏與公主長(zhǎng)得像茴恰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斩熊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355