Vue 3 核心进阶:深度解析计算属性 (Computed)

在 Vue 3 的 Composition API 中,computed 是最常用且最强大的响应式工具之一。它不仅能简化模板逻辑,还能通过缓存机制极大地优化应用性能。

一、 什么是计算属性?

计算属性(Computed Properties)本质上是一个响应式的派生值。它可以基于一个或多个响应式引用(refreactive)进行计算,并返回一个新的只读或可读写的响应式对象。

核心特性:

  1. 声明式逻辑:将复杂的逻辑从模板(Template)中抽离。
  2. 响应式依赖追踪:Vue 会自动追踪计算属性用到了哪些响应式数据。
  3. 缓存(Caching):这是它与普通函数最大的区别。计算属性会基于它们的响应式依赖进行缓存。只有在相关依赖发生改变时它们才会重新求值。

二、 基础用法:只读计算属性

<script setup> 中,我们从 vue 包中导入 computed 函数。最常见的用法是传入一个 getter 函数。

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

const count = ref(0)
const price = ref(100)

// 创建一个计算属性:总价
// 只有当 count 或 price 改变时,totalPrice 才会重新计算
const totalPrice = computed(() => {
  console.log('计算中...') // 测试缓存:多次访问模板,此行只打印一次
  return count.value * price.value
})

const increment = () => count.value++
</script>

<template>
  <div>
    <p>单价: {{ price }} | 数量: {{ count }}</p>
    <p>总价 (计算属性): {{ totalPrice }}</p>
    <button @click="increment">增加数量</button>
  </div>
</template>

三、 进阶用法:可写计算属性 (Getter & Setter)

虽然计算属性默认是只读的,但在某些场景(如:双向绑定 V-Model)下,你可能需要修改它。这时可以传入一个带有 getset 函数的对象。

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

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

/**
 * 核心逻辑:可读写的计算属性
 */
const fullName = computed({
  // 1. getter: 当读取 fullName.value 时触发
  // 依赖项 firstName 或 lastName 改变,它会自动更新
  get() {
    return firstName.value + ' ' + lastName.value
  },

  // 2. setter: 当手动给 fullName.value 赋值时触发 (例如 v-model 改变了它)
  // 参数 newValue 是用户输入的最新的全名字符串
  set(newValue) {
    // 简单的解析逻辑:按空格拆分姓和名
    const names = newValue.split(' ')
    firstName.value = names[0] || ''
    lastName.value = names[1] || ''

    console.log('Setter 触发,新值已同步至响应式源数据')
  }
})
</script>

<template>

      <label>姓 (First Name): </label>
      <input v-model="firstName" type="text" /><br/>

      <label>名 (Last Name): </label>
      <input v-model="lastName" type="text" /><br/>


      <label><strong>全名 (Full Name - 可编辑): </strong></label>
      <input v-model="fullName" type="text" class="full-name-input" /><br/>

      <p>当前状态预览:</p>
      <code>{ "firstName": "{{ firstName }}", "lastName": "{{ lastName }}" }</code>

</template>

四、 计算属性 vs 监听器 vs 函数

特性 计算属性 (Computed) 监听器 (Watch) 普通函数 (Methods)
目的 派生出新状态(1变N/N变1) 执行副作用(如 API 请求、DOM 操作) 响应事件或处理临时逻辑
缓存
返回值 必须有返回值 通常没有返回值 视情况而定
懒执行 依赖不变不执行 默认立即执行或改变时执行 每次调用都执行

五、 最佳实践与注意事项

1. 避免副作用

计算属性的 getter 应该只做纯计算。不要在计算属性中修改 DOM、发起异步请求或修改其他的响应式状态。如果有这些需求,请使用 watch

2. 不要直接修改计算属性的返回值

除非你定义了 set,否则计算属性应该是“只读”的快照。应该修改它依赖的源数据来触发更新。

3. 性能优化

如果一个复杂的计算逻辑在页面中被多次引用,请务必使用计算属性而不是函数。缓存机制能避免重复的 CPU 消耗。


六、 实战案例:列表搜索过滤

下面是通过搜索用户的 Demo,展示了 computed 如何简化逻辑:

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

const searchText = ref('')
const users = ref([
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
])

// 过滤后的列表:自动随输入内容变化
const filteredUsers = computed(() => {
  return users.value.filter(user => 
    user.name.toLowerCase().includes(searchText.value.toLowerCase())
  )
})
</script>

<template>
  <input v-model="searchText" placeholder="搜索用户..." />
  <ul>
    <li v-for="user in filteredUsers" :key="user.id">{{ user.name }}</li>
  </ul>
</template>
posted @ 2026-01-04 01:03  雨中遐想  阅读(64)  评论(0)    收藏  举报