v-model 原理和使用

3,880 阅读1分钟

v-model可以实现双向绑定,它的原理:通过父传子、子传父来实现双向数据绑定,是个语法糖。

// 第一行的代码其实只是第二行的语法糖
<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />

// 第二行代码还能简写
// 给组件添加v-model属性时,默认把value(vue3更新为modelValue)作为组件的属性,'input' 值作为给组件绑定事件时的事件名
<input :value="sth" @input="sth = $event.target.value" />

Vue3更新属性:

  • prop:value -> modelValue
  • 事件:input -> update:modelValue
  • v-bind 的 .sync 修饰符和组件的 model 选项已移除,可在 v-model 上加一个参数代替;
  • 新增:现在可以在同一个组件上使用多个 v-model 绑定;
  • 新增:现在可以自定义 v-model 修饰符

2.x 语法
在 2.x 中,在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件

      <input
        v-model="title"
        type="text"
      >
      <input
        type="text"
        :value="title"
        @input="title = $event"
      >

如果想要更改 prop 或事件名称,则需要在子组件中添加 model 选项

// 父组件
<Test2 v-model="title" />

// 子组件
export default {
  model: {
    prop: 'title',
    event: 'change'
  },
  props: {
    // 这将允许 `value` 属性用于其他用途
    value: String,
    // 使用 `title` 代替 `value` 作为 model 的 prop
    title: {
      type: String,
      default: 'Default title'
    }
  }
}

// 简写
<Test2 :title="pageTitle" @change="pageTitle = $event" />

实现双向绑定:(.sync)

// 子组件 定义触发事件
this.$emit('update:title', newValue)

// 父组件中实时更新
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

// 上面可以使用 .sync 缩写为
<ChildComponent :title.sync="pageTitle" />

3.x 语法
更新

<ChildComponent :title.sync="pageTitle" />

<!-- 替换为 -->

<ChildComponent v-model:title="pageTitle" />

v-bind中默认的value属性,更新为modelValue属性

    <Test2 v-model="title" />
    // 缩写
    <Test2
      :model-value="title"
      @change="title = $event"
    />
    
    // 子组件 Test2
    export default defineComponent({
         props: {
            modelValue: {   //以前是`value:String`
              type: String,
              default: ''
            }
          },

        emits: ['update:modelValue'],
        setup () {
            const changePageTitle = (title) => {
              proxy.$emit('update:modelValue', title)   //以前是 `this.$emit('input', title)`
            }
        }
   })