插槽
插槽的分类如下。 1. 默认插槽; 2. 默认作用域插槽; 3. 具名插槽; 4. 具名作用插槽;
普通插槽是一种用于将内容插入到组件中指定位置的机制,它允许父组件向子组件传递 DOM 元素或组件实例作为子组件的一部分进行渲染。普通插槽可以在子组件中使用 <slot>
元素来定义,使用时可以在父组件中将内容插入到指定的插槽位置。下面是一个普通插槽的代码示例:
<!-- 子组件 -->
<template>
<div>
<h2>子组件</h2>
<slot></slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<h1>父组件</h1>
<child-component>
<p>这是插入到子组件中的内容</p>
</child-component>
</div>
</template>
在上面的代码中,子组件 <child-component>
中使用了一个普通插槽,通过 <slot>
元素来定义。在父组件中,将要插入到子组件中的内容包裹在 <child-component>
标签中即可。
作用域插槽是一种允许子组件向父组件传递数据的机制,它允许父组件将子组件的数据作为参数传递给插槽内容,从而实现更灵活的组件复用。作用域插槽可以在子组件中使用 <slot>
元素,并通过 v-bind
指令将数据传递给插槽内容。下面是一个作用域插槽的代码示例:
<!-- 子组件 -->
<template>
<div>
<h2>子组件</h2>
<slot :data="childData"></slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<h1>父组件</h1>
<child-component>
<template #default="{ data }">
<p>这是插入到子组件中的内容,子组件传递的数据是:{{ data }}</p>
</template>
</child-component>
</div>
</template>
在上面的代码中,子组件 <child-component>
中使用了一个作用域插槽,通过 <slot>
元素和 v-bind
指令来定义。在父组件中,使用 <template>
标签来定义插槽内容,并通过 #default
指令来指定插槽名称。在插槽内容中,使用 data
变量来接收子组件传递的数据,并渲染到页面中。
1、默认插槽
<!-- 子组件Test.vue -->
<template>
<div>
<h2>子组件</h2>
<slot></slot>
</div>
</template>
<!-- 父组件App.vue -->
<template>
<div>
<h1>父组件</h1>
<child-component> //<Test>
<p>这是插入到子组件中的内容</p>
</child-component> //</Test>
</div>
</template>
插槽内容可以是任意合法的模板内容,不局限于文本。例如我们可以传入多个元素,甚至是组件:
<FancyButton>
<span style="color:red">Click me!</span>
<AwesomeIcon name="plus" />
</FancyButton>
在父组件没有提供任何插槽内容时在 <button>
内渲染“Submit”,只需要将“Submit”写在 <slot>
标签之间来作为默认内容:
<button type="submit">
<slot>
Submit <!-- 默认内容 -->
</slot>
</button>
在父组件中使用 <SubmitButton>
且没有提供任何插槽内容时,会以默认内容渲染,有插槽内容时,被显式提供的内容会代替默认内容。
2、默认作用域插槽
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
</MyComponent>
v-slot="slotProps"
可以类比这里的函数签名,和函数的参数类似,可以在 v-slot
中使用解构:
<MyComponent v-slot="{ text, count }">
{{ text }} {{ count }}
</MyComponent>
3、具名插槽
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
这类带 name
的插槽被称为具名插槽 (named slots)。没有提供 name
的 <slot>
出口会隐式地命名为“default”。
<BaseLayout>
<template v-slot:header> //可写为<template #header>
<!-- header 插槽的内容放这里 -->
</template>
<template #default> //可以不写。当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容。
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template> //可以不写
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
v-slot
有对应的简写 #
,因此 <template v-slot:header>
可以简写为 <template #header>
。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。
4、具名作用域插槽
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
</template>
<template #default="defaultProps">
{{ defaultProps }}
</template>
<template #footer="footerProps">
{{ footerProps }}
</template>
</MyComponent>
向具名插槽中传入 props:
<slot name="header" message="hello"></slot>
注意插槽上的 name
是一个 Vue 特别保留的 attribute,不会作为 props 传递给插槽。因此最终 headerProps
的结果是 { message: 'hello' }
。