Vue3 computed 属性(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言:为什么需要学习 Vue3 computed 属性?

在前端开发领域,Vue.js 作为主流框架之一,其响应式系统一直是开发者关注的核心特性。Vue3 作为 Vue.js 的重大升级版本,引入了 Composition API 和大量性能优化。在众多新特性中,computed 属性(计算属性)因其高效、简洁的特性,成为构建复杂 UI 逻辑的重要工具。

对于编程初学者而言,理解 computed 属性可以帮助快速掌握 Vue3 的响应式原理;而中级开发者则可以通过深入分析其底层机制,优化代码性能,提升开发效率。本文将通过循序渐进的方式,结合代码示例和实际场景,带您全面掌握 computed 属性的使用与原理。


一、基础概念:什么是 Vue3 computed 属性?

1.1 计算属性的定义与作用

计算属性(Computed Property) 是 Vue3 中用于处理响应式数据的函数,其核心作用是根据其他响应式数据的值,动态生成新的值。与普通方法不同,计算属性具有以下特点:

  • 依赖追踪:自动追踪被访问的响应式数据
  • 缓存机制:仅在依赖数据变化时重新计算
  • 响应式输出:输出值会自动触发视图更新

形象比喻:可以将计算属性视为一个“智能计算器”。例如,当需要计算购物车总价时,计算属性会自动跟踪商品数量和单价的变化,并在数据变动时重新计算总价,而非每次渲染都执行计算。

1.2 基本语法与声明方式

在 Vue3 中,computed 属性主要通过 computed 函数或 setup 语法糖进行声明。以下是两种常见写法:

方法一:使用 computed 函数

import { ref, computed } from 'vue';

export default {
  setup() {
    const price = ref(100);
    const quantity = ref(2);
    
    const total = computed(() => price.value * quantity.value);
    
    return {
      price,
      quantity,
      total
    };
  }
}

方法二:组合式 API 的 computed 属性

import { ref, computed } from 'vue';

export default {
  setup() {
    const price = ref(100);
    const quantity = ref(2);
    
    const total = computed({
      get() {
        return price.value * quantity.value;
      },
      set(newValue) {
        // 可选:设置双向绑定逻辑
      }
    });
    
    return {
      price,
      quantity,
      total
    };
  }
}

1.3 计算属性与方法的区别

特性计算属性(Computed)普通方法(Methods)
依赖追踪自动追踪响应式数据变化需手动触发或依赖事件
缓存机制仅在依赖变化时重新计算每次调用都会执行
使用场景需要频繁读取且依赖稳定的数据处理一次性或无依赖的逻辑
响应式输出输出值自动更新视图需手动触发更新

二、核心原理:Vue3 computed 的响应式机制

2.1 依赖追踪的实现原理

Vue3 的响应式系统基于 Proxy 对象实现,而 computed 属性的依赖追踪分为以下步骤:

  1. 依赖收集:当计算属性被访问时,Vue3 会记录当前被访问的响应式数据
  2. 触发更新:当被记录的响应式数据变化时,计算属性会重新执行并更新缓存值
  3. 视图更新:新值会自动触发依赖该计算属性的组件视图重渲染

形象比喻:就像快递员跟踪包裹状态,计算属性会持续关注其依赖的数据变化。当包裹(数据)状态更新时,计算属性会立即重新计算物流信息(新值)并通知收件人(视图)。

2.2 缓存机制的性能优势

计算属性的缓存特性使其在复杂场景中表现优异。例如,当需要对大量数据进行聚合计算时:

// 假设有一个包含1000条商品的数组
const products = ref([{ price: 100 }, { price: 200 }, ...]);

// 普通方法(无缓存)
const total = () => {
  return products.value.reduce((sum, item) => sum + item.price, 0);
};

// 计算属性(有缓存)
const totalComputed = computed(() => 
  products.value.reduce((sum, item) => sum + item.price, 0)
);

products 数组未被修改时,调用 totalComputed.value 会直接返回缓存值,避免重复执行计算密集型操作。

2.3 响应式输出的实现

计算属性的值会被包装为响应式对象,其依赖的组件视图会自动订阅该值的变化。例如:

<template>
  <div>Total: {{ totalComputed }}</div>
</template>

totalComputed 的值变化时,Vue3 的渲染系统会自动更新对应 DOM 内容。


三、使用场景与最佳实践

3.1 常见应用场景

场景一:动态数据聚合

const items = ref([10, 20, 30]);
const sum = computed(() => items.value.reduce((a, b) => a + b, 0));

场景二:条件过滤

const users = ref([{ active: true }, { active: false }, ...]);
const activeUsers = computed(() => 
  users.value.filter(user => user.active)
);

场景三:格式化数据

const birthDate = ref('1990-01-01');
const formattedDate = computed(() => 
  birthDate.value.split('-').reverse().join('/')
);

3.2 高级技巧与注意事项

技巧一:结合 watchEffect 实现双向绑定

const originalText = ref('');
const formattedText = computed({
  get() {
    return originalText.value.toUpperCase();
  },
  set(newValue) {
    originalText.value = newValue.toLowerCase();
  }
});

技巧二:避免副作用与复杂计算

  • 避免副作用:计算属性应仅依赖响应式数据,避免包含网络请求或DOM操作
  • 拆分复杂逻辑:当计算涉及多层依赖时,建议拆分为多个计算属性

注意事项

  • 避免循环依赖:多个计算属性互相依赖可能导致无限循环
  • 合理使用 shallowRef:当处理嵌套对象时,考虑使用 shallowRef 优化性能

四、实际案例:构建带搜索功能的 Todo List

4.1 需求分析

实现一个包含以下功能的 Todo List:

  1. 输入框添加待办事项
  2. 搜索框过滤待办事项
  3. 显示已完成/未完成的统计信息

4.2 代码实现

import { ref, computed } from 'vue';

export default {
  setup() {
    const todos = ref([]);
    const newTodo = ref('');
    const searchQuery = ref('');

    // 添加待办事项
    const addTodo = () => {
      if (newTodo.value) {
        todos.value.push({
          text: newTodo.value,
          completed: false
        });
        newTodo.value = '';
      }
    };

    // 计算属性:过滤后的待办列表
    const filteredTodos = computed(() => 
      todos.value.filter(todo => 
        todo.text.includes(searchQuery.value)
      )
    );

    // 计算属性:统计已完成数量
    const completedCount = computed(() => 
      todos.value.filter(todo => todo.completed).length
    );

    return {
      todos,
      newTodo,
      searchQuery,
      addTodo,
      filteredTodos,
      completedCount
    };
  }
};

4.3 模板部分

<template>
  <div>
    <input v-model="newTodo" placeholder="输入新待办事项" />
    <button @click="addTodo">添加</button>
    
    <input v-model="searchQuery" placeholder="搜索待办事项" />
    
    <ul>
      <li v-for="todo in filteredTodos" :key="todo.text">
        <input type="checkbox" v-model="todo.completed" />
        {{ todo.text }}
      </li>
    </ul>
    
    <p>已完成:{{ completedCount }} / {{ todos.length }}</p>
  </div>
</template>

五、进阶话题:与其它特性结合使用

5.1 结合 watch 监听计算属性

import { watch } from 'vue';

watch(() => {
  // 监听多个响应式数据
  return [todos.value, searchQuery.value];
}, (newValues) => {
  // 执行异步操作或数据持久化
});

5.2 在 provide/inject 中使用

// 父组件
const filteredTodos = computed(() => ...);
provide('filteredTodos', filteredTodos);

// 子组件
const filteredTodos = inject('filteredTodos');

5.3 结合 TypeScript 类型推导

const filteredTodos = computed<string[]>(() => 
  todos.value.filter(todo => todo.text.includes(searchQuery.value))
);

结论:掌握 Vue3 computed 属性的实用价值

通过本文的讲解,我们系统学习了 Vue3 computed 属性的核心概念、实现原理及应用场景。以下是关键总结:

  1. 响应式计算:通过依赖追踪和缓存机制,实现高效的数据处理
  2. 代码简洁性:将复杂逻辑封装为声明式代码,提升可维护性
  3. 性能优化:避免重复计算,降低组件渲染开销
  4. 生态整合:与 Vue3 的其他特性(如 watchprovide/inject)无缝衔接

对于开发者而言,掌握 Vue3 computed 属性 是构建大型单页应用的必备技能。建议通过实际项目不断实践,结合本文案例深入理解其工作原理。当您需要动态计算、过滤或转换数据时,优先考虑使用计算属性,让代码更优雅、高效!


提示:本文通过代码示例和场景分析,系统讲解了 Vue3 computed 属性的使用方法与原理。建议读者在实际开发中多加实践,结合项目需求灵活运用这一强大工具。

最新发布