回首Vue3之指令篇(四)

359 阅读3分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

这篇文章我们来讲一下keyref以及v-for怎么去使用,使用它们的时候需要注意什么,以及它们配合使用的时候在Vue3与Vue2中的差异。

指令介绍

key

官方说,key 特殊 attribute 主要用做 Vue 的虚拟 DOM 算法的提示,以在比对新旧节点组时辨识 VNodes。如果不使用 key,Vue 会使用一种算法来最小化元素的移动并且尽可能尝试就地修改/复用相同类型元素。而使用 key 时,它会基于 key 的顺序变化重新排列元素,并且 key 不再存在的元素将始终被移除/销毁。

根据上述说法,我们看一个例子加深理解,如下:

数据

const kings = ref(["程咬金", "安琪拉", "芈月", "吕布", "李信"])

渲染结果用ol、li元素渲染

<ol>
    <li>程咬金</li>  //标记1
    <li>安琪拉</li>  //标记2
    <li>芈月</li>    //标记3
    <li>吕布</li>    //标记4
    <li>李信</li>    //标记5
</ol>

当数据发生变化时,数据为

kings.value=["程咬金", "芈月", "吕布", "安琪拉", "李信"]

无key渲染结果

<ol>
    <li>程咬金</li>  //标记1
    <li>芈月</li>    //标记2
    <li>吕布</li>    //标记3
    <li>安琪拉</li>  //标记4
    <li>李信</li>    //标记5
</ol>

有key渲染结果

<ol>
    <li>程咬金</li>  //标记1
    <li>芈月</li>    //新标记2
    <li>吕布</li>    //新标记3
    <li>安琪拉</li>  //新标记4
    <li>李信</li>    //标记5
</ol>

从上述例子我们可以看出,当数据发生变化时,无key优先复用存在的相同类型的元素,只改变元素的属性和内容;而有key则会重新排序,key不存在的会被销毁。

在key的使用中,我们需要注意是:

  1. 有相同父元素的子元素必须有唯一的 key,重复的 key 会造成渲染错误
  2. key我们在v-for中使用居多,但是我们也可以用在其他元素或者组件上:这样是为了触发过渡,让其被替换而不是被修改。比如下面span的写法,我们想触发它的过渡效果,可以给它加上key
<span :key="text">{{ text }}</span>

ref

ref 被用来给元素或子组件注册引用信息。引用信息将会被注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是那个 DOM 元素;如果用在子组件上,引用就指向组件实例。

简而言之,就是给一个marker,让你可以快速的找到这个元素或组件,值得注意的是ref绑定的时候可以给字符串或者是表达式

v-for

基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression,为当前遍历的元素提供别名。

以上述数据为例,写法如下:

<ol>
    <li v-for="king in kings">{{king}}</li>
</ol>

配合使用

在这里我们不仅讲它们三个之间的配合使用,还要讲它们配合使用的时候在Vue3与Vue2中的差异。

key 与 v-for

在指令介绍中,我们讲述了v-forkey的配合使用,在这里我们来讲一下它们配合使用时的另一种情况(v-for作用在 template)。

v-for作用在 template上时,keyVue2与Vue3的使用方式是不一样的。如下:

//Vue2
<template v-for="king in kings">
    <h1 :key="king">{{king}}</h1>
</template>

//Vue3
<template v-for="king in kings" :key="king">
    <h1>{{king}}</h1>
</template>

ref 与 v-for

下面我们来用两个例子说明一下它们之间的配合使用,数据用kings=["程咬金", "安琪拉", "芈月", "吕布", "李信"]:

第一个例子 ref="li"

<ol>
    <li v-for="king in kings" :key="king" ref="li">{{king}}</li>
</ol>

在我们使用$refs.li来获取标记元素时,在Vue2中我们可以得到一个数组,然而,在Vue3中我们仅仅得到满足这个条件的最后一个元素,即:

<li>李信</li>

第二个例子 :ref="'li'+king":ref="setItemRef"

如果我们在Vue3中想要获取所有标记元素,我们可以做以下操作:

<ol>
    <li v-for="king in kings" :key="king" :ref="'li'+king">{{king}}</li>
</ol>

这样我们在使用$refs是可以获得所有标记元素:

Proxy {li程咬金: li, li安琪拉: li, li芈月: li, li吕布: li, li李信: li}

或者我们也可以这样做:

<div id="app">
    <ol>
        <li v-for="king in kings" :key="king" :ref="setItemRef">{{king}}</li>
    </ol>
</div>

<script src="./vue.global.js"></script>
<script>
    const { createApp, ref } = Vue
    const app = createApp({
        setup() {
            const kings = ref(["程咬金", "安琪拉", "芈月", "吕布", "李信"])

            let itemRefs = [] // 存放元素变量,想操作元素的时候,可以从此变量里面拿值
            const setItemRef = el => {
                if (el) {
                    itemRefs.push(el)
                }
            }
            return {
                kings,
                setItemRef
            }
        }
    })
    app.mount("#app")
</script>

总结

  1. Vue3 中 v-if 总是优先于 v-for 生效,虽然不建议在同一元素上同时使用两者。

  2. Vue3中,ref="li"这种写法将不再在 $ref 中自动创建数组。要从单个绑定获取多个 ref,请将 ref 绑定到一个更灵活的函数上。

  3. v-for作用在template上的情况,Vue2key要放在其包裹的元素上,Vue3key要放在template元素上。

想了解更多文章,传送门已开启:回首Vue3目录篇