Appearance
监听属性 watch
监听属性是Vue3中的一个重要特性,它允许你监听响应式数据的变化,并在数据变化时执行相应的操作。本章节将详细介绍Vue3中监听属性的使用方法和最佳实践。
什么是监听属性?
监听属性是Vue3中用于监听响应式数据变化的特性,当数据发生变化时,它会执行你指定的回调函数。
监听属性的基本使用
1. 监听单个数据
在Vue3的组合式API中,我们使用 watch 函数来监听数据变化:
vue
<template>
<div>
<input v-model="message" type="text">
<p>{{ message }}</p>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const message = ref('Hello')
watch(message, (newValue, oldValue) => {
console.log(`Message changed from ${oldValue} to ${newValue}`)
})
</script>2. 监听多个数据
你可以同时监听多个数据的变化:
vue
<template>
<div>
<input v-model="message" type="text">
<input v-model="count" type="number">
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const message = ref('Hello')
const count = ref(0)
watch([message, count], ([newMessage, newCount], [oldMessage, oldCount]) => {
console.log(`Message changed from ${oldMessage} to ${newMessage}`)
console.log(`Count changed from ${oldCount} to ${newCount}`)
})
</script>3. 监听对象
你可以监听对象的变化:
vue
<template>
<div>
<input v-model="user.name" type="text">
<input v-model="user.age" type="number">
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const user = reactive({
name: 'John',
age: 25
})
watch(user, (newUser, oldUser) => {
console.log('User changed:', newUser, oldUser)
})
</script>监听属性的配置选项
1. deep 选项
默认情况下,watch 只监听对象的引用变化,不会监听对象内部属性的变化。如果要监听对象内部属性的变化,需要使用 deep 选项:
vue
<template>
<div>
<input v-model="user.name" type="text">
<input v-model="user.age" type="number">
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const user = reactive({
name: 'John',
age: 25
})
watch(user, (newUser, oldUser) => {
console.log('User changed:', newUser, oldUser)
}, { deep: true })
</script>2. immediate 选项
默认情况下,watch 只在数据变化时执行回调函数。如果要在监听开始时就执行一次回调函数,需要使用 immediate 选项:
vue
<template>
<div>
<input v-model="message" type="text">
<p>{{ message }}</p>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const message = ref('Hello')
watch(message, (newValue, oldValue) => {
console.log(`Message changed from ${oldValue} to ${newValue}`)
}, { immediate: true })
</script>3. flush 选项
flush 选项用于控制回调函数的执行时机:
- pre:在组件更新之前执行(默认)
- post:在组件更新之后执行
- sync:同步执行
vue
<template>
<div>
<input v-model="message" type="text">
<p>{{ message }}</p>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const message = ref('Hello')
watch(message, (newValue, oldValue) => {
console.log(`Message changed from ${oldValue} to ${newValue}`)
}, { flush: 'post' })
</script>watchEffect
watchEffect 是Vue3中另一个用于监听数据变化的API,它会自动追踪响应式数据的变化:
vue
<template>
<div>
<input v-model="message" type="text">
<input v-model="count" type="number">
</div>
</template>
<script setup>
import { ref, watchEffect } from 'vue'
const message = ref('Hello')
const count = ref(0)
watchEffect(() => {
console.log(`Message: ${message.value}, Count: ${count.value}`)
})
</script>watchEffect vs watch
watchEffect:
- 自动追踪响应式数据的变化
- 立即执行一次回调函数
- 无法获取旧值
- 更简洁,适合简单的场景
watch:
- 需要明确指定要监听的数据
- 默认只在数据变化时执行
- 可以获取旧值
- 更灵活,适合复杂的场景
监听属性的使用场景
1. 数据变化时执行副作用操作
vue
<template>
<div>
<input v-model="search" type="text" placeholder="Search">
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const search = ref('')
watch(search, (newSearch) => {
// 当搜索词变化时,发送请求获取数据
fetch(`https://api.example.com/search?q=${newSearch}`)
.then(response => response.json())
.then(data => {
console.log(data)
})
})
</script>2. 表单验证
vue
<template>
<div>
<input v-model="email" type="email" placeholder="Email">
<p v-if="error" style="color: red;">{{ error }}</p>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const email = ref('')
const error = ref('')
watch(email, (newEmail) => {
if (!newEmail) {
error.value = 'Email is required'
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(newEmail)) {
error.value = 'Invalid email format'
} else {
error.value = ''
}
})
</script>3. 数据持久化
vue
<template>
<div>
<input v-model="message" type="text">
</div>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue'
const message = ref('')
// 组件挂载时从本地存储获取数据
onMounted(() => {
const savedMessage = localStorage.getItem('message')
if (savedMessage) {
message.value = savedMessage
}
})
// 数据变化时保存到本地存储
watch(message, (newMessage) => {
localStorage.setItem('message', newMessage)
})
</script>4. 计算属性的替代方案
当计算属性需要执行异步操作时,可以使用 watch 替代:
vue
<template>
<div>
<input v-model="userId" type="number">
<p v-if="loading">Loading...</p>
<p v-else-if="error">{{ error }}</p>
<p v-else>{{ user.name }}</p>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const userId = ref(1)
const user = ref(null)
const loading = ref(false)
const error = ref('')
watch(userId, async (newUserId) => {
loading.value = true
error.value = ''
try {
const response = await fetch(`https://api.example.com/users/${newUserId}`)
if (!response.ok) {
throw new Error('User not found')
}
user.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}, { immediate: true })
</script>监听属性的最佳实践
1. 合理使用深度监听
深度监听会遍历对象的所有属性,可能会影响性能,因此应该只在必要时使用:
javascript
// 好的做法:只监听需要的属性
watch(() => user.name, (newName, oldName) => {
console.log(`Name changed from ${oldName} to ${newName}`)
})
// 不好的做法:深度监听整个对象
watch(user, (newUser, oldUser) => {
console.log('User changed:', newUser, oldUser)
}, { deep: true })2. 清理副作用
当监听属性执行的操作需要清理时,应该在回调函数中返回一个清理函数:
javascript
watch(search, (newSearch) => {
// 发送请求前取消之前的请求
const controller = new AbortController()
fetch(`https://api.example.com/search?q=${newSearch}`, {
signal: controller.signal
})
.then(response => response.json())
.then(data => {
console.log(data)
})
// 返回清理函数
return () => {
controller.abort()
}
})3. 避免在回调函数中修改被监听的数据
在监听属性的回调函数中修改被监听的数据可能会导致无限循环:
javascript
// 不好的做法:在回调函数中修改被监听的数据
watch(count, (newCount) => {
// 这会导致无限循环
count.value = newCount + 1
})4. 合理使用 watchEffect
对于简单的场景,使用 watchEffect 可以使代码更简洁:
javascript
// 使用 watchEffect
watchEffect(() => {
localStorage.setItem('message', message.value)
})
// 等价于
watch(message, (newMessage) => {
localStorage.setItem('message', newMessage)
}, { immediate: true })总结
监听属性是Vue3中的一个重要特性,它允许你监听响应式数据的变化,并在数据变化时执行相应的操作。通过 watch 和 watchEffect,你可以实现数据变化时的副作用操作、表单验证、数据持久化等功能。
在使用监听属性时,你应该合理使用深度监听,清理副作用,避免在回调函数中修改被监听的数据,以及根据场景选择合适的监听API。
在后续的章节中,我们将学习Vue3的样式绑定,以及它的使用方法和最佳实践。
