餐馆网站怎么做的,沐歌 wordpress,域名注册腾讯云,网站设计目标怎么写目录
1. 基本概念
2. 侦听数据源类型
1. 监听getter函数
2. 监听 ref 或 reactive 的引用
3. 多个来源组成的数组
4. 避免直接传递值#xff01;#xff01;#xff01;
3. 深层侦听器
4. 立即回调的侦听器
5. 一次性侦听器
6. watchEffect()
7. 暂停、恢复和停止…目录
1. 基本概念
2. 侦听数据源类型
1. 监听getter函数
2. 监听 ref 或 reactive 的引用
3. 多个来源组成的数组
4. 避免直接传递值
3. 深层侦听器
4. 立即回调的侦听器
5. 一次性侦听器
6. watchEffect()
7. 暂停、恢复和停止侦听器
8. 清理副作用
1. watch
2. watchEffect 1. 基本概念
在 Vue.js 中**监听器watchers**是一种用于监听数据变化并在变化发生时执行相应操作的功能。监听器通常用于执行异步操作或复杂的逻辑计算例如监控数据变化发起 API 请求执行深层次的对象或数组变化监听等。
templateel-cardp{{ num }}/pinput placeholderEnter typetext v-model.lazynum //el-card
/template
script setup langts
import { ref, watch } from vueconst num ref(1)
// watch接收两个参数数据源回调函数
watch(num, (newVal, oldVal) {console.log(newVal, oldVal)
})
// 回调函数接收两个参数新值旧值
/script上面的例子中当input发生change事件时num的值value会改变同时监听器会监听到num的变化并触发回调函数 2. 侦听数据源类型
watch 的第一个参数 数据源形式上可以是refcomputedreactivegetterprops或响应式对象。但本质上 必须是一个 getter 函数。这个限制是为了确保 watch 能够正确地监听数据的变化同时提供更精确和高效的响应式更新。
1. 监听getter函数
const num1 ref(1)
const num2 ref(1)
watch(() num1.value num2.value,(a, b) {console.log(a, b)},
) 2. 监听 ref 或 reactive 的引用
如果监听的对象是 ref 或 reactive 创建的引用可以直接传入。
const count ref(0);
watch(count, // 直接传递 ref 引用(newCount, oldCount) {console.log(Count changed from ${oldCount} to ${newCount});}
) 3. 多个来源组成的数组
watch([num1, () num2.value], ([new1, new2], [old1, old2]) {console.log(new1, new2, old1, old2)
}) 4. 避免直接传递值
如果传递的是非响应式的普通值Vue 无法监听它的变化。例如
const state reactive({user: { name: Alice, age: 25 },
})watch(state.user.name, (newName, oldName) {console.log(User name changed from ${oldName} to ${newName})
})
控制台警告并且并不能监听到 state.user.name的变化 传递 state.user.name 而不是 () state.user.name 因为此时 watch 直接接收了一个静态值而不是可变的引用或 getter。 查了一下大概的原因 因为watch底层逻辑依赖了proxy代理而静态值不能被proxy代理的。 而之所以不用普通对象而是用函数对象则是和vue的响应式系统的依赖跟踪与收集有关。 PS这种坑很容易在props传值的时候踩
const props defineProps({msg: {type: String,default: hello world,},
})
watch(() props.msg,(newVal, oldVal) {console.log(newVal, oldVal)},
) 3. 深层侦听器 官方直接给 watch() 传入一个响应式对象会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发 const count reactive({num1: 0,num2: {a: 1,b: 2,},
})
watch(count, (newNum, oldNum) {console.log(Count changed from ${oldNum} to ${newNum})console.log(oldNum, newNum)
})
上面代码中当num1或num2中的a、b发生改变时打印的结果是 因为监听的数据源是一个对象那么即使监听到对象持有值变了新旧值也都是数据源对象的地址。与之相对无论是对象的哪一个内容变化了都相当于该对象变化了。
那如果我们监听num2呢
watch(count.num2, (newNum, oldNum) {console.log(Count changed from ${oldNum} to ${newNum})console.log(oldNum, newNum)
}) 当然同理无论a还是b改变都会被监听到。因为reactive也让num2具有了响应性
那如果我们使用getter来监听num2呢
watch(() count.num2,(newNum, oldNum) {console.log(Count changed from ${oldNum} to ${newNum})console.log(oldNum, newNum)},
)
那么无论改变a还是b回调函数的都不会执行因为getter返回的是num2对象的地址啊地址不变当然监听不到变化
当然我们也可以这样显式地加上 deep 选项强制转成深层侦听器
watch(() count.num2,(newNum, oldNum) {console.log(Count changed from ${oldNum} to ${newNum})console.log(oldNum, newNum)},{ deep: true },
) 在 vue 3.5中我们还可以设置深度监听的层数如{ deep: 1}来限制最大遍历深度——即 Vue 应该遍历对象嵌套属性的级数
const count reactive({num1: 0,num2: {a: 1,b: 2,},
})
watch(count, (newNum, oldNum) {console.log(oldNum, newNum)
}, {deep: 1
})
count.num2.a
比如上面的例子中当我们改变num2.a的值时侦听回调函数就不会执行 4. 立即回调的侦听器
watch 默认是懒执行的仅当数据源变化时才会执行回调。也就是说在创建创建侦听器时并不会执行。但但在某些场景中我们又会有这种需求。
比如我们想请求一些初始数据然后在相关状态更改时重新请求数据。
watch(source,(newValue, oldValue) {// 立即执行且当 source 改变时再次执行},{ immediate: true }
) 5. 一次性侦听器
每当被侦听源发生变化时侦听器的回调就会执行。但有时候会希望回调函数只在源变化时触发一次那么就可以使用 once: true 选项。 注意仅支持 vue 3.4 及以上版本
watch(source,(newValue, oldValue) {// 当 source 变化时仅触发一次},{ once: true }
) 6. watchEffect()
watchEffect 会自动收集所有在回调函数内使用的响应式数据并在其中任何一个数据发生变化时重新运行回调函数。适合在不需要明确指定数据源的情况下自动收集依赖的数据。比如
下面的代码在每当 todoId 的引用发生变化时使用侦听器来加载一个远程资源
const todoId ref(1)
const data ref(null)watch(todoId,async () {const response await fetch(https://jsonplaceholder.typicode.com/todos/${todoId.value})data.value await response.json()},{ immediate: true }
)
注意侦听器在这里两次使用了 todoId 的一次是作为源另一次是在回调中。
像这种情况我们可以用 watchEffect 函数 来自动跟踪回调的响应式依赖。
watchEffect(async () {const response await fetch(https://jsonplaceholder.typicode.com/todos/${todoId.value})data.value await response.json()
})
回调会立即执行且不需要指定 immediate: true。在执行期间它还会自动追踪 todoId.value 作为依赖和计算属性类似。每当 todoId.value 变化时回调会再次执行。
虽然对于这种依赖项只有一个得例子来说watchEffect的作用不是很明显但如果有许多依赖项且数据源不明确时呢炒鸡好用
所以watch 和 watchEffect 的主要区别其实就是追踪响应式依赖的方式不同而已。 7. 暂停、恢复和停止侦听器
templateel-cardpnum: {{ count.num1 }}/pel-button clickcount.num1add/el-buttonel-button clickpause暂停/el-buttonel-button clickresume继续监听/el-buttonel-button clickstop停止监听/el-button/el-card
/template
script setup langts
import { reactive, watch } from vueconst count reactive({num1: 1,
})const { stop, resume, pause } watch(() count.num1,(newNum, oldNum) {console.log(oldNum, newNum)},
)
/script注意仅支持 vue 3.5 及以上版本
官方文档地址响应式 API核心 | Vue.js (vuejs.org) 8. 清理副作用
侦听器会在数据源变化时执行一些“副作用”。但这些“副作用”可能会产生一些需要后续清理的资源如未完成的异步请求、事件监听器等Vue提供了机制来清理这些资源以避免内存泄漏或其他潜在问题。
1. watch
在Vue 3.5之前watch的第三个参数是一个可选的副作用清理函数。这个函数会在侦听器被停用或组件卸载时调用允许你进行资源清理。
watch(id, async (newId, oldId, onCleanup) {const { response, cancel } doAsyncWork(newId)// 当 id 变化时cancel 将被调用// 取消之前的未完成的请求onCleanup(cancel)data.value await response
})在Vue 3.5
import { onWatcherCleanup } from vuewatch(id, async (newId) {const { response, cancel } doAsyncWork(newId)onWatcherCleanup(cancel)data.value await response
})2. watchEffect
在Vue 3.5之前 watchEffect 的第一个参数为副作用清理函数.
watchEffect(async (onCleanup) {const { response, cancel } doAsyncWork(newId)// 如果 id 变化则调用 cancel// 如果之前的请求未完成则取消该请求onCleanup(cancel)data.value await response
})在Vue 3.5
import { onWatcherCleanup } from vuewatchEffect(async () {const { response, cancel } doAsyncWork(newId)// 如果 id 变化则调用 cancel// 如果之前的请求未完成则取消该请求onWatcherCleanup(cancel)data.value await response
})注意onWatcherCleanup 仅在 Vue 3.5 中支持并且必须在 watchEffect 效果函数或 watch 回调函数的同步执行期间调用不能在异步函数的 await 语句之后调用它。 若有错误或描述不当的地方烦请评论或私信指正万分感谢 如果我的文章对你有帮助你的赞就是对我的最大支持^_^