Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • computed 计算属性与 watch 监听器

computed 计算属性与 watch 监听器

Vue 3 的响应式系统不仅限于 reactive 和 ref,还提供了 computed 和 watch 两个强大工具,用于处理复杂的数据逻辑和副作用。computed 用于创建依赖响应式数据的计算属性,而 watch 用于监听数据变化并执行自定义操作。本节将详细讲解它们的用法、区别和最佳实践,帮助你更高效地管理响应式状态。

computed 计算属性

computed 创建一个基于其他响应式数据的衍生值,只有当依赖项变化时才会重新计算。

1. 基本用法

示例:计算全名

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

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

export default {
  setup() {
    const firstName = ref('');
    const lastName = ref('');

    const fullName = computed(() => {
      return `${firstName.value} ${lastName.value}`.trim();
    });

    return { firstName, lastName, fullName };
  }
};
</script>
  • 效果:输入名和姓时,全名自动更新。
  • 特点:
    • computed 返回一个只读的 Ref 对象。
    • 在模板中自动解包为值,无需 .value。

2. 可写计算属性

Vue 3 支持通过 getter 和 setter 定义可写的计算属性:

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

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

export default {
  setup() {
    const firstName = ref('');
    const lastName = ref('');

    const fullName = computed({
      get: () => `${firstName.value} ${lastName.value}`.trim(),
      set: (newValue) => {
        const [first, last] = newValue.split(' ');
        firstName.value = first || '';
        lastName.value = last || '';
      }
    });

    return { firstName, lastName, fullName };
  }
};
</script>
  • 效果:输入全名时,自动拆分为名和姓。
  • 用途:适合需要双向转换的场景。

3. 性能优势

  • 缓存机制:computed 值会被缓存,只有依赖的响应式数据变化时才重新计算。
  • 对比方法:普通方法每次渲染都会重新调用。
    <template>
      <p>{{ computedValue }}</p>
      <p>{{ methodValue() }}</p>
    </template>
    
    <script>
    import { ref, computed } from 'vue';
    
    export default {
      setup() {
        const count = ref(0);
        const computedValue = computed(() => count.value * 2);
        const methodValue = () => count.value * 2;
        return { count, computedValue, methodValue };
      }
    };
    </script>
    
    • 区别:computedValue 只在 count 变化时计算,methodValue 每次渲染都执行。

watch 监听器

watch 用于监听响应式数据的变化,并在变化时执行副作用(如异步请求、日志记录)。

1. 基本用法

示例:监听计数器

<template>
  <div>
    <p>计数:{{ count }}</p>
    <button @click="count++">增加</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const count = ref(0);

    watch(count, (newValue, oldValue) => {
      console.log(`count 从 ${oldValue} 变为 ${newValue}`);
    });

    return { count };
  }
};
</script>
  • 效果:点击按钮时,控制台打印变化前后值。
  • 参数:
    • 第一个参数:监听的响应式数据。
    • 第二个参数:回调函数,接收新值和旧值。

2. 监听对象属性

监听 reactive 对象的特定属性需要使用 getter 函数:

<template>
  <div>
    <p>{{ user.name }}</p>
    <button @click="user.name = 'Bob'">修改姓名</button>
  </div>
</template>

<script>
import { reactive, watch } from 'vue';

export default {
  setup() {
    const user = reactive({ name: 'Alice', age: 25 });

    watch(() => user.name, (newName, oldName) => {
      console.log(`姓名从 ${oldName} 变为 ${newName}`);
    });

    return { user };
  }
};
</script>
  • 注意:直接 watch(user, ...) 会监听整个对象的所有属性变化。

3. 选项配置

watch 支持选项:

  • immediate:立即执行一次。
  • deep:深层监听对象。
<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const data = ref({ count: 0 });

    watch(data, (newValue) => {
      console.log('data 变化:', newValue);
    }, { deep: true, immediate: true });

    return { data };
  }
};
</script>
  • 效果:初始化时打印一次,data.count 变化时也触发。

4. 停止监听

watch 返回一个停止函数,用于手动取消监听:

<script>
import { ref, watch, onUnmounted } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const stop = watch(count, (newValue) => {
      console.log('count:', newValue);
    });

    onUnmounted(() => stop()); // 组件销毁时停止监听
    return { count };
  }
};
</script>

computed vs watch

特性computedwatch
用途计算衍生数据执行副作用
返回值响应式值(Ref)无返回值(副作用函数)
缓存有缓存,依赖不变不重算无缓存,每次变化都执行
使用场景数据转换、格式化异步操作、日志记录

示例:选择合适工具

<template>
  <div>
    <input v-model="price" type="number" />
    <p>折扣价:{{ discountedPrice }}</p>
    <p>日志:{{ log }}</p>
  </div>
</template>

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

export default {
  setup() {
    const price = ref(100);
    const log = ref('');

    // computed:计算折扣价
    const discountedPrice = computed(() => price.value * 0.8);

    // watch:记录价格变化
    watch(price, (newPrice, oldPrice) => {
      log.value = `价格从 ${oldPrice} 变为 ${newPrice}`;
    });

    return { price, discountedPrice, log };
  }
};
</script>
  • 效果:输入价格时,折扣价实时计算,日志记录变化。

最佳实践

  1. 优先使用 computed:
    • 如果只是需要基于现有数据生成新值,选择 computed,性能更优。
  2. watch 用于副作用:
    • 如 API 调用、动画触发等,使用 watch。
  3. 避免重复计算:
    • 不建议在 watch 中重复 computed 的逻辑。
  4. 清理副作用:
    • 在组件销毁时停止不必要的 watch,避免内存泄漏。

综合示例

实现一个简单的搜索框:

<template>
  <div>
    <input v-model="query" placeholder="搜索..." />
    <p>结果数量:{{ resultCount }}</p>
  </div>
</template>

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

export default {
  setup() {
    const query = ref('');
    const items = ref(['apple', 'banana', 'orange']);

    // 计算属性:搜索结果数量
    const resultCount = computed(() => {
      return items.value.filter(item => item.includes(query.value)).length;
    });

    // 监听器:记录搜索日志
    watch(query, (newQuery) => {
      console.log(`搜索关键词:${newQuery}`);
    }, { immediate: true });

    return { query, resultCount };
  }
};
</script>
  • 效果:输入时,结果数量更新,控制台记录关键词。

总结

computed 和 watch 是 Vue 3 响应式系统的得力助手。computed 擅长处理依赖数据的计算,具有缓存优势;watch 适合响应变化执行副作用,灵活性更高。掌握这两者的使用场景和区别,能让你的代码更高效、可维护。下一节将探讨响应式开发的常见陷阱,帮你避开潜在问题!

Last Updated:: 2/23/25, 8:50 PM