Vue3 完整学习笔记 - 第二部分
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>