Vue3.4新功能:defineModel 让双向绑定更简单

更新日期: 2025-10-12 阅读: 129 标签: 双向绑定

vue 3.4 带来了一个很实用的新功能:defineModel。这个功能让 v-model 双向绑定的代码变得特别简洁。以前需要写很多行的代码,现在一行就能搞定。


以前的 v-model 写法

在 Vue 3.3 及之前的版本中,我们要在子组件里实现 v-model 功能,需要写不少代码。

比如我们要做一个自定义输入框组件:

<!-- CustomInput.vue -->
<script setup>
// 1. 先定义 props
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  }
})

// 2. 再定义 emits
const emit = defineEmits(['update:modelValue'])

// 3. 写事件处理函数
const handleInput = (event) => {
  // 4. 手动触发更新
  emit('update:modelValue', event.target.value)
}
</script>

<template>
  <input
    :value="modelValue"        <!-- 5. 绑定值 -->
    @input="handleInput"       <!-- 6. 绑定事件 -->
   
    placeholder="请输入内容"
  />
</template>

可以看到,为了实现双向绑定,我们需要完成 6 个步骤。这还只是一个 v-model,如果要支持多个 v-model,代码就更复杂了。

比如用户信息表单组件:

<!-- UserForm.vue -->
<script setup>
// 每个属性都要定义 props
const props = defineProps({
  firstName: String,
  lastName: String,
  email: String
})

// 每个属性都要定义 emits
const emit = defineEmits([
  'update:firstName',
  'update:lastName', 
  'update:email'
])

// 每个属性都要写处理函数
const updateFirstName = (e) => emit('update:firstName', e.target.value)
const updateLastName = (e) => emit('update:lastName', e.target.value)  
const updateEmail = (e) => emit('update:email', e.target.value)
</script>

<template>
  <div class="user-form">
    <input :value="firstName" @input="updateFirstName" placeholder="姓" />
    <input :value="lastName" @input="updateLastName" placeholder="名" />
    <input :value="email" @input="updateEmail" placeholder="邮箱" />
  </div>
</template>

这种写法不仅麻烦,还容易出错。有时候可能会写错事件名,或者忘记触发更新。


Vue 3.4 的新写法:defineModel

现在有了 defineModel,一切都变得简单了。同样的功能,代码量大大减少。

单个 v-model 的情况:

<!-- CustomInput.vue -->
<script setup>
// 只需要这一行
const modelValue = defineModel()
</script>

<template>
  <input
    v-model="modelValue"      <!-- 直接使用 v-model -->
   
    placeholder="请输入内容" 
  />
</template>

多个 v-model 的情况:

<!-- UserForm.vue -->
<script setup>
// 每个 v-model 都是一行代码
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
const email = defineModel('email')
</script>

<template>
  <div class="user-form">
    <input v-model="firstName" placeholder="姓" />
    <input v-model="lastName" placeholder="名" />
    <input v-model="email" placeholder="邮箱" />
  </div>
</template>

父组件的用法跟以前完全一样:

<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'
import UserForm from './UserForm.vue'

const inputValue = ref('初始值')

const firstName = ref('张')
const lastName = ref('三')
const email = ref('zhangsan@example.com')
</script>

<template>
  <!-- 单个 v-model -->
  <CustomInput v-model="inputValue" />
  <p>当前值: {{ inputValue }}</p>
  
  <!-- 多个 v-model -->
  <UserForm
    v-model:firstName="firstName"
    v-model:lastName="lastName"
    v-model:email="email"
  />
</template>


defineModel 的高级用法

defineModel 不只是简化代码,它还支持一些高级功能。

设置默认值和类型

<script setup>
const title = defineModel({
  type: String,
  default: '默认标题'
})

const count = defineModel('count', {
  type: Number,
  default: 0,
  required: true
})
</script>

自定义修饰符

Vue 的 v-model 支持修饰符,比如 .trim、.number。用 defineModel 也可以处理自定义修饰符。

<script setup>
// 定义带修饰符的 model
const modelValue = defineModel({
  set(value) {
    // 如果有 uppercase 修饰符,就转成大写
    if (modelValue.modifiers.uppercase) {
      return value.toUpperCase()
    }
    return value
  }
})
</script>

<template>
  <input v-model="modelValue" />
</template>

在父组件中使用:

<template>
  <!-- 使用自定义修饰符 -->
  <CustomInput v-model.uppercase="textValue" />
</template>

在组合式函数中使用

defineModel 也可以在组合式函数中使用,这让代码复用更加方便。

<script setup>
// 封装一个带验证的 model
function useValidatedModel(initialValue, validator) {
  const model = defineModel({
    default: initialValue
  })
  
  const error = ref('')
  
  watch(model, (newValue) => {
    const result = validator(newValue)
    if (result !== true) {
      error.value = result
    } else {
      error.value = ''
    }
  })
  
  return {
    model,
    error
  }
}

// 使用
const { model: username, error: usernameError } = useValidatedModel('', (value) => {
  if (value.length < 3) return '用户名至少3个字符'
  return true
})
</script>


从旧代码迁移到 defineModel

如果你有现有的项目,想要改用 defineModel,迁移过程很简单。可以一个一个组件慢慢改,不用一次性全部迁移。

迁移步骤:

  1. 删除 defineProps 中的 modelValue 定义

  2. 删除 defineEmits 中的 update:modelValue 定义

  3. 添加 const modelValue = defineModel()

  4. 把模板中的 :value="modelValue" @input="handleInput" 改成 v-model="modelValue"

举个例子,把之前的 CustomInput 组件迁移到新写法:

迁移前:

<script setup>
const props = defineProps({
  modelValue: String
})
const emit = defineEmits(['update:modelValue'])
const handleInput = (e) => emit('update:modelValue', e.target.value)
</script>

<template>
  <input :value="modelValue" @input="handleInput" />
</template>

迁移后:

<script setup>
const modelValue = defineModel()
</script>

<template>
  <input v-model="modelValue" />
</template>


实际项目中的使用建议

什么时候用 defineModel

  • 新的项目:直接使用 defineModel

  • 老的项目:可以逐步迁移,优先修改经常使用的组件

  • 团队项目:统一约定使用方式,保持代码一致性

需要注意的地方

  1. 版本要求:需要 Vue 3.4 或更高版本

  2. 类型支持:如果你用 TypeScript,defineModel 有很好的类型推断

  3. 浏览器兼容:和 Vue 3 的浏览器支持保持一致

性能考虑

defineModel 在性能上和原来的写法没有明显差别。它主要是在编译时进行转换,运行时的表现跟原来差不多。


总结

Vue 3.4 的 defineModel 确实让双向绑定的代码变得更加简洁。从原来需要写很多行代码,到现在只需要一行,这大大提高了开发效率。

这个改进不仅减少了代码量,也让代码更容易理解和维护。特别是对于新手来说,学习成本降低了,不用再记那些复杂的 props 和 emits 写法。

如果你还在用老版本的 Vue,可以考虑升级到 3.4 来体验这个新功能。如果你已经开始用 Vue 3.4,那么现在就可以在项目中使用 defineModel 来简化你的代码了。

好的工具应该让开发变得更简单,defineModel 正是这样一个好工具。它保留了 Vue 易用性的特点,同时让代码更加简洁明了。

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/12999

原生js实现数据双向绑定的三种方式总汇

前端的视图层和数据层有时需要实现双向绑定(two-way-binding),例如mvvm框架,数据驱动视图,视图状态机等,研究了几个目前主流的数据双向绑定框架,总结了下。目前实现数据双向绑定主要有以下三种。

Vue双向绑定的实现原理

vue.js 采用数据劫持的方式,结合发布者-订阅者模式,通过Object.defineProperty()来劫持各个属性的setter,getter以监听属性的变动,在数据变动时发布消息给订阅者,触发相应的监听回调.

vue双向数据绑定失效_解决vue添加新属性实现双向绑定

vue框架目前在前端开发使用比较广了,但是又很多同学发现vue创建对象之后添加新的属性实现不了双向绑定,下面就简单介绍如何解决vue双向绑定出现失效的问题

vue2 实现 div contenteditable=true 类似于 v-model双向数据绑定的效果

用到 contenteditable=true的 div ,而在这个 div 上是使用 v-model 是没有效果的,这里的双向数据绑定该如何实现?解决思路:一自定义指令,二使用组件。

自定义 Vue 中的 v-model 双向绑定

v-model 双向绑定实际上就是通过子组件中的 $emit 方法派发 input 事件,父组件监听 input 事件中传递的 value 值,并存储在父组件 data 中;然后父组件再通过 prop 的形式传递给子组件 value 值,再子组件中绑定 input 的 value 属性即可。

vue双向绑定原理分析

当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理。vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter

简单实现一个vue的双向绑定

首先我们来看一些,vue的基本使用方法;然后我们根据使用方法,来设计一个类和一些基础的声明周期;获取根元素;生命周期 beforeCreate;获取初始数据;获取渲染函数

React input表单双向数据绑定仿Vue v-model实现

用过Vue的同学都知道,Vue里<input> 、 <textarea> 及 <select>等表单元素可以通过v-model指令实现双向数据绑定,也就是说,当用户通过交互改变表单的值时,表单绑定的数据也会同步响应,这一点也是Vue对开发人员非常友好的点之一。

js 超浓缩 双向绑定

绑定确实是个有趣的话题。现在我的绑定器有了不少的功能1. 附着在Object对象上,一切以对象为中心2. 与页面元素进行双向绑定

Vue - 自定义组件双向绑定

无论在任何的语言或框架中,我们都提倡代码的复用性。对于Vue来说也是如此,相同的代码逻辑会被封装成组件,除了复用之外,更重要的是统一管理提高开发效率。我真就接手过一个项目,多个页面都会用到的列表

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!