1. 前置知识
- try,catch,finally
┌─────────────────────────────────────────┐
│ try { │
│ // 尝试执行的代码 │
│ // 如果出错,跳到 catch │
│ } │
│ catch (error) { │
│ // 出错时执行的代码 │
│ // error 是错误信息 │
│ } │
│ finally { │
│ // 不管成功失败都执行 │
│ // 通常用于清理工作 │
│ } │
└─────────────────────────────────────────┘
- async/awaiit :异步语法
- async关键字:async 放在函数前面,表示这个函数是异步的
// 普通函数
function sayHello() {
return 'Hello'
}
// async 函数
async function sayHelloAsync() {
return 'Hello'
}
sayHello() // 返回:'Hello'
sayHelloAsync() // 返回:Promise { 'Hello' }
async 函数 永远返回promise
- await关键字:await 只能用在async函数内部,意思是等待
async function cookDinner() {
console.log('1. 开始煮饭')
const rice = await cookRice() // ⏸️ 暂停,等饭煮好
console.log('2. 饭好了')
console.log('3. 开始炒菜')
const dish = await cookDish() // ⏸️ 暂停,等菜炒好
console.log('4. 菜好了')
return { rice, dish }
}
开始 → 煮饭 → ⏸️等待 → 饭好 → 炒菜 → ⏸️等待 → 菜好 → 结束
2. 侦听数据源类型
watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:
a. 侦听ref(包括计算属性)
import { ref, watch } from 'vue'
const count = ref(0)
// 直接传 ref,不需要 .value
watch(count, (newVal, oldVal) => {
console.log('count 变了:', oldVal, '→', newVal)
})
count.value++ // 触发 watch
b. 侦听响应式对象(reactive)
import { reactive, watch } from 'vue'
const user = reactive({
name: '张三',
age: 25
})
// 直接传 reactive 对象
watch(user, (newUser, oldUser) => {
console.log('user 对象变了:', newUser)
})
// 修改属性会触发
user.name = '李四' // ✅ 触发 watch
user.age = 26 // ✅ 触发 watch
重要区别
// ref - 监视整个 ref
const count = ref(0)
watch(count, callback) // count.value 变化时触发
// reactive - 监视对象内部属性
const obj = reactive({ a: 1 })
watch(obj, callback) // obj.a 变化时触发
c. 侦听getter函数
- getter函数就是返回响应式数据的函数
import { ref, watch } from 'vue'
const state = ref({ count: 0 })
// getter 函数:返回 state.value.count
watch(
() => state.value.count, // ← getter 函数
(newVal, oldVal) => {
console.log('count 变了:', oldVal, '→', newVal)
}
)
state.value.count++ // 触发 watch
为什么要用getter喊输呢?
ⅰ. 场景1:侦听对象的某个属性
const user = reactive({ name: '张三', age: 25 })
// ❌ 错误:这样监视的是整个对象
watch(user, callback)
// ✅ 正确:只监视 name 属性
watch(
() => user.name, // getter 函数
(newName, oldName) => {
console.log('名字变了:', oldName, '→', newName)
}
)
ⅱ. 场景2:侦听表达式
const price = ref(100)
const quantity = ref(2)
// 监视计算表达式
watch(
() => price.value * quantity.value, // getter 函数
(newTotal, oldTotal) => {
console.log('总价变了:', oldTotal, '→', newTotal)
}
)
ⅲ. 场景3:深层嵌套属性
const state = reactive({
user: {
profile: {
name: '张三'
}
}
})
// 只监视深层的 name
watch(
() => state.user.profile.name,
(newName, oldName) => {
console.log('名字变了')
}
)
d. 侦听多个数据源(数组)
import { ref, watch } from 'vue'
const name = ref('张三')
const age = ref(25)
// 数组形式监视多个数据源
watch(
[name, age], // ← 数组
([newName, newAge], [oldName, oldAge]) => {
console.log('name:', oldName, '→', newName)
console.log('age:', oldAge, '→', newAge)
}
)
name.value = '李四' // 触发
age.value = 26 // 触发
3. 深层侦听器
直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// 在嵌套的属性变更时触发
// 注意:`newValue` 此处和 `oldValue` 是相等的
// 因为它们是同一个对象!
})
obj.count++
如果给上面这个例子显式地加上 deep 选项,强制转成深层侦听器:
watch(
() => state.someObject,
(newValue, oldValue) => {
// 注意:`newValue` 此处和 `oldValue` 是相等的
// *除非* state.someObject 被整个替换了
},
{ deep: true }
)