做自(zì)由與創造的先行者

計(jì)算(suàn)屬性

Vue.js中文(wén)手冊

基礎示例

模闆中的表達式雖然方便,但(dàn)也(yě)隻能(néng)用(yòng)來(lái)做簡單的操作(zuò)。如果在模闆中寫太多邏輯,會(huì)讓模闆變得臃腫,難以維護。比如說,我們有這(zhè)樣一個包含嵌套數組的對(duì)象: js export default { data() { return { author: { name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] } } } } 我們想根據 author 是否已有一些(xiē)書籍來(lái)展示不同的信息: template <p>Has published books:</p> <span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span> 這(zhè)裏的模闆看(kàn)起來(lái)有些(xiē)複雜(zá)。我們必須認真看(kàn)好(hǎo)一會(huì)兒才能(néng)明(míng)白(bái)它的計(jì)算(suàn)依賴于 author.books。更重要的是,如果在模闆中需要不止一次這(zhè)樣的計(jì)算(suàn),我們可不想将這(zhè)樣的代碼在模闆裏重複好(hǎo)多遍。 因此我們推薦使用(yòng)計(jì)算(suàn)屬性來(lái)描述依賴響應式狀态的複雜(zá)邏輯。這(zhè)是重構後的示例: js export default { data() { return { author: { name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] } } }, computed: { // 一個計(jì)算(suàn)屬性的 getter publishedBooksMessage() { // `this` 指向當前組件實例 return this.author.books.length > 0 ? 'Yes' : 'No' } } } template <p>Has published books:</p> <span>{{ publishedBooksMessage }}</span> 我們在這(zhè)裏定義了(le)一個計(jì)算(suàn)屬性 publishedBooksMessage。 更改此應用(yòng)的 data 中 books 數組的值後,可以看(kàn)到(dào) publishedBooksMessage 也(yě)會(huì)随之改變。 在模闆中使用(yòng)計(jì)算(suàn)屬性的方式和(hé)一般的屬性并無二緻。Vue 會(huì)檢測到(dào) this.publishedBooksMessage 依賴于 this.author.books,所以當 this.author.books 改變時(shí),任何依賴于 this.publishedBooksMessage 的綁定都将同時(shí)更新。 計(jì)算(suàn)屬性緩存 vs 方法

你(nǐ)可能(néng)注意到(dào)我們在表達式中像這(zhè)樣調用(yòng)一個函數也(yě)會(huì)獲得和(hé)計(jì)算(suàn)屬性相同的結果: template <p>{{ calculateBooksMessage() }}</p> js // 組件中 methods: { calculateBooksMessage() { return this.author.books.length > 0 ? 'Yes' : 'No' } } 若我們将同樣的函數定義爲一個方法而不是計(jì)算(suàn)屬性,兩種方式在結果上(shàng)确實是完全相同的,然而,不同之處在于計(jì)算(suàn)屬性值會(huì)基于其響應式依賴被緩存。一個計(jì)算(suàn)屬性僅會(huì)在其響應式依賴更新時(shí)才重新計(jì)算(suàn)。這(zhè)意味着隻要 author.books 不改變,無論多少次訪問 publishedBooksMessage 都會(huì)立即返回先前的計(jì)算(suàn)結果,而不用(yòng)重複執行 getter 函數。 這(zhè)也(yě)解釋了(le)爲什(shén)麽下(xià)面的計(jì)算(suàn)屬性永遠不會(huì)更新,因爲 Date.now() 并不是一個響應式依賴: js computed: { now() { return Date.now() } } 相比之下(xià),方法調用(yòng)總是會(huì)在重渲染發生時(shí)再次執行函數。 爲什(shén)麽需要緩存呢(ne)?想象一下(xià)我們有一個非常耗性能(néng)的計(jì)算(suàn)屬性 list,需要循環一個巨大(dà)的數組并做許多計(jì)算(suàn)邏輯,并且可能(néng)也(yě)有其他(tā)計(jì)算(suàn)屬性依賴于 list。沒有緩存的話(huà),我們會(huì)重複執行非常多次 list 的 getter,然而這(zhè)實際上(shàng)沒有必要!如果你(nǐ)确定不需要緩存,那麽也(yě)可以使用(yòng)方法調用(yòng)。 可寫計(jì)算(suàn)屬性

計(jì)算(suàn)屬性默認是隻讀的。當你(nǐ)嘗試修改一個計(jì)算(suàn)屬性時(shí),你(nǐ)會(huì)收到(dào)一個運行時(shí)警告。隻在某些(xiē)特殊場景中你(nǐ)可能(néng)才需要用(yòng)到(dào)“可寫”的屬性,你(nǐ)可以通過同時(shí)提供 getter 和(hé) setter 來(lái)創建: js export default { data() { return { firstName: 'John', lastName: 'Doe' } }, computed: { fullName: { // getter get() { return this.firstName + ' ' + this.lastName }, // setter set(newValue) { // 注意:我們這(zhè)裏使用(yòng)的是解構賦值語法 [this.firstName, this.lastName] = newValue.split(' ') } } } } 現(xiàn)在當你(nǐ)再運行 this.fullName = 'John Doe' 時(shí),setter 會(huì)被調用(yòng)而 this.firstName 和(hé) this.lastName 會(huì)随之更新。 最佳實踐

Getter 不應有副作(zuò)用(yòng)

計(jì)算(suàn)屬性的 getter 應隻做計(jì)算(suàn)而沒有任何其他(tā)的副作(zuò)用(yòng),這(zhè)一點非常重要,請(qǐng)務必牢記。舉例來(lái)說,不要在 getter 中做異步請(qǐng)求或者更改 DOM!一個計(jì)算(suàn)屬性的聲明(míng)中描述的是如何根據其他(tā)值派生一個值。因此 getter 的職責應該僅爲計(jì)算(suàn)和(hé)返回該值。在之後的指引中我們會(huì)讨論如何使用(yòng)監聽器根據其他(tā)響應式狀态的變更來(lái)創建副作(zuò)用(yòng)。 避免直接修改計(jì)算(suàn)屬性值

從(cóng)計(jì)算(suàn)屬性返回的值是派生狀态。可以把它看(kàn)作(zuò)是一個“臨時(shí)快(kuài)照”,每當源狀态發生變化時(shí),就會(huì)創建一個新的快(kuài)照。更改快(kuài)照是沒有意義的,因此計(jì)算(suàn)屬性的返回值應該被視(shì)爲隻讀的,并且永遠不應該被更改——應該更新它所依賴的源狀态以觸發新的計(jì)算(suàn)。

網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發
下(xià)一篇:Class 與 Style 綁定
上(shàng)一篇:響應式基礎