前言
重要提示:文章只適合初學者,不適合專家!!!
為什么需要計算屬性?
想象你在開發一個購物車功能。當用戶選擇商品時,你需要:
- 計算商品總價
- 根據折扣碼調整價格
- 自動更新免運費狀態
- 顯示稅費金額
你會怎么做?在模板中寫表達式?
<!-- 反例:模板中復雜邏輯 -->
<p>總價:¥{{ (items.reduce((sum, item) => sum + item.price * item.quantity, 0) * (1 - discountRate)) }}
</p>
<p v-if="(items.reduce((sum, item) => sum + item.price * item.quantity, 0) * (1 - discountRate)) > 100">已免運費
</p>
這種寫法存在三個嚴重問題:
- 重復代碼:相同邏輯在多個地方重復
- 難以維護:業務邏輯分散在模板中
- 性能浪費:每次渲染都重新計算
這就是計算屬性的用武之地!
計算屬性是什么?
計算屬性是Vue的智能數據處理器:
- 它能根據其他響應式數據自動計算新值
- 會緩存計算結果,避免重復計算
- 在模板中使用像普通屬性一樣簡單
- 代碼集中管理,易于維護
計算屬性使用五步法
第一步:從vue引入computed
// 1. 必須先從vue中引入computed
import { ref, computed } from 'vue'
第二步:定義響應式數據
// 2. 創建響應式基礎數據
const price = ref(100) // 商品單價
const quantity = ref(2) // 購買數量
第三步:創建計算屬性
// 3. 使用computed()函數創建計算屬性
const subtotal = computed(() => {// 簡單的計算邏輯:單價 × 數量return price.value * quantity.value
})
第四步:創建更復雜的計算屬性
// 4. 可創建依賴其他計算屬性的計算屬性
const discountRate = ref(0.2) // 折扣率20%const total = computed(() => {// 打折后金額:小計 × (1 - 折扣率)return subtotal.value * (1 - discountRate.value)
})
第五步:在模板中使用
<template><div class="cart"><!-- 直接像普通數據一樣使用計算屬性 --><p>單價: ¥{{ price }}</p><p>數量: {{ quantity }}</p><p>小計: ¥{{ subtotal }}</p><p>折扣率: {{ discountRate * 100 }}%</p><!-- 使用計算結果自動更新 --><p class="total">實付: ¥{{ total }}</p></div>
</template>
使用計算屬性的改進方案
<script setup>
import { reactive, computed } from 'vue'const cart = reactive({items: [{ id: 1, name: 'Vue教程', price: 99, quantity: 2 },{ id: 2, name: 'React手冊', price: 89, quantity: 1 }],discountRate: 0.1 // 10%折扣
})// 1. 計算總價(未打折)
const subtotal = computed(() => {return cart.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
})// 2. 計算最終價格(打折后)
const total = computed(() => {return subtotal.value * (1 - cart.discountRate)
})// 3. 判斷是否免運費
const freeShipping = computed(() => {return total.value > 100
})// 4. 計算稅費(復雜規則)
const tax = computed(() => {if (freeShipping.value) {return total.value * 0.08 // 免運費稅率8%}return total.value * 0.1 // 普通稅率10%
})
</script><template><div><p>商品小計:¥{{ subtotal }}</p><p>折扣后價格:¥{{ total }}</p><p v-if="freeShipping">🎉 已免運費!</p><p>稅費:¥{{ tax }}</p></div>
</template>
計算屬性的優勢
1. 自動依賴追蹤與緩存
const a = ref(10)
const b = ref(20)// 每次訪問都會執行計算
function regularSum() {console.log('函數執行')return a.value + b.value
}// 只有依賴變更時才重新計算
const computedSum = computed(() => {console.log('計算屬性執行')return a.value + b.value
})
測試結果:
console.log(computedSum.value) // "計算屬性執行" → 30
console.log(computedSum.value) // 無打印 → 從緩存返回30a.value = 15 // 更新依賴console.log(computedSum.value) // "計算屬性執行" → 35
console.log(computedSum.value) // 無打印 → 從緩存返回35
2. 復雜邏輯封裝
// 封裝復雜的產品過濾邏輯
const filteredProducts = computed(() => {return products.value.filter(p => p.stock > 0) // 過濾有庫存的.filter(p => p.price <= maxPrice.value) // 價格篩選.sort((a, b) => { // 排序if (sortBy.value === 'price') {return a.price - b.price}return a.name.localeCompare(b.name)})
})
常見問題與解決方案
問題1:計算屬性不更新
原因:依賴項沒有正確響應式
const obj = { count: 0 }// ? 錯誤 - 原始對象不是響應式
const doubled = computed(() => obj.count * 2) // ? 正確 - 使用reactive包裝
const reactiveObj = reactive({ count: 0 })
const doubled = computed(() => reactiveObj.count * 2)
問題2:何時使用計算屬性 vs 方法
場景 | 選擇 | 原因 |
---|---|---|
依賴響應式數據的計算 | 計算屬性 | 自動緩存優化性能 |
數據轉換或格式化 | 計算屬性 | 更清晰的模板語法 |
需要參數的運算 | 方法 | 計算屬性不接受參數 |
事件處理 | 方法 | 與事件配合使用 |
一次性的復雜運算 | 方法 | 避免不必要的響應式依賴 |
總結:何時使用計算屬性?
在以下場景優先選擇計算屬性:
- 數據依賴計算:當需要基于其他響應式數據計算新值
- 模板格式化:需要格式化顯示的數據
- 性能優化:避免重復執行高開銷操作
- 代碼組織:集中管理邏輯,提高可讀性
記住計算屬性的核心價值:
“計算屬性不是普通的函數,而是具有智能緩存功能的響應式數據處理器”