深入解析 Vue 3 中的 `computed` 以及相关知识点

深入解析 Vue 3 中的 computed 以及相关知识点

一、引言

在 Vue.js 中,computed 属性用于定义计算属性,是一个基于响应式依赖的缓存值,只有当依赖的数据变化时才会重新计算。它是构建高效、性能优异的 Vue 应用的重要工具。

Vue 3 通过 Composition API 为 computed 提供了更灵活的用法和更强的可扩展性。本文将深入讲解 Vue 3 中 computed 的用法及其相关知识点,并提供基于 语法糖 的完整示例,帮助你快速掌握。


二、computed 的基础用法

在 Vue 3 中,computed 是通过 @vue/reactivity 提供的一个函数,用于创建响应式的计算属性。

1. 定义只读计算属性

示例代码

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

// 定义响应式数据
const firstName = ref('张')
const lastName = ref('三')

// 定义计算属性
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
</script>

<template>
  <div>
    <p>名字:{{ fullName }}</p>
    <input v-model="firstName" placeholder="姓氏" />
    <input v-model="lastName" placeholder="名字" />
  </div>
</template>

输出说明

  • fullName 是一个基于 firstNamelastName 计算得出的值。
  • firstNamelastName 更新时,fullName 会自动重新计算并更新到视图中。

2. 定义可写计算属性

在某些情况下,我们需要允许计算属性被写入。可以通过 getset 配合实现。

示例代码

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

const firstName = ref('张')
const lastName = ref('三')

// 定义可读写的计算属性
const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (value) => {
    const [first, last] = value.split(' ')
    firstName.value = first || ''
    lastName.value = last || ''
  }
})
</script>

<template>
  <div>
    <p>名字:{{ fullName }}</p>
    <input v-model="fullName" placeholder="全名" />
  </div>
</template>

输出说明

  • fullName 支持双向绑定:可以从输入框中更新 firstNamelastName 的值。

三、computedwatch 的对比

1. 功能上的区别
特性computedwatch
用途依赖值变化时,自动返回计算后的新值监控一个或多个响应式数据的变化,并执行回调函数
是否有返回值有,始终返回计算结果无,回调函数不返回值
是否缓存是,只有依赖发生变化时才会重新计算否,每次依赖值变化时都会执行回调
2. 选择何时使用
  • 使用 computed:当需要基于一个或多个数据源计算新值,并在模板中直接使用时。
  • 使用 watch:当需要执行副作用操作(如调用 API、写日志等)时。

四、computed 的高级用法

1. 依赖多重数据

计算属性可以依赖多个响应式数据,并自动跟踪这些依赖。

示例代码

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

const items = ref([
  { name: '苹果', price: 3 },
  { name: '香蕉', price: 2 },
  { name: '橙子', price: 4 }
])

// 计算总价格
const totalPrice = computed(() => items.value.reduce((sum, item) => sum + item.price, 0))
</script>

<template>
  <div>
    <ul>
      <li v-for="item in items" :key="item.name">{{ item.name }}: {{ item.price }} 元</li>
    </ul>
    <p>总价:{{ totalPrice }} 元</p>
  </div>
</template>

说明

  • totalPrice 会根据 items 的变化自动更新。
  • 在 Vue 中,你不需要手动声明依赖关系,computed 会自动追踪依赖。

2. 配合 watchEffect 使用

有时需要在计算属性中依赖外部副作用的场景,可以配合 watchEffect 使用(副作用是指任何会影响外部状态的行为,比如打印日志,发起网络请求,操作DOM,调用外部API)。

示例代码

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

const basePrice = ref(100)
const discount = ref(10)

const finalPrice = computed(() => basePrice.value - discount.value)

// 打印计算过程
watchEffect(() => {
  console.log(`基础价格: ${basePrice.value}, 折扣: ${discount.value}, 最终价格: ${finalPrice.value}`)
})
</script>

<template>
  <div>
    <p>最终价格:{{ finalPrice }}</p>
    <input v-model.number="basePrice" type="number" placeholder="基础价格" />
    <input v-model.number="discount" type="number" placeholder="折扣" />
  </div>
</template>

五、computed 的原理解析

Vue 3 中的 computed 是基于响应式系统实现的,其原理大致如下:

  1. 依赖收集:在 computedgetter 函数中访问响应式数据时,会自动注册对这些数据的依赖。
  2. 懒惰计算computed 默认采用 惰性求值 策略,只有当计算属性被访问时,才会重新计算。
  3. 缓存机制computed 会缓存计算结果,只有在依赖值发生变化时,才会重新计算。

核心源码(简化版):

function computed(getter) {
  let cachedValue
  let dirty = true

  const effect = new ReactiveEffect(getter, () => {
    dirty = true
  })

  return {
    get value() {
      if (dirty) {
        cachedValue = effect.run()
        dirty = false
      }
      return cachedValue
    }
  }
}

六、常见问题与优化

1. 不要在 computed 中执行副作用

错误示例

const invalid = computed(() => {
  console.log('执行副作用') // 不推荐
  return someValue
})

优化建议

  • 将副作用逻辑放在 watchwatchEffect 中。
2. 避免复杂计算

计算属性过于复杂可能导致性能问题。建议将复杂逻辑拆分成多个小的 computed 属性。


七、总结

  • computed 是 Vue 3 中高效管理依赖关系的重要工具,通过缓存和懒加载提高性能。
  • 它适合处理基于响应式数据的派生状态,并提供只读和可写两种模式。
  • watch 相比,computed 更适合用于模板中的派生值计算,而 watch 更适合处理副作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值