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() ****让组件的双向绑定回归"直觉"------就像操作本地状态一样简单,却能自动同步到父组件。


相关推荐
炫饭第一名30 分钟前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫1 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊1 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter1 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折1 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_1 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
不会敲代码11 小时前
前端组件化样式隔离实战:React CSS Modules、styled-components 与 Vue scoped 对比
css·vue.js·react.js
Angelial1 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js
jiayu2 小时前
Angular学习笔记24:Angular 响应式表单 FormArray 与 FormGroup 相互嵌套
前端
jiayu2 小时前
Angular6学习笔记13:HTTP(3)
前端