重要提示:文章只适合初学者,不适合专家!!!
想象你在开发一个购物车功能。当用户选择商品时,你需要:
你会怎么做?在模板中写表达式?
<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的智能数据处理器:
// 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>
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) // 无打印 → 从缓存返回30
a.value = 15 // 更新依赖
console.log(computedSum.value) // "计算属性执行" → 35
console.log(computedSum.value) // 无打印 → 从缓存返回35
// 封装复杂的产品过滤逻辑
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)
})
})
原因:依赖项没有正确响应式
const obj = { count: 0 }
// ❌ 错误 - 原始对象不是响应式
const doubled = computed(() => obj.count * 2)
// ✅ 正确 - 使用reactive包装
const reactiveObj = reactive({ count: 0 })
const doubled = computed(() => reactiveObj.count * 2)
场景 | 选择 | 原因 |
---|---|---|
依赖响应式数据的计算 | 计算属性 | 自动缓存优化性能 |
数据转换或格式化 | 计算属性 | 更清晰的模板语法 |
需要参数的运算 | 方法 | 计算属性不接受参数 |
事件处理 | 方法 | 与事件配合使用 |
一次性的复杂运算 | 方法 | 避免不必要的响应式依赖 |
在以下场景优先选择计算属性:
记住计算属性的核心价值:
“计算属性不是普通的函数,而是具有智能缓存功能的响应式数据处理器”