Skip to content

计算属性 computed

计算属性是Vue3中的一个重要特性,它允许你基于响应式数据计算出新的值,并自动缓存计算结果。本章节将详细介绍Vue3中计算属性的使用方法和最佳实践。

什么是计算属性?

计算属性是基于响应式数据计算出来的值,它会缓存计算结果,只有当依赖的响应式数据发生变化时才会重新计算。

计算属性的基本使用

1. 定义计算属性

在Vue3的组合式API中,我们使用 computed 函数来定义计算属性:

vue
<template>
  <div>
    <input v-model="firstName" type="text">
    <input v-model="lastName" type="text">
    <p>Full name: {{ fullName }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`
})
</script>

2. 访问计算属性

计算属性可以像普通的响应式数据一样在模板中使用:

vue
<template>
  <div>
    <p>Full name: {{ fullName }}</p>
  </div>
</template>

计算属性的特性

1. 缓存

计算属性会缓存计算结果,只有当依赖的响应式数据发生变化时才会重新计算:

vue
<template>
  <div>
    <p>Full name: {{ fullName }}</p>
    <p>Full name: {{ fullName }}</p>
    <p>Full name: {{ fullName }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed(() => {
  console.log('Computing full name...')
  return `${firstName.value} ${lastName.value}`
})
</script>

在上面的例子中,虽然我们在模板中多次使用了 fullName,但计算函数只会执行一次,因为计算结果被缓存了。

2. 响应式

计算属性是响应式的,当依赖的响应式数据发生变化时,计算属性会自动重新计算:

vue
<template>
  <div>
    <input v-model="firstName" type="text">
    <input v-model="lastName" type="text">
    <p>Full name: {{ fullName }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`
})
</script>

当你修改 firstNamelastName 时,fullName 会自动更新。

计算属性的 setter

计算属性默认只有 getter,但你也可以为计算属性添加 setter:

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

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (value) => {
    const [first, last] = value.split(' ')
    firstName.value = first
    lastName.value = last
  }
})
</script>

计算属性的使用场景

1. 数据格式化

vue
<template>
  <div>
    <p>Original price: {{ price }}</p>
    <p>Formatted price: {{ formattedPrice }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const price = ref(199.99)

const formattedPrice = computed(() => {
  return `$${price.value.toFixed(2)}`
})
</script>

2. 数据过滤

vue
<template>
  <div>
    <input v-model="search" type="text" placeholder="Search">
    <ul>
      <li v-for="item in filteredItems" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const items = ref([
  { id: 1, name: 'Apple' },
  { id: 2, name: 'Banana' },
  { id: 3, name: 'Orange' },
  { id: 4, name: 'Mango' }
])

const search = ref('')

const filteredItems = computed(() => {
  return items.value.filter(item => 
    item.name.toLowerCase().includes(search.value.toLowerCase())
  )
})
</script>

3. 数据计算

vue
<template>
  <div>
    <input v-model="num1" type="number">
    <input v-model="num2" type="number">
    <p>Sum: {{ sum }}</p>
    <p>Difference: {{ difference }}</p>
    <p>Product: {{ product }}</p>
    <p>Quotient: {{ quotient }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const num1 = ref(10)
const num2 = ref(5)

const sum = computed(() => num1.value + num2.value)
const difference = computed(() => num1.value - num2.value)
const product = computed(() => num1.value * num2.value)
const quotient = computed(() => num1.value / num2.value)
</script>

4. 状态派生

vue
<template>
  <div>
    <p>Cart items: {{ cart.length }}</p>
    <p>Total price: {{ totalPrice }}</p>
    <p>Is empty: {{ isEmpty }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const cart = ref([
  { id: 1, name: 'Product 1', price: 100 },
  { id: 2, name: 'Product 2', price: 200 },
  { id: 3, name: 'Product 3', price: 300 }
])

const totalPrice = computed(() => {
  return cart.value.reduce((total, item) => total + item.price, 0)
})

const isEmpty = computed(() => cart.value.length === 0)
</script>

计算属性 vs 方法

计算属性

  • 缓存:计算结果会被缓存,只有当依赖的响应式数据发生变化时才会重新计算
  • 响应式:自动响应依赖数据的变化
  • 使用方式:像普通数据一样在模板中使用

方法

  • 无缓存:每次调用都会重新执行
  • 手动调用:需要手动调用方法
  • 使用方式:在模板中通过函数调用的方式使用

选择建议

  • 计算属性:当需要基于响应式数据计算新值,且计算逻辑较复杂时使用
  • 方法:当需要执行一些操作,且不需要缓存结果时使用

计算属性的最佳实践

1. 保持计算属性简洁

计算属性应该只做一件事,保持简洁明了:

javascript
// 好的做法
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`
})

// 不好的做法
const fullName = computed(() => {
  console.log('Computing full name...')
  const fullName = `${firstName.value} ${lastName.value}`
  localStorage.setItem('fullName', fullName)
  return fullName
})

2. 避免在计算属性中修改状态

计算属性应该是纯函数,不应该修改状态:

javascript
// 好的做法
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`
})

// 不好的做法
const fullName = computed(() => {
  const result = `${firstName.value} ${lastName.value}`
  // 不要在计算属性中修改状态
  firstName.value = 'John' // 这是错误的
  return result
})

3. 合理使用计算属性的 setter

只有当你需要双向绑定计算属性时才使用 setter:

javascript
// 当需要双向绑定时使用 setter
const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (value) => {
    const [first, last] = value.split(' ')
    firstName.value = first
    lastName.value = last
  }
})

// 当不需要双向绑定时,只使用 getter
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`
})

4. 避免在计算属性中执行异步操作

计算属性应该是同步的,不应该执行异步操作:

javascript
// 不好的做法
const data = computed(async () => {
  const response = await fetch('https://api.example.com/data')
  return await response.json()
})

// 正确的做法
const data = ref(null)
const isLoading = ref(true)

async function fetchData() {
  isLoading.value = true
  try {
    const response = await fetch('https://api.example.com/data')
    data.value = await response.json()
  } catch (error) {
    console.error(error)
  } finally {
    isLoading.value = false
  }
}

// 组件挂载时调用
onMounted(fetchData)

总结

计算属性是Vue3中的一个重要特性,它允许你基于响应式数据计算出新的值,并自动缓存计算结果。通过计算属性,你可以使模板更加简洁,逻辑更加清晰,同时提高应用的性能。

在使用计算属性时,你应该保持计算属性的简洁性,避免在计算属性中修改状态,合理使用计算属性的 setter,以及避免在计算属性中执行异步操作。

在后续的章节中,我们将学习Vue3的监听属性,以及它的使用方法和最佳实践。

© 2026 编程马·菜鸟教程 版权所有