计算属性和侦听器
loyalvi Lv7

计算属性和侦听器

计算属性和侦听器

Vue 的计算属性(Computed Properties)和侦听器(Watchers)都是用于基于数据的派生状态的工具,但它们在功能和使用场景上有一些关键区别。以下是它们的主要区别和适用场景:

1. 计算属性(Computed Properties)

1.1 定义

计算属性是基于 Vue 实例的数据动态计算得到的值。它依赖于 Vue 的响应式系统,当计算属性所依赖的数据发生变化时,计算属性会自动重新计算。

1.2 特点

  • 缓存机制:计算属性具有缓存特性。只有当计算属性所依赖的响应式数据发生变化时,才会重新计算。如果依赖的数据没有变化,计算属性会直接返回缓存的结果,避免不必要的重复计算。
  • 依赖响应式数据:计算属性依赖于 Vue 的响应式数据(如 data 中的属性)。如果依赖的数据未被 Vue 的响应式系统追踪,计算属性也不会触发更新。
  • 同步更新:计算属性是同步的。它会在依赖数据变化时立即更新。

1.3 使用场景

计算属性适用于基于现有数据派生出新数据的场景。例如:

  • 格式化数据(如将日期格式化为特定格式)。
  • 计算总和、平均值等。
  • 根据用户输入动态生成内容。
    示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    };
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    }
  }
};

2. 侦听器(Watchers)

2.1 定义

侦听器用于观察 Vue 实例上的数据,并在数据变化时执行异步或开销较大的操作。它允许开发者对数据的变化做出更复杂的响应。

2.2 特点

  • 无缓存机制:侦听器不会缓存结果。每次依赖的数据发生变化时,侦听器都会执行指定的回调函数。
  • 异步或复杂操作:侦听器适合执行异步操作(如 API 请求)或复杂逻辑,这些操作可能不适合在计算属性中完成。
  • 手动触发更新:侦听器需要手动触发更新逻辑,计算属性则会自动更新。

2.3 使用场景

侦听器适用于以下场景:

  • 执行异步操作(如根据用户输入查询数据库)。
  • 执行复杂的逻辑(如根据多个数据源更新状态)。
  • 需要延迟更新的场景(如防抖或节流)。
    示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default {
  data() {
    return {
      searchQuery: ''
    };
  },
  watch: {
    searchQuery(newVal, oldVal) {
      if (newVal !== oldVal) {
        this.fetchSearchResults(newVal);
      }
    }
  },
  methods: {
    fetchSearchResults(query) {
      console.log(`Fetching results for: ${query}`);
      // 模拟 API 请求
    }
  }
};

3. 计算属性与侦听器的区别

特性 计算属性(Computed) 侦听器(Watchers)
缓存机制 有缓存,依赖数据未变化时直接返回缓存结果 无缓存,每次数据变化都会执行回调函数
更新机制 同步更新,依赖数据变化时立即更新 可以同步或异步更新,适合复杂逻辑
适用场景 基于现有数据派生新数据,格式化数据等 执行异步操作、复杂逻辑、防抖/节流等
依赖响应式数据 是,依赖 Vue 的响应式系统 是,依赖 Vue 的响应式系统
代码复杂度 简单,适合直接基于数据的计算 更灵活,适合需要手动处理的复杂场景

4. 总结

  • 计算属性:适用于基于现有数据派生新数据的场景,具有缓存机制,适合同步更新。
  • 侦听器:适用于需要执行异步操作或复杂逻辑的场景,无缓存机制,适合手动触发更新。
    在实际开发中,可以根据需求选择合适的工具。如果需要基于现有数据派生新数据,优先使用计算属性;如果需要执行复杂逻辑或异步操作,使用侦听器。

Vue 3 中 watchEffectcomputed 的底层实现及区别

1. 底层实现

1.1 watchEffect

watchEffect 是 Vue 3 引入的响应式 API,用于自动追踪函数内部的响应式依赖,并在这些依赖发生变化时重新执行该函数。它的底层实现基于 ReactiveEffect 类,通过依赖收集机制自动追踪函数内部访问的响应式数据。

  • watchEffect 被调用时,它会创建一个 ReactiveEffect 实例,并将传入的函数作为副作用函数。
  • 在副作用函数执行过程中,访问的响应式数据会被收集为依赖。
  • 当依赖发生变化时,ReactiveEffect 会触发副作用函数重新执行。

1.2 computed

computed 是基于响应式系统实现的计算属性,其底层也依赖于 ReactiveEffect。它的实现原理如下:

  • computed 接收一个 getter 函数,并返回一个只读的响应式引用对象。
  • 在访问计算属性时,会触发 getter 函数的执行,并将当前计算属性添加到依赖列表中。
  • 当计算属性的依赖数据发生变化时,会触发 setter 函数,重新计算并更新计算属性的值。

2. 区别

2.1 使用场景

  • computed
        - 用于基于响应式数据派生出新的值,适合简单的计算逻辑。
        - 计算结果会被缓存,只有当依赖的响应式数据发生变化时才会重新计算。
        - 返回值是一个只读的响应式引用对象。
  • watchEffect
        - 用于自动追踪函数内部的响应式依赖,并在依赖变化时执行副作用。
        - 不需要显式指定依赖,适合复杂的副作用逻辑。
        - 返回一个停止侦听的函数。

2.2 执行时机

  • computed
        - 是惰性的,只有当计算属性被访问时才会执行 getter 函数。
        - 依赖不变时不会重新计算,避免不必要的性能开销。
  • watchEffect
        - 是立即执行的,会在定义时立即运行一次。
        - 每次依赖变化时都会重新执行。

2.3 依赖追踪

  • computed
        - 需要明确指定依赖,依赖于响应式数据或计算属性。
  • watchEffect
        - 自动追踪函数内部访问的响应式数据,不需要显式指定。

2.4 返回值

  • computed
        - 返回一个只读的响应式引用对象,通过 .value 访问。
  • watchEffect
        - 返回一个停止侦听的函数,用于手动停止监听。

3. 总结

  • computed
        - 适用于基于响应式数据派生新值的场景,具有缓存机制,性能优化。
        - 适合简单的计算逻辑,不适合执行异步操作。
  • watchEffect
        - 适用于复杂的副作用逻辑,自动追踪依赖,适合立即执行。
        - 适合需要在依赖变化时执行异步操作或复杂逻辑的场景。
    在实际开发中,可以根据需求选择合适的 API。如果需要缓存计算结果,使用 computed;如果需要在依赖变化时执行复杂的副作用,使用 watchEffect
由 Hexo 驱动 & 主题 Keep
访客数 访问量