Vue3 Composition API 深度開發指南
響應式系統核心解析
1.1 響應式原理解構
Vue3 基于 Proxy 實現響應式追蹤,其核心流程為:
const reactiveHandler = {get(target, key, receiver) {track(target, key) // 依賴收集return Reflect.get(target, key, receiver)},set(target, key, value, receiver) {const result = Reflect.set(target, key, value, receiver)trigger(target, key) // 觸發更新return result}
}function reactive(obj) {return new Proxy(obj, reactiveHandler)
}
關鍵差異:
ref
通過對象包裝實現基礎類型響應式reactive
直接代理整個對象shallowRef/shallowReactive
實現淺層響應
1.2 響應式工具進階
// 響應式轉換控制
const readonlyUser = readonly(reactive({ name: 'Alice' }))// 解構保持響應性
const { x, y } = toRefs(reactiveMousePosition)// Ref類型自動解包
const count = ref(0)
const double = computed(() => count.value * 2)
組件設計模式深度實踐
2.1 受控組件模式
// 通用表單控制邏輯
export function useFormControl<T>(initialValue: T) {const value = ref<T>(initialValue)const touched = ref(false)const setValue = (newValue: T) => {value.value = newValuetouched.value = true}return {value: readonly(value),isTouched: readonly(touched),setValue}
}// 組件實現
const emailControl = useFormControl<string>('')
2.2 依賴注入模式
// 上下文類型定義
interface EditorContext {content: Ref<string>formatters: Map<string, FormatterFn>
}// 提供者組件
const editorSymbol = Symbol() as InjectionKey<EditorContext>provide(editorSymbol, {content: ref(''),formatters: new Map([['bold', text => `**${text}**`]])
})// 消費者組件
const { formatters } = inject(editorSymbol)!
Composition API 高級模式
3.1 異步狀態機
type AsyncState<T> = {data: T | nullerror: Error | nullstatus: 'idle' | 'pending' | 'success' | 'error'
}export function useAsyncTask<T>(task: () => Promise<T>) {const state = reactive<AsyncState<T>>({data: null,error: null,status: 'idle'})const execute = async () => {state.status = 'pending'try {state.data = await task()state.status = 'success'} catch (err) {state.error = err as Errorstate.status = 'error'}}return { state, execute }
}// 使用示例
const { state, execute } = useAsyncTask(fetchUserList)
3.2 響應式存儲模式
class ReactiveStore<T extends object> {private state: Tprivate proxy: Tconstructor(initialState: T) {this.state = initialStatethis.proxy = reactive(initialState) as T}getState(): Readonly<T> {return readonly(this.proxy)}mutate(mutation: (state: T) => void) {mutation(this.proxy)}
}// 創建Store實例
const userStore = new ReactiveStore({id: 0,profile: { name: '' }
})// 組件中使用
const { id } = userStore.getState()
性能優化策略
4.1 計算屬性緩存策略
const heavyList = ref<Item[]>(/* 大數據集 */)// 帶緩存的篩選計算
const filteredList = computed(() => {return heavyList.value.filter(item => item.category === 'active' && item.value > 1000)
})// 計算屬性調試
const debugComputed = computed({get() { /* 原邏輯 */ },set() { /* 開發環境調試鉤子 */ }
})
4.2 虛擬滾動優化
// 虛擬滾動Composable
export function useVirtualScroll(options: {containerRef: Ref<HTMLElement | null>itemHeight: numbertotalItems: number
}) {const scrollTop = ref(0)const visibleCount = computed(() => Math.ceil(options.containerRef.value!.clientHeight / options.itemHeight))const startIndex = computed(() =>Math.floor(scrollTop.value / options.itemHeight))const endIndex = computed(() =>Math.min(startIndex.value + visibleCount.value + 2, options.totalItems))return { scrollTop, startIndex, endIndex }
}
類型系統深度集成
5.1 復雜類型推導
// 類型安全的provide/inject
const LOCALE_KEY = Symbol() as InjectionKey<{lang: Ref<string>setLang: (lang: string) => void
}>// Props類型增強
interface ModalProps {modelValue: booleantitle?: stringtransition?: 'fade' | 'slide'
}const props = defineProps<ModalProps>()// Emits類型約束
const emit = defineEmits<{(e: 'update:modelValue', value: boolean): void(e: 'confirm', payload: { timestamp: number }): void
}>()
5.2 泛型Composable
interface PaginationOptions<T> {initialPage: numberpageSize: numberfetcher: (page: number) => Promise<T[]>
}export function usePagination<T>(options: PaginationOptions<T>) {const currentPage = ref(options.initialPage)const list = ref<T[]>([]) as Ref<T[]>const loadPage = async () => {list.value = await options.fetcher(currentPage.value)}return {currentPage,list,loadPage}
}// 使用示例
const { list, loadPage } = usePagination<User>({initialPage: 1,pageSize: 20,fetcher: fetchUsers
})
工程化實踐
6.1 自定義指令開發
// 權限控制指令
const vPermission = {mounted(el: HTMLElement, binding: DirectiveBinding<string[]>) {const userPermissions = useAuthStore().permissionsif (!binding.value.some(perm => userPermissions.includes(perm))) {el.parentNode?.removeChild(el)}}
}// 使用方式
<button v-permission="['admin', 'editor']">刪除</button>
6.2 單元測試策略
// 測試Composable
import { useCounter } from './counter'
import { renderHook } from '@testing-library/vue'test('counter logic', async () => {const { result } = renderHook(() => useCounter(10))expect(result.current.count.value).toBe(10)await result.current.increment()expect(result.current.count.value).toBe(11)await result.current.reset()expect(result.current.count.value).toBe(10)
})
響應式調試技巧
7.1 依賴追蹤可視化
// 調試watch效果
const stop = watchEffect((onCleanup) => {console.log('依賴變化:', effectScope.activeEffect?.deps)onCleanup(() => {console.log('清理副作用')})
})// Chrome DevTools + Vue DevTools 組合調試
7.2 響應式樹分析
import { DebuggerEvent, debug } from 'vue'debug({onTrack(e: DebuggerEvent) {if (e.target === store) {console.log('Store被追蹤:', e)}},onTrigger(e: DebuggerEvent) {console.log('響應式觸發:', e)}
})