vue3中使用defineModel

是的!从 Vue 3.4 开始,Vue 官方引入了 defineModel() 编译宏(macro),极大简化了组件中实现 v-model 双向绑定的写法 ,无需手动声明 propsemit,也无需处理 modelValue / update:modelValue 的样板代码。

下面系统讲解 defineModel() 的使用方式、原理、优势和注意事项。


一、基础用法:替代 modelValue + emit

传统写法(Vue 3.0 ~ 3.3)

xml 复制代码
<!-- Child.vue -->
<script setup>
  const props = defineProps(['modelValue'])
  const emit = defineEmits(['update:modelValue'])

  function update() {
    emit('update:modelValue', props.modelValue + 1)
  }
</script>

<template>
  <div>{{ props.modelValue }}</div>
  <button @click="update">+</button>
</template>

Vue 3.4+ 新写法: defineModel()

xml 复制代码
<!-- Child.vue -->
<script setup>
  const model = defineModel() // 返回一个 ref

  function update() {
    model.value++ // 直接修改,自动同步到父组件
  }
</script>

<template>
  <div>Parent bound v-model is: {{ model }}</div>
  <button @click="update">Increment</button>
</template>

父组件完全不变:

xml 复制代码
<template>
  <Child v-model="count" />
</template>

<script setup>
  import { ref } from 'vue'
  const count = ref(0)
</script>

model 是一个 双向绑定的 ref

  • 读取 model.value → 获取父组件传入的值
  • 修改 model.value → 自动触发 update:modelValue,更新父组件数据

二、支持带参数的 v-model (多模型绑定)

Vue 支持多个 v-model,例如:

xml 复制代码
<Parent>
  <Child v-model:name="name" v-model:age="age" />
</Parent>

使用 defineModel 实现:

xml 复制代码
<!-- Child.vue -->
<script setup>
  const name = defineModel('name')
  const age = defineModel('age')

  // 或者用对象形式(可选)
  // const { name, age } = defineModels({ name: String, age: Number })
</script>

<template>
  <input v-model="name" />
  <input v-model.number="age" />
</template>

注意:defineModel('propName') 会自动对应 v-model:propName


三、类型与默认值(TypeScript / 运行时校验)

1. 指定类型(TypeScript)

c 复制代码
const model = defineModel<string>()
// model.value 类型为 string | undefined

2. 设置默认值

arduino 复制代码
const model = defineModel({ default: 'hello' })

3. 运行时校验 + 默认值

php 复制代码
const model = defineModel({
  type: String,
  required: false,
  default: 'default text'
})

💡 这些选项会自动转换为等效的 ****props ****声明,由 Vue 编译器处理。


四、与 useAttrs() 协同工作

虽然 defineModel() 自动处理了 modelValue,但其他属性仍需透传:

xml 复制代码
<script setup>
  const model = defineModel()
  // 如果有多个根节点,或想控制透传位置,才需要 useAttrs
</script>

<template>
  <!-- 单根节点:自动透传 attrs(包括 class/style/@focus 等) -->
  <input v-model="model" />
</template>

如果组件有多个根节点 ,必须手动使用 v-bind="$attrs",否则 Vue 会警告。


五、总结:为什么推荐 defineModel()

对比项 传统方式 defineModel()
代码量 多(props + emits) 极简(一行)
易错性 容易拼错 update:modelValue 零错误
可读性 逻辑分散 聚焦数据流
封装效率 高(尤其包装原生元素)
TypeScript 支持 需手动标注 自动推导

一句话
defineModel() ****让组件的双向绑定回归"直觉"------就像操作本地状态一样简单,却能自动同步到父组件。


相关推荐
counterxing8 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq8 小时前
windows下nginx的安装
linux·服务器·前端
之歆8 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜8 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai108088 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
kyriewen10 小时前
产品经理把PRD写成“天书”,我用AI半小时重写了一遍,他当场愣住
前端·ai编程·cursor
humcomm11 小时前
元框架的工作原理详解
前端·前端框架
canonical_entropy11 小时前
Attractor Before Harness: AI 大规模开发的方法论
前端·aigc·ai编程
zhangxingchao11 小时前
多 Agent 架构到底怎么选?从 Claude Agent Teams、Cognition/Devin 到工程落地原则
前端·人工智能·后端
IT_陈寒11 小时前
SpringBoot那个自动配置的坑,害我排查到凌晨三点
前端·人工智能·后端