生化危机4重制版修改器 v20260203 三十六项修改器 By 风灵月影
2026/4/16 20:49:16
侦听器是Vue3中用于响应数据变化的核心工具,当你需要在数据变化时执行异步或复杂的操作时,侦听器就派上用场了。比如:
export default { data() { return { question: '', answer: 'Questions usually contain a question mark. ;-)', loading: false } }, watch: { // 当question变化时触发 question(newQuestion, oldQuestion) { if (newQuestion.includes('?')) { this.getAnswer() } } }, methods: { async getAnswer() { this.loading = true this.answer = 'Thinking...' try { const res = await fetch('https://yesno.wtf/api') this.answer = (await res.json()).answer } catch (error) { this.answer = 'Error! Could not reach the API. ' + error } finally { this.loading = false } } } }<script setup> import { ref, watch } from 'vue' const question = ref('') const answer = ref('Questions usually contain a question mark. ;-)') const loading = ref(false) // 直接监听ref watch(question, async (newQuestion, oldQuestion) => { if (newQuestion.includes('?')) { loading.value = true answer.value = 'Thinking...' try { const res = await fetch('https://yesno.wtf/api') answer.value = (await res.json()).answer } catch (error) { answer.value = 'Error! Could not reach the API. ' + error } finally { loading.value = false } } }) </script> <template> <p> Ask a yes/no question: <input v-model="question" :disabled="loading" /> </p> <p>{{ answer }}</p> </template>默认情况下,侦听器是浅层的,只会监听引用类型的引用变化,不会监听内部属性变化。如果需要监听嵌套对象的变化,需要使用深度侦听器。
import { reactive, watch } from 'vue' const user = reactive({ name: 'John', address: { city: 'New York' } }) // 深度侦听整个对象 watch(user, (newUser, oldUser) => { console.log('User changed:', newUser) }, { deep: true }) // 或者只侦听嵌套属性 watch(() => user.address.city, (newCity) => { console.log('City changed to:', newCity) })默认情况下,侦听器是懒加载的,只有当数据变化时才会触发。如果需要在组件创建时立即执行一次,可以使用immediate: true选项。
watch(question, (newQuestion) => { // 这个回调会在组件创建时立即执行一次 }, { immediate: true })watchEffect是Vue3提供的另一种侦听器,它会自动追踪回调函数中的响应式依赖,当依赖变化时自动触发。
import { ref, watchEffect } from 'vue' const todoId = ref(1) const data = ref(null) // 自动追踪todoId的变化 watchEffect(async () => { const response = await fetch( `https://jsonplaceholder.typicode.com/todos/${todoId.value}` ) data.value = await response.json() })watchvswatchEffect对比流程图:
┌─────────────────┐ ┌─────────────────┐ │ watch │ │ watchEffect │ ├─────────────────┤ ├─────────────────┤ │ 显式指定依赖 │ │ 自动追踪依赖 │ │ 懒加载(默认) │ │ 立即执行 │ │ 可获取新旧值 │ │ 无法获取旧值 │ │ 更精确控制 │ │ 更简洁语法 │ └─────────────────┘ └─────────────────┘在Pinia中,我们可以使用Vue的`watch`函数来监听store中的状态变化。
首先创建一个Pinia store:
// stores/counter.js import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, message: 'Hello Pinia' }), actions: { increment() { this.count++ } } })然后在组件中监听store状态:
<script setup> import { watch } from 'vue' import { useCounterStore } from '@/stores/counter' const counterStore = useCounterStore() // 监听单个状态 watch(() => counterStore.count, (newCount, oldCount) => { console.log(`Count changed from ${oldCount} to ${newCount}`) }) // 监听多个状态 watch([() => counterStore.count, () => counterStore.message], ([newCount, newMessage], [oldCount, oldMessage]) => { console.log(`Count: ${oldCount} -> ${newCount}`) console.log(`Message: ${oldMessage} -> ${newMessage}`) } ) // 深度监听整个store watch(counterStore, (newStore, oldStore) => { console.log('Store changed:', newStore) }, { deep: true }) </script>假设我们有一个表单组件,需要将表单数据同步到Pinia store中,同时当store中的数据变化时,表单也需要更新。
<script setup> import { ref, watch } from 'vue' import { useFormStore } from '@/stores/form' const formStore = useFormStore() // 本地表单数据 const localForm = ref({ name: '', email: '' }) // 组件创建时同步store数据到本地 localForm.value = { ...formStore.formData } // 监听本地表单变化,同步到store watch(localForm, (newForm) => { formStore.updateFormData(newForm) }, { deep: true }) // 监听store数据变化,同步到本地 watch(() => formStore.formData, (newForm) => { localForm.value = { ...newForm } }, { deep: true }) </script> <template> <form> <input v-model="localForm.name" placeholder="Name" /> <input v-model="localForm.email" placeholder="Email" type="email" /> </form> </template>Pinia store代码:
// stores/form.js import { defineStore } from 'pinia' export const useFormStore = defineStore('form', { state: () => ({ formData: { name: '', email: '' } }), actions: { updateFormData(newData) { this.formData = { ...newData } } } })答案解析:
答案解析:可以直接将store实例作为watch的第一个参数,并设置deep: true选项:
watch(counterStore, (newStore, oldStore) => { console.log('Store changed:', newStore) }, { deep: true })或者使用getter函数:
watch(() => ({ ...counterStore }), (newStore) => { console.log('Store changed:', newStore) })原因:传递给watch的第一个参数不是有效的响应式源。比如直接传递了一个非响应式的对象或值。解决方法:
watch(() => obj.property, callback)原因:当使用getter函数作为watch源时,deep选项会被忽略,因为getter函数返回的是一个值,而不是引用类型。解决方法:
watch(() => ({ ...obj }), callback, { deep: true })原因:在watch回调中修改了被监听的数据,导致无限循环。解决方法:
watchEffect代替。原因:可能是因为没有正确使用getter函数来监听store中的状态。解决方法:
watch(() => store.count, callback)