模板指令的变更

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-03-22

除之前提到 v-model 外,还有一系列关于模板的变更。

key attribute 非兼容

特殊的 key attribute 被用于提示 Vue 的虚拟DOM算法来保持对节点身份的持续跟踪。这样Vue可以知道何时能够重用和修补现有节点,以及何时需要对它们重新排序或重新创建。

Vue 2.x 建议在 v-if/v-else/v-else-if 的分支中使用 key。

但是现在我们不再建议在条件分支中继续使用 key attribute,因为没有为条件分支提供 key 时,也会自动生成唯一的 key。

非兼容变更体现在如果你手动提供了 key,那么每个分支都必须使用一个唯一的 key。因此大多数情况下都不需要设置这些 key。

<!-- Vue 2.x 建议使用 -->
<div v-if="condition" key="a">Yes</div>
<div v-else key="a">No</div>

<!-- Vue 3.x 建议移除key -->
<div v-if="condition">Yes</div>
<div v-else>No</div>

<!-- Vue 3.x 如果提供了必须保持key值的唯一性,所以大多数情况下不需要设置 -->
<div v-if="condition" key="a">Yes</div>
<div v-else key="b">No</div>

针对v-for,有这样的变更,以前<template>标签不能拥有 key 值,可以为其每个节点分别设置key值,而在Vue3中,key 则应该被设置在<template>上。

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

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

v-if 与 v-for 的优先级对比 非兼容

2.x 版本中在一个元素上同时使用 v-ifv-for 时,v-for 会优先作用。而 3.x 版本中 v-if 总是优先于 v-for 生效。

由于语法上存在歧义,建议避免在同一元素上同时使用两者。比起在模板层面管理相关逻辑,更好的办法是通过创建计算属性筛选出列表,并以此创建可见元素。

v-bind 非兼容

在Vue2.x 中如果动态绑定一个全是attribute 的对象,可以这样使用:

<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

但存在这样的问题,如果一个元素同时定义了 v-bind="object" 和一个相同的单独的 property,那么这个单独的 property 总是会覆盖 object 中的绑定。

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>

在 3.x,如果一个元素同时定义了 v-bind="object" 和一个相同的单独的 property,那么声明绑定的顺序决定了它们如何合并。

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>

<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>

移除 v-on.native 修饰符 非兼容

在Vue2.x 中,传递给带有 v-on 的组件的事件监听器只有通过 this.$emit 才能触发。要将原生 DOM 监听器添加到子组件的根元素中,可以使用 .native 修饰符。

<my-component
  v-on:close="handleComponentEvent"
  v-on:click.native="handleNativeClickEvent"
/>

而在Vue3中,移除了.native修饰符,新增的 emits 选项允许子组件定义真正会被触发的事件。

<my-component
  v-on:close="handleComponentEvent"
  v-on:click="handleNativeClickEvent"
/>

<!-- MyComponent.vue -->
<script>
  export default {
    emits: ['close'], // 在emits选项中不再提供native相关的事件名称,就可以将原生DOM监听器添加到子组件的根元素中
  }
</script>

对于子组件中未被定义为组件触发的所有事件监听器,Vue 现在将把它们作为原生事件监听器添加到子组件的根元素中 (除非在子组件的选项中设置了 inheritAttrs: false)。

所以需要确保所有组件都使用 emits 选项记录其除原生事件外的自定义事件。

v-for 中的 Ref 数组 非兼容

在 Vue 2 中,在 v-for 里使用的 ref attribute 会用 ref 数组填充相应的 $refs property。当存在嵌套的 v-for 时,这种行为会变得不明确且效率低下。

在 Vue 3 中,这样的用法将不再在 $ref 中自动创建数组。要从单个绑定获取多个 ref,请将 ref 绑定到一个更灵活的函数上 (这是一个新特性):

<template>
  <div v-for="item in list" :ref="setItemRef"></div>
</template>

<!-- composition api -->
<script>
import { onBeforeUpdate, onUpdated } from 'vue'

export default {
  setup() {
    // 如果是使用 options api, 则可以将itemRefs挂载在data选项上,将setItemRef定义在methods选项中
    let itemRefs = [] 
    const setItemRef = el => {
      if (el) {
        itemRefs.push(el)
      }
    }
    onBeforeUpdate(() => {
      itemRefs = []
    })
    onUpdated(() => {
      console.log(itemRefs)
    })
    return {
      setItemRef
    }
  }
}
</script>

需要注意的是,itemRefs 不必是数组。它也可以是一个对象,其 ref 会通过迭代的 key 被设置。如果需要,itemRef 也可以是响应式的且可以被监听。