Vue3 完整学习笔记 - 第二部分
2. Vue3 响应式系统深入
2.1 ref 深入理解
重点掌握:
- ref 的工作原理
- 基本类型和对象类型的处理差异
- template 中的自动解包
核心示例:
<template><div><!-- 模板中自动解包,无需 .value --><h1>{{ message }}</h1><p>Count: {{ count }}</p><button @click="increment">+1</button></div>
</template><script setup>
import { ref } from 'vue'// 基本类型的响应式
const count = ref(0)
const message = ref('Hello')// 在 JS 中需要 .value
const increment = () => {count.value++message.value = `Count is ${count.value}`
}// 对象类型的响应式
const user = ref({name: 'John',age: 30
})// 修改对象属性仍需要 .value
function updateUser() {user.value.age++// 或者整个替换对象user.value = { name: 'Jane', age: 25 }
}
</script>
2.2 reactive 深入理解
重点掌握:
- reactive 的使用场景
- 响应式对象的限制
- 解构和展开的处理
示例代码:
<template><div><h2>{{ state.user.name }}</h2><p>Age: {{ state.user.age }}</p><button @click="updateState">Update State</button></div>
</template><script setup>
import { reactive, toRefs } from 'vue'// 创建响应式对象
const state = reactive({user: {name: 'John',age: 30},settings: {theme: 'dark',notification: true}
})// ❌ 解构会失去响应性
const { user } = state// ✅ 使用 toRefs 保持响应性
const { settings } = toRefs(state)const updateState = () => {// 直接修改嵌套属性state.user.age++state.settings.theme = 'light'
}
</script>
2.3 toRefs 和 toRef 的使用
重点掌握:
- toRefs 的使用场景
- toRef 单个属性的处理
- 解构响应式对象的正确方式
示例代码:
<template><div><h2>{{ name }}</h2><p>Age: {{ age }}</p><button @click="increment">Age +1</button></div>
</template><script setup>
import { reactive, toRefs, toRef } from 'vue'const state = reactive({name: 'John',age: 30
})// 转换整个对象
const { name, age } = toRefs(state)// 或者单独转换一个属性
const ageRef = toRef(state, 'age')const increment = () => {// 都是响应式的age.value++// 或者ageRef.value++
}// 使用场景:组件属性解构
const props = defineProps(['title'])
const title = toRef(props, 'title')
</script>
2.4 computed 计算属性
重点掌握:
- 计算属性的基本使用
- getter 和 setter
- 计算属性缓存特性
示例代码:
<template><div><input v-model="firstName" /><input v-model="lastName" /><p>Full name: {{ fullName }}</p><!-- 使用可写计算属性 --><input v-model="fullName" /></div>
</template><script setup>
import { ref, computed } from 'vue'const firstName = ref('John')
const lastName = ref('Doe')// 只读计算属性
const fullName = computed(() => {return `${firstName.value} ${lastName.value}`
})// 可写计算属性
const fullName = computed({get() {return `${firstName.value} ${lastName.value}`},set(newValue) {[firstName.value, lastName.value] = newValue.split(' ')}
})// 带缓存的计算属性
const expensiveComputed = computed(() => {console.log('computing...')return someExpensiveOperation(firstName.value)
})
</script>
2.5 watch 侦听器基础
重点掌握:
- 基本数据类型的侦听
- 对象的侦听
- 多个数据源的侦听
示例代码:
<script setup>
import { ref, watch } from 'vue'const count = ref(0)
const message = ref('Hello')
const user = ref({ name: 'John', age: 30 })// 侦听单个ref
watch(count, (newValue, oldValue) => {console.log(`Count changed from ${oldValue} to ${newValue}`)
})// 侦听多个数据源
watch([count, message], ([newCount, newMessage], [oldCount, oldMessage]) => {console.log('Values changed:', { newCount, newMessage, oldCount, oldMessage })
})// 侦听对象
watch(user, (newUser, oldUser) => {console.log('User changed:', newUser, oldUser)
}, { deep: true }) // 深度侦听// 立即执行
watch(count, (newValue) => {console.log(`Initial count: ${newValue}`)
}, { immediate: true })
</script>
2.6 watchEffect 的使用
重点掌握:
- watchEffect 的自动依赖追踪
- 停止侦听
- 清理副作用
示例代码:
<script setup>
import { ref, watchEffect } from 'vue'const count = ref(0)
const message = ref('Hello')// 自动收集依赖
const stop = watchEffect(() => {console.log(`Count is ${count.value}`)console.log(`Message is ${message.value}`)
})// 带清理的副作用
watchEffect((onCleanup) => {const timer = setInterval(() => {count.value++}, 1000)// 清理函数onCleanup(() => clearInterval(timer))
})// 停止侦听
setTimeout(() => {stop()
}, 5000)// 异步请求示例
watchEffect(async () => {const response = await fetch(`/api/user/${count.value}`)const data = await response.json()message.value = data.name
})
</script>