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

Vue3 学习教程,从入门到精通,Vue3 监听属性(Watchers)语法知识点及案例代码(16)

Vue3 监听属性(Watchers)语法知识点及案例代码

在 Vue 3 中,监听属性(Watchers) 允许你响应数据的变化,并在数据变化时执行特定的逻辑。监听器对于处理异步操作或需要在数据变化时执行复杂逻辑的场景非常有用。

一、监听属性的基本语法

1. 使用 watch 选项

在组件选项中,通过 watch 选项来定义监听器。watch 对象中的每个键对应一个要监听的数据源,值是一个回调函数,当数据源变化时回调函数会被调用。

export default {data() {return {count: 0};},watch: {count(newVal, oldVal) {console.log(`count 从 ${oldVal} 变为 ${newVal}`);}}
};

2. 使用 watch 函数

除了在选项式 API 中使用 watch 选项外,Vue 3 还提供了组合式 API 中的 watch 函数,用于在 setup 函数中定义监听器。

import { ref, watch } from 'vue';export default {setup() {const count = ref(0);watch(count, (newVal, oldVal) => {console.log(`count 从 ${oldVal} 变为 ${newVal}`);});return {count};}
};

3. 监听器的选项

watch 回调函数可以接受多个参数:

  • 新值(newVal):变化后的新值。
  • 旧值(oldVal):变化前的旧值。
  • onInvalidate:用于清除副作用的函数。

此外,监听器还支持一些选项:

  • immediate:布尔值,设置为 true 时,监听器会在初始化时立即执行一次。
  • deep:布尔值,设置为 true 时,监听器会进行深度监听,适用于监听对象或数组内部的变化。
watch(source,(newVal, oldVal) => {// 回调函数},{immediate: true,deep: true}
);

4. 监听多个数据源

可以通过数组的形式同时监听多个数据源。

watch([() => this.a, () => this.b], ([newA, newB], [oldA, oldB]) => {console.log(`a 从 ${oldA} 变为 ${newA}, b 从 ${oldB} 变为 ${newB}`);
});

5. 停止监听器

在某些情况下,你可能需要手动停止监听器。可以使用 watch 返回的函数来停止监听。

const unwatch = watch(count, (newVal, oldVal) => {console.log(`count 从 ${oldVal} 变为 ${newVal}`);
});// 需要停止监听时调用
unwatch();

二、案例代码

下面是一个完整的 Vue 3 组件示例,演示了如何使用监听属性。这个组件包含一个计数器,用户可以点击按钮增加计数,监听器会监测计数的变化并执行相应的逻辑。

1. 使用选项式 API 的示例

<template><div><h2>计数器</h2><p>当前计数: {{ count }}</p><button @click="increment">增加</button><p>监听器输出:</p><ul><li v-for="(log, index) in logs" :key="index">{{ log }}</li></ul></div>
</template><script>
export default {data() {return {count: 0,logs: []};},watch: {// 监听 count 的变化count(newVal, oldVal) {this.logs.push(`count 从 ${oldVal} 变为 ${newVal}`);// 示例:每当 count 变化时,执行异步操作this.fetchData(newVal);}},methods: {increment() {this.count++;},async fetchData(val) {// 模拟异步请求const data = await new Promise((resolve) => {setTimeout(() => {resolve(`服务器返回的数据: ${val}`);}, 1000);});this.logs.push(data);}},// 立即执行一次监听器mounted() {this.$watch(() => this.count,(newVal, oldVal) => {this.logs.push(`[立即监听] count 从 ${oldVal} 变为 ${newVal}`);},{ immediate: true });}
};
</script><style scoped>
button {margin-top: 10px;
}
ul {list-style-type: none;padding: 0;
}
li {background: #f0f0f0;margin: 5px 0;padding: 5px;
}
</style>
解释:
  1. 数据定义

    • count:当前的计数。
    • logs:用于存储监听器输出的日志。
  2. 监听器

    • watch 对象中定义了 count 的监听器。当 count 变化时,回调函数会执行,将新旧值记录到 logs 中,并调用 fetchData 方法模拟异步操作。
  3. 方法

    • increment:增加 count 的值。
    • fetchData:模拟一个异步请求,延迟 1 秒后返回服务器数据。
  4. 生命周期钩子

    • mounted:在组件挂载后,使用 $watch 方法定义一个立即执行的监听器,演示 immediate 选项的使用。
  5. 模板

    • 显示当前的计数。
    • 提供一个按钮来增加计数。
    • 显示监听器的输出日志。

2. 使用组合式 API 的示例

<template><div><h2>计数器(组合式 API)</h2><p>当前计数: {{ count }}</p><button @click="increment">增加</button><p>监听器输出:</p><ul><li v-for="(log, index) in logs" :key="index">{{ log }}</li></ul></div>
</template><script>
import { ref, watch, onMounted } from 'vue';export default {setup() {const count = ref(0);const logs = ref([]);// 定义监听器const stopWatch = watch(count, (newVal, oldVal) => {logs.value.push(`count 从 ${oldVal} 变为 ${newVal}`);fetchData(newVal);}, {immediate: false,deep: false});// 方法定义const increment = () => {count.value++;};const fetchData = async (val) => {const data = await new Promise((resolve) => {setTimeout(() => {resolve(`服务器返回的数据: ${val}`);}, 1000);});logs.value.push(data);};// 立即执行一次监听器onMounted(() => {watch(() => count.value,(newVal, oldVal) => {logs.value.push(`[立即监听] count 从 ${oldVal} 变为 ${newVal}`);},{ immediate: true });});return {count,increment,logs};}
};
</script><style scoped>
button {margin-top: 10px;
}
ul {list-style-type: none;padding: 0;
}
li {background: #f0f0f0;margin: 5px 0;padding: 5px;
}
</style>
解释:
  1. 导入

    • ref:用于定义响应式数据。
    • watch:用于定义监听器。
    • onMounted:生命周期钩子,用于在组件挂载后执行代码。
  2. 数据定义

    • count:当前的计数,使用 ref 定义。
    • logs:用于存储监听器输出的日志。
  3. 监听器

    • 使用 watch 函数定义 count 的监听器。当 count 变化时,回调函数会执行,将新旧值记录到 logs 中,并调用 fetchData 方法模拟异步操作。
  4. 方法

    • increment:增加 count 的值。
    • fetchData:模拟一个异步请求,延迟 1 秒后返回服务器数据。
  5. 生命周期钩子

    • onMounted:在组件挂载后,使用 watch 函数定义一个立即执行的监听器,演示 immediate 选项的使用。
  6. 模板

    • 显示当前的计数。
    • 提供一个按钮来增加计数。
    • 显示监听器的输出日志。

三、完整案例:购物车监听

<template><div><h1>购物车</h1><div><button @click="addItem">添加商品</button><button @click="removeItem">移除商品</button><button @click="changeUser">更改用户</button></div><div><h3>购物车内容 ({{ cartItems.length }} 件):</h3><ul><li v-for="(item, index) in cartItems" :key="index">{{ item.name }} - ¥{{ item.price }} × {{ item.quantity }}</li></ul></div><div><h3>总价: ¥{{ totalPrice }}</h3></div><div><h3>用户信息:</h3><p>姓名: {{ user.name }}</p><p>会员等级: {{ user.level }}</p></div><div v-if="discountApplied"><p style="color: green;">已应用 {{ discountRate * 100 }}% 会员折扣!</p></div><div v-if="cartChanged"><p style="color: orange;">购物车内容已更改,请确认!</p></div></div>
</template><script>
import { ref, reactive, computed, watch, watchEffect } from 'vue'export default {setup() {// 购物车商品const cartItems = ref([{ id: 1, name: '商品A', price: 100, quantity: 1 },{ id: 2, name: '商品B', price: 200, quantity: 2 }])// 用户信息const user = reactive({name: '张三',level: 'gold', // silver, gold, platinumdiscountRates: {silver: 0.95,gold: 0.9,platinum: 0.85}})// 计算属性const totalPrice = computed(() => {const subtotal = cartItems.value.reduce((sum, item) => sum + item.price * item.quantity, 0)return subtotal * discountRate.value})const discountRate = computed(() => {return user.discountRates[user.level] || 1})// 状态标志const discountApplied = ref(false)const cartChanged = ref(false)// 1. 监听用户等级变化,应用折扣watch(() => user.level,(newLevel) => {console.log(`用户等级变更为: ${newLevel}`)discountApplied.value = true// 3秒后隐藏折扣提示setTimeout(() => {discountApplied.value = false}, 3000)})// 2. 深度监听购物车变化watch(cartItems,(newItems, oldItems) => {console.log('购物车内容变化:', newItems)cartChanged.value = true// 5秒后重置变化标志setTimeout(() => {cartChanged.value = false}, 5000)},{ deep: true })// 3. 使用 watchEffect 自动跟踪依赖const stopEffect = watchEffect(() => {console.log(`当前总价: ${totalPrice.value} (用户: ${user.name}, 等级: ${user.level})`)})// 方法const addItem = () => {const newId = cartItems.value.length + 1cartItems.value.push({id: newId,name: `商品${String.fromCharCode(64 + newId)}`,price: Math.round(Math.random() * 200 + 50),quantity: 1})}const removeItem = () => {if (cartItems.value.length > 0) {cartItems.value.pop()}}const changeUser = () => {const levels = ['silver', 'gold', 'platinum']const currentIndex = levels.indexOf(user.level)const nextIndex = (currentIndex + 1) % levels.lengthuser.level = levels[nextIndex]// 随机更改用户名const names = ['张三', '李四', '王五', '赵六']user.name = names[Math.floor(Math.random() * names.length)]}return {cartItems,user,totalPrice,discountApplied,cartChanged,addItem,removeItem,changeUser}}
}
</script><style>
/* 简单样式 */
button {margin: 5px;padding: 8px 16px;cursor: pointer;
}
</style>

四、总结

Vue 3 提供了强大的监听属性功能,使得开发者能够灵活地响应数据的变化并执行相应的逻辑。通过选项式 API 和组合式 API 两种方式,开发者可以根据具体需求选择最适合的方式来定义监听器。此外,监听器还支持多种选项,如 immediatedeep,进一步增强了其功能。

http://www.dtcms.com/a/297210.html

相关文章:

  • Unity编辑器拓展 IMGUI与部分Utility知识总结(代码+思维导图)
  • JAVA-09(2025.07.25学习记录)
  • MMRotate ReDet ReFPN 报错 `assert input.type == self.in_type`
  • Franky — 边缘计算智能语音助手 / Edge‑Computing Smart Voice Assistant
  • 04-netty基础-Reactor三种模型
  • docker compose xtify-music-web
  • 华为OpenStack架构学习9篇 连载—— 02 OpenStack界面管理【附全文阅读】
  • VR 三维重建:重塑建筑工程全生命周期的数字化革命
  • [NLP]多电源域设计的仿真验证方法
  • Redis 5.0.14安装教程
  • Android 10.0 sts CtsSecurityBulletinHostTestCases的相关异常分析
  • 关于自定义域和 GitHub Pages(Windows)
  • OpenCV(04)梯度处理,边缘检测,绘制轮廓,凸包特征检测,轮廓特征查找
  • [python][flask]Flask-Login 使用详解
  • uniapp小程序上传图片并压缩
  • 吊汤:厨房的鲜味密码
  • 若依框架 ---一套快速开发平台
  • STM32-中断配置教程(寄存器版)
  • 【应急响应】进程隐藏技术与检测方式(二)
  • Gin 框架的中间件机制
  • 三种深度学习模型(GRU、CNN-GRU、贝叶斯优化的CNN-GRU/BO-CNN-GRU)对北半球光伏数据进行时间序列预测
  • win11 使用adb 获取安卓系统日志
  • ESP32学习笔记_Peripherals(4)——MCPWM基础使用
  • C++ : list的模拟
  • Kafka——多线程开发消费者实例
  • 使用OpenCV做个图片校正工具
  • 技术演进中的开发沉思-45 DELPHI VCL系列:6种方法
  • 关于新学C++编程Visual Studio 2022开始,使用Cmake工具构建Opencv和SDK在VS里编译项目开发简介笔记
  • RocketMQ常见问题梳理
  • 三、Spark 运行环境部署:全面掌握四种核心模式