阅读 613

从Vue 2到Vue 3的迁移指南之破坏性特性(三、v-model)

1、内容系个人翻译自 Vue 3.0 Beta 版文档中 Migration From Vue 2 章节
2、不一定准确,欢迎交流(别人都翻过几百遍了吧,再说也没人看)
3、水平有限、随时太监

· 从Vue 2到Vue 3的迁移指南之破坏性特性(一、全局API)
· 从Vue 2到Vue 3的迁移指南之破坏性特性(二、全局API的tree-shaking)

v-model

概览

这些变化可以概括为:

  • 破坏性的: 当用在 自定义组件 上的时候,v-model 的 prop 与 event 的默认名已变更:
    • prop: value -> modelValue
    • event: input -> update:modelValue
  • 破坏性的: v-bind.sync 修饰符以及 model 选项已删除,取而代之的是 v-model 的一个参数;
  • 新的: 现在可以在一个组件上使用多个 v-model 来绑定数据了;
  • 新的: 新增了自定义 v-model 修饰符的功能。

更多信息请继续阅读!

Introduction

当 Vue 2.0 发布的时候,v-model 指令要求开发者固定使用 value 属性(作为数据传递)。而如果开发者需要使用多个不同参数的话,那就只能使用 v-bind.sync 来实现。此外,v-modelvalue 之间这种硬编码关系也会导致我们在使用原生或自定义元素时产生一些问题。

在 2.2 的时候我们引入了 model 这个组件选项,它允许一个组件在使用 v-model 的时候定制 prop 和 event,但是实际上还是只能在组件上使用一个 v-model

而在 Vue 3 中,这个用于双向绑定的 API 会变得更标准化以减少混乱的地方,同时开发者也可以更灵活地使用 v-model 指令。

2.x 语法

在 2.x 里,使用 v-model 等同于向组件传递一个 value 属性,同时监听一个 input 事件:

<ChildComponent v-model="pageTitle" />

<!-- 是以下代码的简写: -->

<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
复制代码

如果我们想修改 prop 和 event 值的命名,我们则需要通过在一个子组件添加 model 选项:

<!-- ParentComponent.vue -->

<ChildComponent v-model="pageTitle" />
复制代码
// ChildComponent.vue

export default {
  model: {
    prop: 'title',
    event: 'change'
  },
  props: {
    // 允许将 'value' 属性作其他用途
    value: String,
    // 使用 'title' 作为 prop 
    title: {
      type: String,
      default: 'Default title'
    }
  }
}
复制代码

所以,在这种状况下,v-model 是以下代码的简写:

<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
复制代码

使用 v-bind.sync

有些时候,我们可能需要对一个属性进行双向绑定(除了已经用 v-model 绑定的那个属性以外的情况)。这种情况我们推荐使用 update:myPropName 这种模式去触发事件;举例来说,对于前面那个例子,我们可以通过这方式达到向子组件的 title 属性传递一个新值的目的:

this.$emit('update:title', newValue)
复制代码

这样一来父组件就可以监听到这个事件,然后更新本地数据,像这样:

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
复制代码

我们可以使用 .sync 修饰符来简写上述内容:

<ChildComponent :title.sync="pageTitle" />
复制代码

3.x 语法

在 3.x 里,使用 v-model 等同于向组件传递一个 modelValue 属性,同时监听一个 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" />
复制代码

v-bind anatomy

这也可以代替 .sync 修饰符,并且现在我们可以在自定义组件上使用多个 v-model 了。

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

<!-- 是以下代码的简写: -->

<ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>
复制代码

v-model 的修饰符

除了 2.x 上硬编码的 v-model 相关的修饰符、像 .trim 这样的外,在 3.x 上我们支持自定义修饰符了:

<ChildComponent v-model.capitalize="pageTitle" />
复制代码

自定义事件 章节中获取更多关于 v-model 修饰符的信息。

迁移策略

推荐:

  • 找到代码库中使用到 .sync 的地方,并将其替换为 v-model

    <ChildComponent :title.sync="pageTitle" />
    
    <!-- 替换成 -->
    
    <ChildComponent v-model:title="pageTitle" />
    复制代码
  • 对于所有不带参数的 v-model,确保将它所使用的 props 名和事件名分别修改成 modelValue and update:modelValue

    <ChildComponent v-model="pageTitle" />
    复制代码
    // ChildComponent.vue
    
    export default {
      props: {
        modelValue: String // 在这之前是 `value: String`
      },
      methods: {
        changePageTitle(title) {
          this.$emit('update:modelValue', title) // 在这之前是 `this.$emit('input', title)`
        }
      }
    }
    复制代码

后续

获取更多关于新的 v-model 语法的信息,请参阅: