基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Vue中computed 和 watch 的区别及使用场景

知识点图片

在 Vue.js 中,computed (计算属性) 和 watch (侦听器) 都是用于响应数据变化的工具,但它们的设计理念、行为机制和适用场景有显著的区别。

以下是详细的对比分析:

1. 核心区别总结表

特性 Computed (计算属性) Watch (侦听器)
是否有缓存 (基于响应式依赖缓存) (每次变化都会执行)
是否支持异步 不支持 (必须同步返回结果) 支持 (可以执行异步操作,如 API 请求)
侧重点 得到一个新值 (数据转换) 执行一个动作 (副作用/逻辑处理)
依赖关系 多对一 (多个数据影响一个结果) 一对多 (一个数据变化影响多个逻辑)
调用方式 像属性一样在模板中调用 (不加括号) 自动触发,不需要手动调用
性能 高 (只有依赖变化时才重新计算) 视具体逻辑而定 (频繁触发可能影响性能)

2. 详细解析

Computed (计算属性)

  • 定义:它是基于现有的数据(data/props)计算衍生出新的数据。
  • 缓存机制:这是 computed 最重要的特性。只要它依赖的数据没有发生变化,多次访问 computed 属性会立即返回之前的计算结果,而不会重新执行函数。
  • 必须有返回值:它必须 return 一个值,用于在模板或其他地方使用。

Watch (侦听器)

  • 定义:它用于观察和响应 Vue 实例上的数据变动。当需要在数据变化时执行异步开销较大的操作时,这个方式是最有用的。
  • 无缓存:数据变一次,回调函数就执行一次。
  • 不一定需要返回值:它的目的是执行逻辑(比如发请求、操作 DOM、存 LocalStorage),而不是产出数据。
  • 高级配置:支持 deep (深度监听对象内部变化) 和 immediate (初始化时立即执行一次)。

3. 使用场景 (When to use what?)

✅ 使用 Computed 的场景

场景:当你需要根据现有的数据生成一个新的数据时。

  1. 数据格式化:例如将 firstNamelastName 拼接成 fullName
  2. 数据过滤/排序:例如根据搜索关键词过滤一个列表,或者对商品价格进行排序。
  3. 样式类名计算:根据多个状态(如 isActive, isDisabled, hasError)动态生成复杂的 class 对象。
  4. 购物车总价:依赖商品数量和单价,自动计算总金额。

✅ 使用 Watch 的场景

场景:当数据变化时,你需要执行“副作用” (Side Effects) 或异步操作时。

  1. 异步操作 (API 请求):例如搜索框输入内容变化后,去服务器拉取搜索结果。
  2. DOM 操作:数据变化后,需要手动操作 DOM(例如初始化图表、滚动条位置)。
  3. 复杂逻辑判断:当数据变化需要触发一系列复杂的业务流程,且不只是为了得到一个值。
  4. 监听路由变化:在组件内监听 $route 对象的变化来重新获取数据。

4. 代码示例对比

示例 1:Computed (拼接姓名)

这里适合用 computed,因为我们只是想要一个新的字符串,且依赖于 firstNamelastName

javascript
<template>
  <div>{{ fullName }}</div>
</template>

<script>
export default {
  data() {
    return {
      firstName: 'Foo',
      lastName: 'Bar'
    }
  },
  computed: {
    // 只有当 firstName 或 lastName 改变时,fullName 才会重新计算
    // 多次读取 fullName 不会重复执行函数
    fullName() {
      return this.firstName + ' ' + this.lastName;
    }
  }
}
</script>

示例 2:Watch (搜索功能)

这里适合用 watch,因为我们需要在输入变化时发起网络请求(异步操作),这是 computed 做不到的。

javascript
<template>
  <input v-model="question" />
</template>

<script>
export default {
  data() {
    return {
      question: '',
      answer: '等待输入...'
    }
  },
  watch: {
    // 只要 question 发生改变,这个函数就会执行
    question(newQuestion, oldQuestion) {
      this.getAnswer();
    }
  },
  methods: {
    getAnswer() {
      this.answer = '思考中...';
      // 模拟异步 API 请求
      setTimeout(() => {
        this.answer = '这是 API 返回的结果';
      }, 500);
    }
  }
}
</script>

5. 总结原则

  • 能用 computed 解决的,尽量用 computed。因为它更简洁、声明式,且有缓存优化,性能更好。
  • 只有当需要执行异步操作,或者在数据变化时执行开销较大的操作(而不是仅仅为了得到一个值)时,才使用 watch
00:00
00:00