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. 響應式工具函數

toRawmarkRaw

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 開發中遊刃有餘。