vue2升级vue3之模板指令新变化

79 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

v-model

在 Vue 2.0 发布后,开发者使用 v-model 指令时必须使用名为 value 的 prop。如果开发者出于不同的目的需要使用其他的 prop,他们就不得不使用 v-bind.sync。此外,由于v-modelvalue 之间的这种硬编码关系的原因,产生了如何处理原生元素和自定义元素的问题。

在 Vue 2.2 中,我们引入了 model 组件选项,允许组件自定义用于 v-model 的 prop 和事件。但是,这仍然只允许在组件上使用一个 v-model

2.x语法

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

 <ChildComponent v-model="pageTitle" />
 ​
 <!-- 是以下的简写: -->
 ​
 <ChildComponent :value="pageTitle" @input="pageTitle = $event" />

如果想要更改 prop 或事件名称(默认为value和input),则需要在 ChildComponent 组件中添加 model 选项:

 <!-- ParentComponent.vue -->
 ​
 <ChildComponent v-model="pageTitle" />
 // ChildComponent.vue
 ​
 export 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" />

3.x语法

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

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

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

 <ChildComponent v-model:title="pageTitle" />
 ​
 <!-- 是以下的简写: -->
 ​
 <ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

这也可以作为 .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的问题,并且可以自定义参数名称,对应事件就是update:propName

默认为modelValueupdate:modelValue

key改变

对于 v-if/v-else/v-else-if 的各分支项 key 将不再是必须的,因为现在 Vue 会自动生成唯一的 key

<template v-for>key 应该设置在 <template> 标签上 (而不是设置在它的子节点上)。

在 Vue 2.x 中,<template> 标签不能拥有 key。不过,你可以为其每个子节点分别设置 key

 <!-- Vue 2.x -->
 <template v-for="item in list">
   <div :key="'heading-' + item.id">...</div>
   <span :key="'content-' + item.id">...</span>
 </template>

在 Vue 3.x 中,key 则应该被设置在 <template> 标签上。

 <!-- Vue 3.x -->
 <template v-for="item in list" :key="item.id">
   <div>...</div>
   <span>...</span>
 </template>

v-if与v-for优先级

2.x语法

2.x 版本中在一个元素上同时使用 v-ifv-for 时,v-for 会优先作用。

这也是常遇到的vue相关面试题,v-if和v-for能不能一起用?

3.x 语法

3.x 版本中 v-if 总是优先于 v-for 生效。

v-bind合并行为

在一个元素上动态绑定 attribute 时,同时使用 v-bind="object" 语法和独立 attribute 是常见的场景。然而,这就引出了关于合并的优先级的问题。

2.x语法

在 2.x 中,如果一个元素同时定义了 v-bind="object" 和一个相同的独立 attribute,那么这个独立 attribute 总是会覆盖 object 中的绑定。

 <!-- 模板 -->
 <div id="red" v-bind="{ id: 'blue' }"></div>
 <!-- 结果 -->
 <div id="red"></div>

3.x语法

在 3.x 中,如果一个元素同时定义了 v-bind="object" 和一个相同的独立 attribute,那么绑定的声明顺序将决定它们如何被合并。换句话说,相对于假设开发者总是希望独立 attribute 覆盖 object 中定义的内容,现在开发者能够对自己所希望的合并行为做更好的控制。

 <!-- 模板 -->
 <div id="red" v-bind="{ id: 'blue' }"></div>
 <!-- 结果 -->
 <div id="blue"></div>
 ​
 <!-- 模板 -->
 <div v-bind="{ id: 'blue' }" id="red"></div>
 <!-- 结果 -->
 <div id="red"></div>