前端核心知识:Vue 3 编程的 10 个实用技巧

Vue 3 编程的 10 个实用技巧
(2025–2026 仍在大量实际项目中高频使用的核心写法)

以下内容聚焦 Vue 3 + Composition API 的真实工程实践,基本都是“写过很多项目后觉得最值得反复使用的技巧”。

1. 善用 toRefs 解构 reactive 对象,保持响应式

最容易犯的错误之一:解构 reactive 后丢失响应式。

// ❌ 错误写法
const state = reactive({ count: 0, name: 'tom' })
const { count, name } = state   // count 和 name 不再是响应式的

// ✅ 正确写法
const state = reactive({ count: 0, name: 'tom' })
const { count, name } = toRefs(state)

// 或者一次性全部解构
const { count, name, ...rest } = toRefs(state)

小技巧:当你需要把 reactive 对象传给子组件 props 时,也推荐用 toRefs 解构后传递单个 ref。

2. 使用 shallowRef / shallowReactive 做性能优化

当对象/数组非常大且你只关心顶层变化时,关闭深层响应能显著提升性能。

// 大型配置对象,只关心整体替换,不关心内部属性变化
const config = shallowRef({ theme: 'dark', size: 'large', ...很多字段 })

// 只需要这样替换就会触发更新
config.value = newConfig

// 或者 shallowReactive(对象顶层属性响应,嵌套不响应)
const form = shallowReactive({ name: '', age: 0, address: { city: '' } })
form.name = 'new'         // 触发
form.address.city = 'xx'  // 不会触发

适用场景:大型列表数据、表单初始值、第三方库返回的大对象。

3. 善用 computed 的 getter + setter 双向绑定

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (newValue: string) => {
    const [first, ...rest] = newValue.trim().split(' ')
    firstName.value = first || ''
    lastName.value = rest.join(' ') || ''
  }
})

// 使用时就像 v-model
<input v-model="fullName" />

这在复杂表单、地址拆分、金额千分位格式化等场景非常实用。

4. 自定义 ref + 自动转换(最优雅的输入处理方式)

function useTrimmedRef(initial = '') {
  return customRef<string>((track, trigger) => {
    let value = initial
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        const trimmed = newValue.trim()
        if (trimmed !== value) {
          value = trimmed
          trigger()
        }
      }
    }
  })
}

const username = useTrimmedRef('')

类似还可以做:数字自动转 number、自动大写、自动补零、输入防抖等。

5. 组合式函数(Composables)最佳实践命名与结构

推荐的 composable 文件结构与命名:

// src/composables/useUserInfo.ts
export function useUserInfo(userId?: string) {
  const user = ref(null)
  const loading = ref(false)
  const error = ref(null)

  const fetchUser = async () => {
    // ...
  }

  onMounted(fetchUser)

  return {
    user,
    loading,
    error,
    refresh: fetchUser
  }
}

命名约定(社区最常见):

  • useXxx → 最常见
  • useXxxState → 有状态管理
  • useXxxFetch → 数据请求相关
  • useXxxForm → 表单相关
  • useXxxModal → 弹窗控制

6. 用 watch + immediate + deep 的正确姿势

// 推荐写法(清晰、可读性高)
watch(
  () => props.someObject,
  (newVal, oldVal) => {
    // 处理逻辑
  },
  { deep: true, immediate: true }
)

// 更推荐:当你只关心某个属性时
watch(
  () => props.user?.id,
  (newId, oldId) => {
    if (newId) fetchUserDetail(newId)
  },
  { immediate: true }
)

7. 用 markRawunref 解决第三方库和 ref 嵌套问题

// 第三方库实例不要被代理(会很慢或出错)
const chartInstance = markRaw(new Chart(ctx, config))

// 快速取值(避免 .value 写太多)
const count = unref(someRef)   // ref 或 reactive 都适用

8. 优雅处理异步请求 + loading + error 状态

function useAsyncFn<T>(fn: () => Promise<T>) {
  const loading = ref(false)
  const error = ref<Error | null>(null)
  const data = ref<T | null>(null)

  const execute = async (...args: any[]) => {
    loading.value = true
    error.value = null
    try {
      data.value = await fn(...args)
    } catch (e) {
      error.value = e as Error
    } finally {
      loading.value = false
    }
  }

  return { execute, loading, error, data }
}

9. v-model 组件的现代写法(defineModel)

Vue 3.3+ 推荐写法(极大简化双向绑定组件)

// 子组件 MyInput.vue
const modelValue = defineModel<string>({ required: true })

// 等价于旧写法:
const modelValue = defineProps<{ modelValue: string }>().modelValue
const emit = defineEmits(['update:modelValue'])

甚至可以指定默认值、转换器:

const count = defineModel<number>({
  default: 0,
  get: (val) => Number(val),
  set: (val) => String(val)
})

10. 使用 useTemplateRef + onMounted 简化 DOM 操作(Vue 3.5+)

<template>
  <input ref="inputEl" />
</template>

<script setup>
const inputEl = useTemplateRef<HTMLInputElement>('inputEl')

onMounted(() => {
  inputEl.value?.focus()
})
</script>

不再需要 ref(null) 再类型断言,更加安全。

额外加餐:最常被忽略但非常好用的两个小技巧

  • useSlots() 判断插槽是否存在
    const hasHeader = !!useSlots().header
  • useAttrs() 透传所有未声明的属性
    非常适合封装组件时把 class、style、data-* 等自动透传给根元素。
const attrs = useAttrs()

这 10 个技巧覆盖了 Vue 3 日常开发中 80% 以上最容易踩坑和最能提升代码质量的地方。

你目前用 Vue 3 开发中最头疼的是哪一块?
(比如组合式函数组织、类型定义、性能优化、组件封装、状态管理……)
可以告诉我,我可以针对性再展开更详细的实战写法。

文章已创建 4391

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部