阅读:80回复:1
Vue3中 watch、watchEffect 详解1. watch 的使用 语法 import { watch } from "vue" watch( name , ( curVal , preVal )=>{ //业务处理 }, options ) ; 共有三个参数,分别为: name:需要帧听的属性; (curVal,preVal)=>{ //业务处理 } 箭头函数,是监听到的最新值和本次修改之前的值,此处进行逻辑处理。 options :配置项,对监听器的配置,如:是否深度监听。 1.1 监听 ref 定义的响应式数据 <template> <div> <div>值:pw_count</div> <button @click="add">改变值</button> </div> </template> <script> import { ref, watch } from 'vue'; export default { setup(){ const count = ref(0); const add = () => { count.value ++ }; watch(count,(newVal,oldVal) => { console.log('值改变了',newVal,oldVal) }) return { count, add, } } } </script> 1.2 监听 reactive 定义的响应式数据 <template> <div> <div>pw_obj.name</div> <div>pw_obj.age</div> <button @click="changeName">改变值</button> </div> </template> <script> import { reactive, watch } from 'vue'; export default { setup(){ const obj = reactive({ name:'zs', age:14 }); const changeName = () => { obj.name = 'ls'; }; watch(obj,(newVal,oldVal) => { console.log('值改变了',newVal,oldVal) }) return { obj, changeName, } } } </script> 1.3 监听多个响应式数据数据 <template> <div> <div>pw_obj.name</div> <div>pw_obj.age</div> <div>pw_count</div> <button @click="changeName">改变值</button> </div> </template> <script> import { reactive, ref, watch } from 'vue'; export default { setup(){ const count = ref(0); const obj = reactive({ name:'zs', age:14 }); const changeName = () => { obj.name = 'ls'; }; watch([count,obj],() => { console.log('监听的多个数据改变了') }) return { obj, count, changeName, } } } </script> 1.4 监听对象中某个属性的变化 <template> <div> <div>pw_obj.name</div> <div>pw_obj.age</div> <button @click="changeName">改变值</button> </div> </template> <script> import { reactive, watch } from 'vue'; export default { setup(){ const obj = reactive({ name:'zs', age:14 }); const changeName = () => { obj.name = 'ls'; }; watch(() => obj.name,() => { console.log('监听的obj.name改变了') }) return { obj, changeName, } } } </script> 1.5 深度监听(deep)、默认执行(immediate) <template> <div> <div>pw_obj.brand.name</div> <button @click="changeBrandName">改变值</button> </div> </template> <script> import { reactive, ref, watch } from 'vue'; export default { setup(){ const obj = reactive({ name:'zs', age:14, brand:{ id:1, name:'宝马' } }); const changeBrandName = () => { obj.brand.name = '奔驰'; }; watch(() => obj.brand,() => { console.log('监听的obj.brand.name改变了') },{ deep:true, immediate:true, }) return { obj, changeBrandName, } } } </script> |
|
沙发#
发布于:2025-06-11 15:26
2. watchEffect 的使用
watchEffect 也是一个帧听器,是一个副作用函数。 它会监听引用数据类型的所有属性,不需要具体到某个属性,一旦运行就会立即监听,组件卸载的时候会停止监听。 <template> <div> <input type="text" v-model="obj.name"> </div> </template> <script> import { reactive, watchEffect } from 'vue'; export default { setup(){ let obj = reactive({ name:'zs' }); watchEffect(() => { console.log('name:',obj.name) }) return { obj } } } </script> 停止侦听 当 watchEffect 在组件的 setup() 函数或生命周期钩子被调用时,侦听器会被链接到该组件的生命周期,并在组件卸载时自动停止。 在一些情况下,也可以显式调用返回值以停止侦听: <template> <div> <input type="text" v-model="obj.name"> <button @click="stopWatchEffect">停止监听</button> </div> </template> <script> import { reactive, watchEffect } from 'vue'; export default { setup(){ let obj = reactive({ name:'zs' }); const stop = watchEffect(() => { console.log('name:',obj.name) }) const stopWatchEffect = () => { console.log('停止监听') stop(); } return { obj, stopWatchEffect, } } } </script> 清除副作用 有时副作用函数会执行一些异步的副作用,这些响应需要在其失效时清除 (场景:有一个页码组件里面有5个页码,点击就会异步请求数据。于是做一个监听,监听当前页码,只要有变化就请求一次。问题:如果点击的比较快,从1到5全点了一遍,那么会有5个请求,最终页面会显示第几页的内容?第5页?那是假定请求第5页的ajax响应的最晚,事实呢?并不一定。于是这就会导致错乱。还有一个问题,连续快速点5次页码,等于我并不想看前4页的内容,那么是不是前4次的请求都属于带宽浪费?这也不好。 于是官方就给出了一种解决办法: 侦听副作用传入的函数可以接收一个 onInvalidate 函数作入参,用来注册清理失效时的回调。 当以下情况发生时,这个失效回调会被触发: 副作用即将重新执行时; 侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect,则在组件卸载时) watchEffect(onInvalidate => { const token = performAsyncOperation(id.value) onInvalidate(() => { // id has changed or watcher is stopped. // invalidate previously pending async operation token.cancel() }) }) 首先,异步操作必须是能中止的异步操作,对于定时器来讲中止定时器很容易,clearInterval之类的就可以,但对于ajax来讲,需要借助ajax库(比如axios)提供的中止ajax办法来中止ajax。 现在我写一个能直接运行的范例演示一下中止异步操作: 先搭建一个最简[backcolor=url(&]Node服务器,3000端口的: const http = require('http'); const server = http.createServer((req, res) => { res.setHeader('Access-Control-Allow-Origin', "*"); res.setHeader('Access-Control-Allow-Credentials', true); res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'); res.writeHead(200, { 'Content-Type': 'application/json'}); }); server.listen(3000, () => { console.log('Server is running...'); }); server.on('request', (req, res) => { setTimeout(() => { if (/\d.json/.test(req.url)) { const data = { content: '我是返回的内容,来自' + req.url } res.end(JSON.stringify(data)); } }, Math.random() * 3000); }); <template> <div> <div>content: pw_ content </div> <button @click="changePageNumber">第pw_ pageNumber 页</button> </div> </template> <script> import axios from 'axios'; import { ref, watchEffect } from 'vue'; export default { setup() { let pageNumber = ref(1); let content = ref(''); const changePageNumber = () => { pageNumber.value++; } watchEffect((onInvalidate) => { axios.get(`http://localhost:3000/${pageNumber.value}.json`, { // cancelToken: source.token, }).then((response) => { content.value = response.data.content; }).catch(function (err) { if (axios.isCancel(err)) { console.log('Request canceled', err.message); } }); }); return { pageNumber, content, changePageNumber, }; }, }; </script> 上面注释掉的代码先保持注释,然后经过多次疯狂点击之后,得到这个结果,显然,内容错乱了: ……………… https://blog.csdn.net/wish_way/article/details/134420294?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226ca265d512761906b18599b29ec2c5b2%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=6ca265d512761906b18599b29ec2c5b2&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-134420294-null-null.142^v102^pc_search_result_base7&utm_term=vue3%20%20watchEffect&spm=1018.2226.3001.4187 |
|