1. 深層響應式控制
shallowRef - 淺層 Ref
import { shallowRef, triggerRef } from 'vue'
const state = shallowRef({
count: 0,
nested: { value: 1 } // 這個變化不會被自動追蹤
})
// 只有直接賦值會觸發更新
state.value = { count: 1, nested: { value: 1 } }
// 深層修改需要手動觸發
state.value.nested.value = 2
triggerRef(state) // 手動觸發更新
shallowReactive - 淺層 Reactive
import { shallowReactive } from 'vue'
const state = shallowReactive({
level1: {
level2: { value: 1 } // 只有 level1 的變化會被追蹤
}
})
// 這個變化不會被響應
state.level1.level2.value = 2
// 這個變化會被響應
state.level1 = { level2: { value: 3 } }
2. 自定義 Ref 實現
防抖 Ref
import { customRef } from 'vue'
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
// 使用
const text = useDebouncedRef('', 500)
本地存儲 Ref
function useLocalStorageRef(key, defaultValue) {
return customRef((track, trigger) => {
return {
get() {
track()
const item = localStorage.getItem(key)
return item ? JSON.parse(item) : defaultValue
},
set(value) {
localStorage.setItem(key, JSON.stringify(value))
trigger()
}
}
})
}
const settings = useLocalStorageRef('user-settings', { theme: 'dark' })
3. 模板編譯特性
v-memo - 性能優化指令
<template>
<div v-memo="[user.id]">
<!-- 只有當 user.id 變化時才會重新渲染 -->
{{ user.name }}
<p>{{ user.email }}</p>
<!-- 大量靜態內容 -->
</div>
</template>
動態 CSS 綁定
<template>
<div class="text">Hello</div>
</template>
<style scoped>
.text {
color: v-bind(color); /* 動態 CSS 值 */
}
</style>
<script setup>
import { ref } from 'vue'
const color = ref('red')
</script>
4. 高級組件通信
多級 Provide/Inject
// 祖先組件
import { provide, ref } from 'vue'
const theme = ref('dark')
const toggleTheme = () => { theme.value = theme.value === 'dark' ? 'light' : 'dark' }
// 提供響應式數據和方法
provide('theme', {
theme,
toggleTheme
})
// 後代組件
import { inject } from 'vue'
const { theme, toggleTheme } = inject('theme')
模板引用轉發
<!-- Parent.vue -->
<template>
<ChildComponent ref="childRef" />
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './Child.vue'
const childRef = ref()
// 訪問子組件暴露的方法和屬性
const doSomething = () => {
childRef.value.someMethod()
}
</script>
<!-- Child.vue -->
<script setup>
import { defineExpose } from 'vue'
const someMethod = () => console.log('Hello from child!')
// 明確暴露給父組件的內容
defineExpose({
someMethod
})
</script>
5. 渲染函數與 JSX 技巧
條件渲染的優化寫法
import { h } from 'vue'
export default {
setup() {
return () => h('div', [
// 使用 null 替代空數組或 undefined
condition ? h(ComponentA) : null,
anotherCondition ? h(ComponentB) : null
])
}
}
動態組件註冊
import { defineAsyncComponent, shallowRef } from 'vue'
const components = shallowRef({})
// 動態註冊組件
function registerComponent(name, component) {
components.value[name] = defineAsyncComponent(() =>
import(`./components/${component}.vue`)
)
}
// 在模板中使用
const componentName = shallowRef('ComponentA')
6. 副作用管理與清理
自動清理的副作用
import { watchEffect, onScopeDispose } from 'vue'
function useEventListener(target, event, callback) {
watchEffect((onInvalidate) => {
target.addEventListener(event, callback)
// 自動清理
onInvalidate(() => {
target.removeEventListener(event, callback)
})
})
}
// 組件銷燬時自動清理
onScopeDispose(() => {
console.log('組件作用域銷燬')
})
自定義生命週期鈎子
import { onMounted, getCurrentInstance } from 'vue'
function onFirstMount(callback) {
const instance = getCurrentInstance()
let mounted = false
onMounted(() => {
if (!mounted) {
mounted = true
callback()
}
})
}
7. 響應式工具函數
toRaw 和 markRaw
import { reactive, toRaw, markRaw } from 'vue'
const state = reactive({
normal: { value: 1 },
rawObject: markRaw({ value: 2 }) // 不會被轉換為響應式
})
// 獲取原始對象
const raw = toRaw(state.normal)
// 標記對象永不轉為響應式
const largeList = markRaw([...]) // 適合大型不可變數據
readonly 和深層只讀
import { reactive, readonly } from 'vue'
const original = reactive({ count: 0 })
const copy = readonly(original)
// 這不會工作,因為是隻讀的
copy.count++
// 這會觸發 copy 的更新
original.count++
8. 編譯器宏的進階用法
類型安全的 Props 和 Emits
<script setup lang="ts">
interface Props {
title: string
count?: number
}
interface Emits {
(e: 'update:title', value: string): void
(e: 'submit', payload: { data: string }): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
// 帶默認值的 Props
const { title, count = 0 } = defineProps<Props>()
</script>
泛型組件
<script setup lang="ts" generic="T">
interface Props<T> {
items: T[]
itemKey: keyof T
}
defineProps<Props<T>>()
</script>
9. 性能優化技巧
惰性觀察器
import { watch, nextTick } from 'vue'
// 只在下一個 tick 執行
watch(source, () => {
// 這個回調會在下一個 tick 執行
}, { flush: 'post' })
// 同步執行
watch(source, () => {
// 同步執行
}, { flush: 'sync' })
批量更新優化
import { nextTick } from 'vue'
async function batchUpdate() {
// 多個狀態更新
state.a = 1
state.b = 2
state.c = 3
// 等待一次更新
await nextTick()
// DOM 已經更新
}
10. 組合式函數的高級模式
可組合的 Store 模式
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
function reset() {
count.value = initialValue
}
return {
count: readonly(count), // 只讀暴露
double,
increment,
reset
}
}
依賴注入的工廠函數
import { inject, provide } from 'vue'
const InjectionKey = Symbol()
export function useProvider(factory) {
provide(InjectionKey, factory)
}
export function useConsumer() {
const factory = inject(InjectionKey)
if (!factory) {
throw new Error('Provider not found')
}
return factory()
}
這些 Vue 3 的進階特性和技巧大部分開發者還是不瞭解的。掌握這些不為人知的知識點,能夠讓你在 Vue 3 開發中遊刃有餘。