内置特殊 Attributes

key

描述: 在 Vue 3 中,key 的作用主要与重新渲染和优化有关。

作用: 用于标识列表中的元素,以便在列表更新时,Vue 可以识别哪些元素发生了变化,而不是简单地替换所有元素。

期望接收: number | string | symbolkey 绑定的值应为基础类型,如字符串或数字。不要使用对象作为 v-for 的 key。

例如,如果有一个动态列表,希望在列表更新时保留某些元素的身份,可以使用 key

import { reactive } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'

let template = `
    <button v-on:click='updateItems'>反转</button>
    <ul>
        <li v-for="item in items" :key="item.id">{{ item.name }}</li>
    </ul>
`

export default {
    setup: function () {
        let items = reactive([
            { id: 1, name: 'Apple' },
            { id: 2, name: 'Banana' },
            { id: 3, name: 'Cherry' },
        ])

        let updateItems = () => items.reverse()

        return { items, updateItems }
    },
    template,
}

在这个例子中,使用 key 可以确保列表的渲染更加高效,因为它可以区分哪些元素发生了变化,而不是每次重新创建所有元素。

同一父元素下的子元素必须具有唯一的 key。重复的 key 将导致渲染异常。

key 通常与 v-for 配合使用。建议在任何可行的情况下为 v-for 提供一个 key 属性,除非列表渲染的结果不依赖于子组件状态或临时 DOM 状态,或者你想有意采用默认行为来提高性能(默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。)

如果传递了 key,则根据 key 的变化顺序重新排列元素,并且将移除/销毁已不存在的元素。

<transition>
  <span :key="text">{{ text }}</span>
</transition>

text 变化时,<span> 将总是被替换而不是更新,触发 transition。

ref

描述: ref 允许在模板中为元素或子组件注册引用信息。

作用: ref 用于注册元素或子组件的引用。

期望接收: string | Function

使用组合式 API,引用存储在与名称匹配的 ref 中。对于普通 DOM 元素,引用是元素本身;对于子组件,引用是子组件的实例。

let template = `
    <div ref='div1'>通过ref获取到这个元素</div>
`

export default {
    setup: function () {
        let div1 = ref()

        onMounted(() => {
            console.log(div1.value) // <div>通过ref获取到这个元素</div>
        })

        return { div1 }
    },
    template
}

在模板中,不需要使用 v-bind: 来绑定 ref,因为 ref 自动创建了一个响应式引用。直接使用 ref 返回的响应式引用即可。

因为 ref 是作为渲染函数的结果创建的,必须等待组件挂载后才能访问它。

is

is 属性用于动态决定应该渲染哪个组件。这允许在运行时决定渲染哪个组件,而不是在模板中静态声明。在某些场景下非常有用,例如条件渲染多个组件版本或动态切换组件类型。

期望接收: string | Component

结合 <component> (这个东西下面说)举例,有一个 C1 组件,C2 类似:

let template = `
    <div>C1</div>
`

export default {
    template
}

有个父组件:

import { ref } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
import C1 from './C1.js'
import C2 from './C2.js'

let template = `
    <component :is="currentComponent"></component>  
    <button @click="changeCurrentComponent">Change Component</button>
`

export default {
    setup: function () {
        let currentComponent = ref('C1')
        let changeCurrentComponent = () => {
            currentComponent.value = currentComponent.value === 'C1' ? 'C2' : 'C1'
        }

        return { currentComponent, changeCurrentComponent }
    },
    components: {
        C1,
        C2,
    },
    template
}

在这个例子中,currentComponent 的值决定了渲染哪个组件。可以根据应用的状态动态地改变这个值,这里通过按钮切换两个组件。

如果is这个属性用在原生的DOM元素上面,is 的值必须加上前缀 vue: 才可以被解析为一个 Vue 组件。为什么要用在原生DOM元素上?因为某些元素仅在放置于特定元素中时才会显示,例如<option>要在<select>才会显示,<select>中也只有<option>才能显示。

子组件:

<template>
	<option>1</option>
	<option>2</option>
	<option>3</option>
</template>

<script setup></script>

<style lang="scss" scoped></style>

父组件:

<script setup>
	import MyOption from './components/MyOption.vue'
</script>

<template>
	<select>
		<div>我会被忽略</div>
		<MyOption/>
		<option is="vue:MyOption"></option>
	</select>
</template>

<style scoped></style>

这时,第一个div会被忽略;因为<select>中只能识别<option>,所以如果你第二个<MyOption>直接放置在<select>中出问题了,那你要使用第三种方式,即使用一个<option>伪装一下

内置特殊元素

<component>

在 Vue 3 中,<component> 标签是用于动态地渲染一个组件。它允许你在运行时根据条件或属性来决定渲染哪个组件。

<component> 标签的语法如下:

<component :is="dynamicComponent"></component>

要渲染的实际组件由 is prop 决定。当 is 是字符串,它既可以是 HTML 标签名也可以是组件的注册名。或者,is 也可以直接绑定到组件的定义。dynamicComponent 是一个变量或表达式,它的值应该是一个组件的名称、组件对象或组件实例。

例如,假设你有一个名为 MyComponent 的组件,你可以通过以下方式动态地渲染它:

<component is="MyComponent"></component> 

注意:如果MyComponent不是一个变量,而确确实实是一个组件,那么is前面就不需要加v-bind:

也可以渲染一个HTML 标签:

<component :is="href ? 'a' : 'span'"></component>

渲染异步组件

在 Vue 3 中,你可以使用 defineAsyncComponent 方法来定义异步组件,以便在组件加载时进行动态渲染。defineAsyncComponent 方法返回一个 Promise,该 Promise 解析为组件实例。

以下是一个使用 defineAsyncComponent 方法定义异步组件的示例:

假设你有你个C1组件:

import { defineAsyncComponent } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'

let template = `
    <component :is='C1'></component>
`

export default{
    setup(){
        let C1 = defineAsyncComponent(()=> import('./components/C1.js'))

        return {C1}
    },
    template,
}

在模板中,你可以这样来动态渲染异步组件:

<component :is="C1"></component>

C1 的值发生变化时,Vue 会自动重新渲染相应的组件。

<slot>

这里只介绍<slot>标签,关于插槽的具体内容,请看我的另一篇文章

表示模板中的插槽内容出口。元素本身将被其所匹配的插槽内容替换。

注意点

  1. <slot> 元素可以使用 name attribute 来指定插槽名:你可以为 <slot> 元素指定一个名称,以便在父组件中通过这个名称引用它。这样,父组件就可以知道应该将内容插入到哪个插槽中。
  2. 当没有指定 name 时,将会渲染默认插槽:如果子组件中的 <slot> 元素没有指定 name 属性,那么父组件中的内容将会被渲染到默认的插槽中。
  3. 传递给插槽元素的附加 attributes 将作为插槽 props,传递给父级中定义的作用域插槽:如果你在 <slot> 元素上添加了一些属性(即附加的 attributes),这些属性将会作为 prop 传递给父组件中定义的作用域插槽。换句话说,这些属性可以在父组件的插槽内容中使用。

举例,我们有一个C3子组件

let template = `
    <slot name="header" class='custom-class'></slot>
`

export default {
    template
}

还有一个C2父组件

import C3 from './C3.js'

let template = `
    <C3>
        <template v-slot:header> <!-- 使用 v-slot 指令将内容插入到 header 插槽中 -->  
            <h1 class='custom-class'>这是标题内容</h1> <!-- 这里我们可以使用子组件传递下来的 class attribute -->  
        </template>
    </C3>
`

export default {    
    components: {
        C3,
    },
    template
}

在上面的例子中,子组件的 <slot> 元素有一个 name 属性和一个 class 属性。在父组件中,我们通过 v-slot:header 将内容插入到名为 “header” 的插槽中。同时,由于子组件传递下来的 class 属性,我们可以在父组件的插槽内容中使用它(通过审查元素可以看到这个attribute)。

<template>

1.在Vue.js中,<template>标签可以被用来表示一个模板,但它不会在DOM中渲染成一个真实的元素。它的主要用途是作为占位符使用。

2.当<template>标签与特定的Vue指令一起使用时,如v-ifv-else-ifv-elsev-forv-slot,Vue会对其特殊处理。如果没有这些指令,<template>会被渲染成原生的HTML的<template>元素。

例如,我有多个元素需要通过v-if来显示和隐藏,我可以在这几个元素外面用一个div包着,然后给这个div用上v-if指令,但我为什么不这样做呢?这是因为div会令页面多了一个元素,而<template>就不会在DOM中渲染成一个真实的元素。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

如果<template>标签带有v-for指令,它还可以有一个key属性。对于其他的属性和指令,由于没有对应的元素,它们会被丢弃。

3.在单文件组件中,顶层的<template>标签用来包裹整个模板。这种用法与上述描述的<template>用法是不同的。顶层的<template>标签并不是模板本身的一部分,它不支持像指令这样的模板语法。

Logo

前往低代码交流专区

更多推荐