vue2 vs vue3 v-model 的使用

926 阅读2分钟

vue2

  • 限制

    • <input>
    • <select>
    • <textarea>
    • components
  • 修饰符

    • .lazy - 取代 input 监听 change 事件
    • .number - 输入字符串转为有效的数字
    • .trim - 输入首尾空格过滤
  • 首先 v-model 是一个语法糖

    • 在 vue2 中使用的是 v-bind 来绑定属性 然后通过 @input 获取到输入框中的值重新赋值给该属性

      • <input :value="value" @input="input"/>
        
      • 也就是说 v-model 是 v-bind 和 @input 两个表达式的简写
组件上的使用
  • 在 2.x 中,在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件:

    • <ChildComponent v-model="pageTitle" /><!-- 是以下的简写: --><ChildComponent :value="pageTitle" @input="pageTitle = $event" />
      
  • 如果想要更改 prop 或事件名称,则需要在 ChildComponent 组件中添加 model 选项:

    • <!-- ParentComponent.vue --><ChildComponent v-model="pageTitle" />
      
    • // ChildComponent.vueexport default {
        model: {
          prop: 'title',
          event: 'change'
        },
        props: {
          // 这将允许 `value` 属性用于其他用途
          value: String,
          // 使用 `title` 代替 `value` 作为 model 的 prop
          title: {
            type: String,
            default: 'Default title'
          }
        }
      }
      
    • 在这个例子中 v-model 是以下的简写:
    • <ChildComponent :title="pageTitle" @change="pageTitle = $event" />
      
vue2 中存在的问题
  • 传递下去的必须是value值,接收的也必须是input事件
  • 并不是所有的元素都适合传递value,比如<input type="checkbox">,当type属性的值为checkbox是,实际上是checked这个属性的存在用来表示是否被选中,而value值是另外的含义
  • 而且有些时候,一些组件并不是通过input来进行触发事件。也就是说valueinput事件在大多数情况下能够适用,但是存在value另有含义,或者不能使用input触发的情况,这时候我们就不能使用v-model进行简写了
.sync方式实现双向绑定
  • 如果需要对某一个 prop 进行“双向绑定”(除了前面用 v-model 绑定 prop 的情况) 建议使用 update:myPropName 抛出事件。

  • 例如,对于在上一个示例中带有 title prop 的 ChildComponent,我们可以通过下面的方式将分配新 value 的意图传达给父级:

    • this.$emit('update:title', newValue)
      
  • 然后父组件可以在需要时监听该事件,并更新本地的 data property。例如:

    • <ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
      // 简写
      <ChildComponent :title.sync="pageTitle" />
      

vue3

  • 在 3.x 中,自定义组件上的 v-model 相当于传递了 modelValue prop 并接收抛出的 update:modelValue 事件:

    • <ChildComponent v-model="pageTitle" /><!-- 是以下的简写: --><ChildComponent
        :modelValue="pageTitle"
        @update:modelValue="pageTitle = $event"
      />
      
  • v-model 参数

    若需要更改 model 的名称,现在我们可以为 v-model 传递一个参数,以作为组件内 model 选项的替代:

    • <ChildComponent v-model:title="pageTitle" /><!-- 是以下的简写: --><ChildComponent :title="pageTitle" @update:title="pageTitle = $event" /><ChildComponent v-model:title="pageTitle" v-model:content="pageContent" /><!-- 是以下的简写: --><ChildComponent
        :title="pageTitle"
        @update:title="pageTitle = $event"
        :content="pageContent"
        @update:content="pageContent = $event"
      />
      
迁移策略
  • 代码库中所有使用 .sync 的部分并将其替换为 v-model

    • <ChildComponent :title.sync="pageTitle" /><!-- 替换为 --><ChildComponent v-model:title="pageTitle" />
      
  • 对于所有不带参数的 v-model

    • prop => 命名更改为 modelValue

    • event => 命名更改为 update:modelValue

      • 相当于 modelValue 为默认值了
    • <ChildComponent :title.sync="pageTitle" /><!-- 替换为 --><ChildComponent v-model:title="pageTitle" />
      
    • // ChildComponent.vueexport default {
        props: {
          modelValue: String // 以前是`value:String`
        },
        emits: ['update:modelValue'],
        methods: {
          changePageTitle(title) {
            this.$emit('update:modelValue', title) // 以前是 `this.$emit('input', title)`
          }
        }
      }
      

总结

  • 总之语法的使用 要区分清楚 忘记了多看官网