《v-model原理 》以及 《自定义组件实现v-model》

104 阅读2分钟

一、v-model 的实现机制解析

1. 表单元素中的实现机制

v-model 的实现本质是通过 双向数据绑定语法糖,将 v-bind:valuev-on:input 组合封装。

<input v-model="message">

等价于以下代码

<input 
  :value="message" 
  @input="message = $event.target.value"
>

数据 → 视图:通过 v-bind:value 将数据绑定到表单的 value 属性(或 checkedselected 等属性)

视图 → 数据:监听 input 事件(或其他适配事件),通过事件对象 $event.target.value 更新数据


二、 自定义组件中的实现机制

在自定义组件中,v-model 通过 props + 事件 的组合实现父子组件双向通信,且支持 多数据绑定(Vue 3 特性)。

1、父组件实现

通过 v-model:test_data 指定自定义 prop 名称,将父组件 data 变量绑定到子组件的 test_data prop

<template> 
  <ChildComponent v-model:test_data="data" /> 
 </template> 
 
<script> 
  import ChildComponent from "./ChildComponent" 
  const data = ref('aaa') 
</script> 
   
<style> </style>

2、子组件实现

props 接收:通过 test_data prop 接收父组件数据

事件触发:通过 emit('update:test_data') 事件反向更新父组件数据

双向同步:子组件修改数据后,父组件的 data 变量会自动更新

// 接收父组件传递的 prop
const props = defineProps({
  test_data: {
    type: String,
    required: true
  }
});

// 定义事件发射器
const emit = defineEmits(['update:test_data']);

// 数据更新逻辑
const handleChange = (str) => {
  emit('update:test_data', str); // 触发自定义事件,告知父组件更新数据
}

三、 为什么定义emit事件为 update:xxx

update:xxx 是 Vue 的​​双向绑定约定语法​​,当父组件通过 v-model:test_data 绑定时:

  1. ​自动映射​​:

    父组件的 v-model:test_data="data" 会被编译为:

    <ChildComponent 
      :test_data="data" 
      @update:test_data="data = $event"
    />
    

    子组件的 emit('update:test_data', newValue) 会触发父组件的数据更新。

四、v-model可以绑定多个

v-model支持 ​​多字段扩展​​:

允许一个组件同时绑定多个独立字段(如 v-model:firstName 和 v-model:lastName

<CustomInput 
  v-model:first-name="firstName" 
  v-model:last-name="lastName"
/>

(PS): 同时绑定多个独立数据流,需在子组件分别定义对应的 props 和 emit 事件

五、 注意事项

  1. 避免直接修改 prop :子组件应通过事件触发更新,而非直接修改父组件传递的 prop

    若传递的数据是对象或者数组类型,建议 深拷贝一份,改完再emit

    lodash 拷贝比较方便

    npm install lodash

import _ from 'lodash'

let index = 2
const newDateList = _.cloneDeep(props.dateList)  //深拷贝一份
newDateList[index].isActive = true  // 修改拷贝后的数据
emit('update:dateList', newDateList)  // 将拷贝后的数据,告知父组件

// dateList: [{
//   day: "今天",
//   date: "00.00",
//   isActive: true,
//   enabled: true,
//   time_timestamp_JSDate: 1713120000,
//   time_timestamp_moment: 42341414,
//   UTC_str: "Tue Apr 15 2025 19:00:00 GMT+0800 (中国标准时间)"
// }]
  1. 复杂数据结构处理
    对象类型数据需使用 v-model 的深层绑定特性(Vue 3 新增)

  2. 性能敏感场景
    高频输入场景建议使用 .lazy 修饰符减少更新频率