ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] >[success] # watch 和 watchEffect 的使用和差异性 我们讲一下在 **composition API** 中如何来使用 **watch** 和 **watchEffect** >[success] ## watch 使用方法 1. **监听基本数据** **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ setup(){ const { ref, watch } = Vue // 定义name属性 const name = ref('dell') // 监听name属性 // 具备一定的惰性 lazy // 参数可以拿到原始和当前值 watch(name, (currentValue, prevValue) => { console.log(currentValue, prevValue) }) return { name } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ 2. **监听对象或数组** 1. **错误写法示范** 如果 **监听** 的是一个 **reactive** 这样的数据, **watch** 的 **第 1 个参数** 就 **不可以** 像下面这样写: **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ setup(){ const { reactive, watch, toRefs } = Vue const nameObj = reactive({ name: 'dell' }) // 具备一定的惰性 lazy // 参数可以拿到原始和当前值 watch(nameObj.name, (currentValue, prevValue) => { console.log(currentValue, prevValue) }) const { name } = toRefs(nameObj) return { name } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ 2. **正确写法示范** 监听 **reactive** 这样的数据,**watch** 的第一个参数,要用 **箭头函数** 的形式 ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ setup(){ const { reactive, watch, toRefs } = Vue const nameObj = reactive({ name: 'dell' }) // 具备一定的惰性 lazy // 参数可以拿到原始和当前值 watch(() => nameObj.name, (currentValue, prevValue) => { console.log(currentValue, prevValue) }) const { name } = toRefs(nameObj) return { name } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ 3. **监听多个数据** 像下面这个代码中,想要 **同时监听 2 个数据** 就要写 **2 次 watch** **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ setup(){ const { reactive, watch, toRefs } = Vue // 定义变量 const nameObj = reactive({ name: 'dell', englishName: 'lee' }) // 监听 nameObj.name watch(() => nameObj.name, (currentValue, prevValue) => { console.log(currentValue, prevValue) }) // 监听 nameObj.englishName watch(() => nameObj.englishName, (currentValue, prevValue) => { console.log(currentValue, prevValue) }) // 解构取值 const { name, englishName } = toRefs(nameObj) return { name, englishName } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> <div> EnglishName: <input v-model="englishName"> </div> <div> EnglishName is {{ englishName }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ 上面的代码就会 **显得特别麻烦,重复性的代码写了多次** ,那我们可以这样写,把 **它们俩写在一起监听** ,在 **watch 里可以接收一个数组** ,它的意思就是 **这个数组中不管哪个值发生变化,我都会执行后面的函数,同样后面函数的参数也必须是数组的形式** **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ setup(){ const { reactive, watch, toRefs } = Vue // 定义变量 const nameObj = reactive({ name: 'dell', englishName: 'lee' }) // 监听 nameObj.name watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng],[preName, preEng]) => { console.log(curName, preName, '---', curEng, preEng) }) // 解构取值 const { name, englishName } = toRefs(nameObj) return { name, englishName } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> <div> EnglishName: <input v-model="englishName"> </div> <div> EnglishName is {{ englishName }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ 4. **初始化执行一次监听** **watch** 也可以 **默认执行一次监听** , **watch** 的 **第 2 个参数** 是个 **对象** ,可以在里面进行 **配置 immediate: true** 即可,代码如下: **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ setup(){ const { reactive, watch, watchEffect, toRefs } = Vue // 定义变量 const nameObj = reactive({ name: 'dell', englishName: 'lee' }) // 监听 nameObj.name watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng],[preName, preEng]) => { console.log('watch', curName, preName, '---', curEng, preEng) }, { immediate: true }) // 解构取值 const { name, englishName } = toRefs(nameObj) return { name, englishName } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> <div> EnglishName: <input v-model="englishName"> </div> <div> EnglishName is {{ englishName }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ >[success] ## watchEffect 使用方法 传统的 **vue2.x 版本 watch** 想实现 **默认执行一次监听** ,就要写 **immediate: true** ,如下: **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 const app = Vue.createApp({ data(){ return { nameObj: { name: 'dell', englishName: 'lee' } } }, watch: { 'nameObj.name' : { immediate: true, handler: function (oldValue, newValue) { console.log(oldValue,) } } }, template: ` <div> <div> Name: <input v-model="nameObj.name"> </div> <div> Name is {{ nameObj.name }} </div> <div> EnglishName: <input v-model="nameObj.englishName"> </div> <div> EnglishName is {{ nameObj.englishName }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ 而新版 **composition API** 的 **watchEffect 方法,初始化就会执行一次** , 它会 **自动检测方法内部使用的代码是否有变化** ,而且 **不需要传递你要侦听的内容,它会自动感知内容变化,缺点:无法获取之前或当前的数据** **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 // watchEffect 侦听器,偏向于 effect const app = Vue.createApp({ setup(){ const { reactive, watch, watchEffect, toRefs } = Vue // 定义变量 const nameObj = reactive({ name: 'dell', englishName: 'lee' }) // 监听 nameObj.name // watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng],[preName, preEng]) => { // console.log('watch', curName, preName, '---', curEng, preEng) // }) // 立即执行,没有惰性 immediate // 不需要传递你要侦听的内容,自动会感知代码依赖,不需要传递很多参数,只要传递一个回调函数 // 不能获取之前数据的值 watchEffect(() => { console.log(nameObj.name) }) // 解构取值 const { name, englishName } = toRefs(nameObj) return { name, englishName } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> <div> EnglishName: <input v-model="englishName"> </div> <div> EnglishName is {{ englishName }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~ >[success] ## 结束 watch 或 watchEffect 监听 假如我有这样一个需求想 **2s** 后 **结束监听** ,可以用 **变量或者常量** 把 **watch 或 watchEffect** 储存起来,然后 **2s 后执行一下这个变量的方法即可结束监听**,具体代码如下: ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>watch 和 watchEffect 的使用和差异性</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // watch 侦听器 // watchEffect 侦听器,偏向于 effect const app = Vue.createApp({ setup(){ const { reactive, watch, watchEffect, toRefs } = Vue // 定义变量 const nameObj = reactive({ name: 'dell', englishName: 'lee' }) // 监听 nameObj.name const stop1 = watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng],[preName, preEng]) => { console.log('watch', curName, preName, '---', curEng, preEng) setTimeout(() => { stop1() // 结束监听 }, 2000) }) // 立即执行,没有惰性 immediate // 不需要传递你要侦听的内容,自动会感知代码依赖,不需要传递很多参数,只要传递一个回调函数 // 不能获取之前数据的值 const stop = watchEffect(() => { console.log(nameObj.name) setTimeout(() => { stop() // 结束监听 }, 2000) }) // 解构取值 const { name, englishName } = toRefs(nameObj) return { name, englishName } }, template: ` <div> <div> Name: <input v-model="name"> </div> <div> Name is {{ name }} </div> <div> EnglishName: <input v-model="englishName"> </div> <div> EnglishName is {{ englishName }} </div> </div> ` }) const vm = app.mount('#root') </script> </html> ~~~