Vue3 初探(四)模板指令
继续看一下Vue3的迁移文档
v-model
2.x 语法
在 2.x 中,在组件上使用 v-model
相当于绑定 value
prop 和 input
事件:
1 | <ChildComponent v-model="pageTitle" /> |
如果要将属性或事件名称更改为其他名称,则需要在 ChildComponent
组件中添加 model
选项:
- 在子组件中通过model.prop配置,修改v-model所绑定的prop属性。比如下面的例子中v-model属性绑定的prop就从value变为title。
- 在子组件中通过model.event配置,可以修改v-model所绑定的值在子组件中发生变化时需要传递到父组件时触发的事件。比如下面的例子中,触发的事件由默认input变为change。
- 由于通过model.prop配置改变了v-model所绑定的prop为title,所以value可以当做一个普通的prop传入。
1 | <!-- ParentComponent.vue --> |
1 | // ChildComponent.vue |
所以,在这个例子中 v-model
的简写(这里的简写指的是,通过以下写法,可以省略上面在子组件中的特殊配置)如下:
1 | <ChildComponent :title="pageTitle" @change="pageTitle = $event" /> |
使用 v-bind.sync
在某些情况下,我们可能需要对某一个 prop 进行“双向绑定”(除了前面用 v-model
绑定 prop 的情况)。为此,我们建议使用 update:myPropName
抛出事件。例如,对于在上一个示例中带有 title
prop 的 ChildComponent
,我们可以通过下面的方式将分配新 value 的意图传达给父级:
1 | this.$emit('update:title', newValue) |
如果需要的话,父级可以监听该事件并更新本地 data property。例如:
1 | <ChildComponent :title="pageTitle" @update:title="pageTitle = $event" /> |
为了方便起见,我们可以使用 .sync
修饰符来缩写,如下所示:
1 | <ChildComponent :title.sync="pageTitle" /> |
3.x 语法
在 3.x 中,自定义组件上的 v-model
相当于传递了 modelValue
prop 并接收抛出的 update:modelValue
事件:
1 | <ChildComponent v-model="pageTitle" /> |
v-model
参数
若需要更改 model
名称,而不是更改组件内的 model
选项,那么现在我们可以将一个 argument 传递给 model
:
1 | <ChildComponent v-model:title="pageTitle" /> |
这也可以作为 .sync
修饰符的替代,而且允许我们在自定义组件上使用多个 v-model
。
1 | <ChildComponent v-model:title="pageTitle" v-model:content="pageContent" /> |
v-model
修饰符
除了像 .trim
这样的 2.x 硬编码的 v-model
修饰符外,现在 3.x 还支持自定义修饰符:
1 | <ChildComponent v-model.capitalize="pageTitle" /> |
详情可以看另一篇博客:https://sunra.top/posts/4258a220/ 中关于自定义事件的内容
Key attribute
- 新增v-if, v-else, v-else-if的各分支项,key将不再是必须的,因为现在 Vue 会自动生成唯一的key
- 非兼容:如果你手动提供
key
,那么每个分支必须使用唯一的key
。你不能通过故意使用相同的key
来强制重用分支。
- 非兼容:如果你手动提供
- 非兼容:
<template v-for>
的key
应该设置在<template>
标签上 (而不是设置在它的子节点上)。
在条件分支中
Vue 2.x 建议在 v-if
/v-else
/v-else-if
的分支中使用 key
。
1 | <!-- Vue 2.x --> |
这个示例在 Vue 3.x 中仍能正常工作。但是我们不再建议在 v-if
/v-else
/v-else-if
的分支中继续使用 key
attribute,因为没有为条件分支提供 key
时,也会自动生成唯一的 key
。
1 | <!-- Vue 3.x --> |
非兼容变更体现在如果你手动提供了 key
,那么每个分支都必须使用一个唯一的 key
。因此大多数情况下都不需要设置这些 key
。
1 | <!-- Vue 2.x --> |
结合 <template v-for>
在 Vue 2.x 中 <template>
标签不能拥有 key
。不过你可以为其每个子节点分别设置 key
。
1 | <!-- Vue 2.x --> |
在 Vue 3.x 中 key
则应该被设置在 <template>
标签上。
1 | <!-- Vue 3.x --> |
类似地,当使用 <template v-for>
时存在使用 v-if
的子节点,key
应改为设置在 <template>
标签上。
1 | <!-- Vue 2.x --> |
v-if 与 v-for 的优先级对比
- 非兼容:两者作用于同一个元素上时,
v-if
会拥有比v-for
更高的优先级。
v-bind 合并行为
2.x 语法
在 2.x,如果一个元素同时定义了 v-bind="object"
和一个相同的单独的 property,那么这个单独的 property 总是会覆盖 object
中的绑定。
1 | <!-- template --> |
3.x 语法
在 3.x,如果一个元素同时定义了 v-bind="object"
和一个相同的单独的 property,那么声明绑定的顺序决定了它们如何合并。换句话说,相对于假设开发者总是希望单独的 property 覆盖 object
中定义的内容,现在开发者对自己所希望的合并行为有了更好的控制。
1 | <!-- template --> |
v-for 中的 Ref 数组非兼容
在 Vue 2 中,在 v-for
里使用的 ref
attribute 会用 ref 数组填充相应的 $refs
property。当存在嵌套的 v-for
时,这种行为会变得不明确且效率低下。
在 Vue 3 中,这样的用法将不再在 $ref
中自动创建数组。要从单个绑定获取多个 ref,请将 ref
绑定到一个更灵活的函数上 (这是一个新特性):
1 | <div v-for="item in list" :ref="setItemRef"></div> |
结合选项式 API:
1 | export default { |
结合组合式 API:
1 | import { ref, onBeforeUpdate, onUpdated } from 'vue' |
注意:
itemRefs
不必是数组:它也可以是一个对象,其 ref 会通过迭代的 key 被设置。- 如果需要,
itemRef
也可以是响应式的且可以被监听。