v-model ,在 vue3和 vue2中的区别

Vue 3 的 v-model 设计更简洁、灵活,减少了配置成本,同时支持更复杂的双向绑定场景,是对 Vue 2 语法的重要改进。

1. 自定义组件的默认 Prop 和事件不同

  • Vue 2

    自定义组件使用 v-model 时,默认绑定 value 作为 prop,input 作为事件。

    <Child v-model="parentVal" /> 等价于:

    javascript 复制代码
    <Child :value="parentVal" @input="parentVal = $event" />

    子组件:

    javascript 复制代码
    <template>
      <input 
        :value="value" 
        @input="$emit('input', $event.target.value)"
      />
    </template>
    
    <script>
    export default {
      name: 'CustomInput',
      props: {
        value: {
          type: String,
          default: ''
        }
      }
    }
    </script>

    若要修改默认的 prop / 事件,需在子组件中通过 model 选项声明:

    javascript 复制代码
    // 子组件(Vue 2)
    export default {
      model: {
        prop: 'checked', // 自定义 prop 名
        event: 'change'  // 自定义事件名
      },
      props: ['checked']
    }
  • Vue 3

    自定义组件使用 v-model 时,默认绑定 modelValue 作为 prop,update:modelValue 作为事件。

    <Child v-model="parentVal" /> 等价于:

    javascript 复制代码
    <Child 
      :modelValue="parentVal" 
      @update:modelValue="parentVal = $event" 
    />

    无需额外配置,直接在子组件中声明 modelValue prop 即可:

    javascript 复制代码
    <!-- 子组件 -->
    <script setup>
    
    defineProps(['modelValue'])
    
    </script>

2. 支持多个 v-model 绑定

  • Vue 2

    一个组件只能有一个 v-model,若需多个双向绑定,必须手动绑定多个 prop 和事件:

    javascript 复制代码
    <Child 
      :name="userName" @name-change="userName = $event"
      :age="userAge" @age-change="userAge = $event"
    />
  • Vue 3

    支持通过参数化 v-model 实现多个双向绑定,语法为 v-model:propName

    例如同时绑定 nameage

    javascript 复制代码
    <!-- 父组件 -->
    <Child 
      v-model:name="userName" 
      v-model:age="userAge" 
    />

    子组件中对应声明 nameage prop,并通过 update:nameupdate:age 事件更新:

    javascript 复制代码
    <!-- 子组件 -->
    <script setup>
    const props = defineProps(['name', 'age'])
    const emit = defineEmits(['update:name', 'update:age'])
    </script>
    
    <template>
      <input 
        :value="name" 
        @input="emit('update:name', $event.target.value)"
      />
      <input 
        :value="age" 
        @input="emit('update:age', $event.target.value)"
      />
    </template>

3. 修饰符处理方式不同

  • Vue 2

    自定义组件使用 v-model 修饰符(如 .trim)时,需在子组件中通过 model.modifiers 手动处理,逻辑繁琐:

    javascript 复制代码
    // Vue 2 子组件处理修饰符
    export default {
      model: { prop: 'value', event: 'input' },
      props: {
        value: String,
        modifiers: { default: () => ({}) } // 接收修饰符
      },
      methods: {
        handleInput(val) {
          if (this.modifiers.trim) {
            val = val.trim()
          }
          this.$emit('input', val)
        }
      }
    }
  • Vue 3

    修饰符会自动作为 modelModifiers prop 传递(参数化 v-model 则为 propNameModifiers),处理更直接:

    javascript 复制代码
    <!-- 父组件使用修饰符 -->
    <Child v-model.uppercase="text" />
    
    <!-- 子组件处理修饰符 -->
    <script setup>
    const props = defineProps({
      modelValue: String,
      modelModifiers: { default: () => ({}) } // 自动接收修饰符
    })
    const emit = defineEmits(['update:modelValue'])
    
    const handleInput = (e) => {
      let val = e.target.value
      if (props.modelModifiers.uppercase) { // 直接使用修饰符
        val = val.toUpperCase()
      }
      emit('update:modelValue', val)
    }
    </script>

总结:核心差异对比

特性 Vue 2 中的 v-model Vue 3 中的 v-model
默认 prop / 事件 value + input modelValue + update:modelValue
多个双向绑定 不支持,需手动绑定多个 prop / 事件 支持 v-model:propName 语法
修饰符处理 需通过 model.modifiers 手动处理 自动解析为 modelModifiers prop
自定义 prop / 事件名 需通过 model 选项配置 无需配置,通过 v-model:prop 直接实现