当前位置: 首页 > article >正文

Vue 中的 computed 与 watch:深度剖析与实践应用

Vue 中的 computed 与 watch:深度剖析与实践应用

在 Vue 3 的开发世界里,computedwatch作为两个关键的响应式 API,对于构建高效、灵活且易于维护的前端应用起着至关重要的作用。无论是处理数据变化,还是执行异步操作,它们都有着独特的价值。今天,就让我们深入探讨这两个 API 的区别、用法以及实际应用场景。

 

一、用途和行为特性大揭秘

(一)computed:计算属性的魔法

computed主要用于创建基于其他响应式数据的计算属性。它就像是一个智能加工厂,根据输入的响应式数据,经过特定的计算逻辑,输出一个新的属性值。

其行为特性十分有趣。通过getter函数返回计算后的值,并且会自动追踪依赖的变化。一旦依赖的数据发生变动,computed属性就会自动更新。更棒的是,它拥有缓存机制,当依赖数据没有变化时,多次访问computed属性,它会直接返回之前的计算结果,而不会重新执行复杂的计算逻辑,这在提升性能方面效果显著。

举个例子,在一个电商购物车的场景中,我们需要实时计算商品的总价。商品的数量和单价都是响应式数据,通过computed属性来计算总价就再合适不过了。这样,当商品数量或单价发生变化时,总价会自动更新,而且在多次访问总价时,如果数量和单价没有改变,就直接使用缓存结果,大大提高了计算效率。同时,它非常适用于简化模板中的复杂表达式。假设模板中需要展示一个经过多步计算得出的复杂数据,如果直接在模板中编写计算逻辑,代码会变得冗长且难以维护。而使用computed属性,将计算逻辑封装起来,在模板中直接使用计算后的属性,能让代码更加清晰易读。

 

(二)watch:数据变化的守护者

watch则主要用于侦听某个数据的变化,并在数据变化时执行特定的副作用,比如异步操作、条件判断等。它就像一个忠诚的卫士,时刻监听着数据的一举一动,一旦数据有变化,就立即执行相应的操作。

当数据变化时,watch会触发回调函数。不过要注意,如果数据频繁变化,回调函数可能会多次触发,这就可能会带来性能问题。所以在使用watch时,尤其是回调函数中包含复杂逻辑时,需要特别关注性能优化。

例如,在一个搜索功能中,用户每输入一个字符,都需要向服务器发起搜索请求。这时就可以使用watch来侦听搜索框输入值的变化,一旦值发生改变,就触发搜索请求这个异步操作。但如果用户输入速度很快,频繁触发搜索请求可能会对服务器造成压力,也会影响用户体验,这时候就需要考虑防抖或节流等优化策略。

 

二、语法全解析

(一)computed 的语法奥秘

在组合式 API 中,创建computed属性非常简单,通过computed函数即可实现。计算属性默认是只读的,不过也可以定义可写的计算属性,这需要借助setter函数。

import { ref, computed } from 'vue';
const items = ref([10, 20, 30, 40]);
const total = computed(() => items.value.reduce((sum, item) => sum + item, 0));

在这个例子中,total就是一个computed属性,它依赖于items。当items中的数据发生变化时,total会自动重新计算。

如果想要创建一个可写的计算属性,可以这样做:

<template>
  <div>
    <p>原始数字: {{ number }}</p>
    <p>平方数字: {{ squaredNumber }}</p>
    <input v-model.number="number">
  </div>
</template>

<script>
import { ref, computed } from 'vue';
export default {
  setup() {
    const number = ref(4);
    const squaredNumber = computed({
      get: () => number.value * number.value,
      set: (newVal) => {
        number.value = Math.sqrt(newVal);
      }
    });
    return {
      number,
      squaredNumber
    };
  }
};
</script>

这里的squaredNumber就是一个可写的计算属性。当修改squaredNumber的值时,setter函数会被触发,从而更新number的值。

 

(二)watch 的语法细节

同样在组合式 API 中,通过watch函数来创建侦听器。它可以精确指定要侦听的数据源,并且在数据源变化时执行回调函数。watch函数返回一个停止侦听的函数,方便在需要时停止侦听。

watch还有一些非常实用的额外选项:

  • immediate:设置为true时,侦听器会在创建时立即触发回调,之后响应式数据变化时继续执行回调。比如在初始化页面时,就需要根据某个初始数据执行一些操作,这时就可以使用immediate选项。
  • deep:设置为true时,侦听器会深度侦听对象内部属性的变化。当需要监听一个对象内部深层次属性的变化时,这个选项就派上用场了。

import { ref, watch } from 'vue';
const query = ref('');
watch(query, (newQuery, oldQuery) => {
  // 执行异步操作,如API请求
  fetch(`https://api.example.com/search?q=${newQuery}`).then(response => response.json()).then(data => {
    // 更新数据
  });
}, { immediate: true, deep: false }); 

在这个示例中,当query的值发生变化时,就会触发fetch请求这个异步操作。同时,因为设置了immediate: true,所以在侦听器创建时也会执行一次回调。

 

三、实战演练:在项目中灵活运用

(一)computed 的实战应用

假设有一个需求,在页面上展示一段消息的反转内容。当用户输入消息时,反转后的消息也实时更新。使用computed可以轻松实现:

<template>
  <div>
    <p>原始消息: {{ message }}</p>
    <p>反转消息: {{ reversedMessage }}</p>
    <input v-model="message">
  </div>
</template>

<script>
import { ref, computed } from 'vue';
export default {
  setup() {
    const message = ref('Hello, Vue 3!');
    const reversedMessage = computed(() => {
      return message.value.split('').reverse().join('');
    });
    return {
      message,
      reversedMessage
    };
  }
};
</script>

在这个例子中,reversedMessage是一个依赖于message的计算属性。当message的值发生变化时,reversedMessage会自动重新计算并更新页面展示。

 

(二)watch 的实战应用

  1. 基本使用:监听单一数据变化
    还是以消息输入为例,这次我们使用watch来监听消息的变化,并在变化时打印新旧值:
<template>
  <div>
    <p>原始消息: {{ message }}</p>
    <input v-model="message">
  </div>
</template>

<script>
import { ref, watch } from 'vue';
export default {
  setup() {
    const message = ref('Hello, Vue 3!');
    watch(message, (newValue, oldValue) => {
      console.log(`Message changed from "${oldValue}" to "${newValue}"`);
    });
    return {
      message
    };
  }
};
</script>

当用户在输入框中修改消息内容时,watch的回调函数就会被触发,打印出消息的新旧值。

2. 监听多个源
在一些场景中,需要同时监听多个数据的变化。比如在一个表单中,有两个输入框,分别控制一个矩形的宽度和高度,当宽度或高度发生变化时,都需要重新计算矩形的面积。这时就可以使用watch监听多个源:

<template>
  <div>
    <p>First: {{ first }}</p>
    <p>Second: {{ second }}</p>
    <input v-model.number="first">
    <input v-model.number="second">
  </div>
</template>

<script>
import { ref, watch } from 'vue';
export default {
  setup() {
    const first = ref(1);
    const second = ref(2);
    watch([first, second], ([newFirst, newSecond], [oldFirst, oldSecond]) => {
      console.log(`First changed from ${oldFirst} to ${newFirst}`);
      console.log(`Second changed from ${oldSecond} to ${newSecond}`);
    });
    return {
      first,
      second
    };
  }
};
</script>

在这个例子中,watch同时监听firstsecond两个数据的变化,当其中任何一个发生变化时,都会执行回调函数,打印出变化前后的值。


3. 深度侦听
当需要监听一个对象内部深层次属性的变化时,deep选项就发挥作用了。比如有一个用户对象,包含姓名、年龄等属性,当用户修改姓名时,我们需要执行一些操作:

<template>
  <div>
    <p>User: {{ user.name }}</p>
    <input v-model="user.name">
  </div>
</template>

<script>
import { reactive, watch } from 'vue';
export default {
  setup() {
    const user = reactive({ name: 'John Doe' });
    watch(user, (newValue, oldValue) => {
      console.log(`User changed from`, oldValue, `to`, newValue);
    }, { deep: true });
    return {
      user
    };
  }
};
</script>

这里通过设置deep: truewatch可以深度监听user对象内部name属性的变化。

4. 立即执行
有时候,我们希望在侦听器创建时就立即执行一次回调函数,比如在页面加载时,根据初始数据执行一些初始化操作。这时候就可以使用immediate选项:

<template>
  <div>
    <p>Message: {{ message }}</p>
    <input v-model="message">
  </div>
</template>

<script>
import { ref, watch } from 'vue';
export default {
  setup() {
    const message = ref('Hello, Vue 3!');
    watch(message, (newValue, oldValue) => {
      console.log(`Message changed from "${oldValue}" to "${newValue}"`);
    }, { immediate: true });
    return {
      message
    };
  }
};
</script>

在这个例子中,因为设置了immediate: true,所以在页面加载时,watch的回调函数就会立即执行一次,打印出初始的新旧值。

 

四、总结:computed 与 watch 的选择之道

通过以上的详细介绍,我们对computedwatch的区别与用法有了更深入的理解。在实际开发中,选择使用computed还是watch,需要根据具体的需求来决定。

如果需要创建一个基于其他响应式依赖的计算属性,并且希望高效地缓存计算结果,同时在模板中使用这个计算属性来简化代码,那么computed是不二之选。它不仅能提升性能,还能让代码更加清晰易读。

而当需要侦听响应式引用或计算属性的变化,并在变化时执行副作用,比如异步操作、复杂的条件判断等,watch则能发挥它的优势。并且watch还提供了诸如监听多个源、深度侦听、立即执行等灵活的选项,满足各种复杂场景的需求。


http://www.kler.cn/a/564088.html

相关文章:

  • 本地大模型编程实战(22)用langchain实现基于SQL数据构建问答系统(1)
  • Hot100 动态规划
  • 应用的负载均衡
  • HBuilderx 插件开发变量名称翻译 ,中文转(小驼峰,大驼峰,下划线,常量,CSS类名)
  • IP---网络类型
  • 【DeepSeek】【GPT-Academic】:DeepSeek集成到GPT-Academic(官方+第三方)
  • DDNS-GO 动态域名解析
  • 前端网页或者pwa如何实现只横屏显示,设备竖着的时候依然保持横屏
  • kiln微调大模型-使用deepseek R1去训练一个你的具备推理能力的chatGPT 4o
  • seacmsv9报错注入
  • 基于MATLAB红外弱小目标检测MPCM算法复现
  • nginx 配置https
  • 归并排序:分而治之的排序之道
  • Mac安装双系统教程
  • 如果更换ip地址会怎么样?网络ip地址怎么更换
  • Elasticsearch索引设计与分片策略深度优化-手记
  • 2025-02-26 学习记录--C/C++-C语言 判断字符串S2是否在字符串S1中
  • docker file中ADD命令的介绍
  • mysql-analyze table导致waiting for table flush
  • python 剪切音频