携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
什么是插槽?
插槽就是封装组件的一个占位符,在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。
举个栗子:
my-button组件
<my-button>
<!-- 插槽内容 -->
Click me
</my-button>
my-button组件模板
<button>
<!-- 插槽出口 -->
<slot></slot>
</button>
最终渲染在页面的结果
<button>
Click me!
</button>
slot标签是一个插槽出口,父组件提供的插槽内容会把 slot 标签替换掉。插槽内容可以是任何模板代码,比如HTML、甚至其他组件。
没有 slot标签时:
my-button组件
<my-button>
<!-- 插槽内容 -->
Click me
</my-button>
如果my-button组件模板中没有 slot标签,则该组件起始标签和结束标签之间的任何内容都会被抛弃。最终渲染结果同下:
<button>
</button>
后备内容
给插槽设置一个后备内容很有必要,当组件没有提供插槽内容时,插槽会渲染后备内容。
<button>
<!-- 设置后备内容 -->
<slot>Submit</slot>
</button>
my-button组件
<my-button>
<!-- 没有插槽内容 -->
</my-button>
最终渲染结果
<button>
Submit
</button>
但如果提供了插槽内容,my-button组件
<my-button>
<!-- 插槽内容 -->
Click me
</my-button>
则提供的插槽内容会替代后备内容:
<button>
Click me
</button>
具名插槽
如果一个组件需要预留多个插槽,,<slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义具名插槽:
<div class="container">
<header>
<!-- 页头 -->
<slot name="header"></slot>
</header>
<main>
<!-- 内容 -->
<slot></slot>
</main>
<footer>
<!-- 页脚 -->
<slot name="footer"></slot>
</footer>
</div>
不带 name 的 <slot> 标签会带有隐含的名字“default”。
在向具名插槽提供内容的时候,在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:
<my-home>
<template v-slot:header>
<h1>header</h1>
</template>
<p>default</p>
<p>main</p>
<template v-slot:footer>
<p>footer</p>
</template>
</my-home>
现在 <template> 元素中的所有内容都将会被传入相应的插槽。没有被<template> 包裹的内容都会被视为默认插槽的内容。
如果希望语义更明确,也可以在 <template> 中包裹默认插槽的内容:
<my-home>
<template v-slot:header>
<h1>header</h1>
</template>
<template v-slot:default>
<p>default</p>
<p>main</p>
</template>
<template v-slot:footer>
<p>footer</p>
</template>
</my-home>
具名插槽的缩写
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:
<my-home>
<template #header>
<h1>header</h1>
</template>
<template #default>
<p>default</p>
<p>main</p>
</template>
<template #footer>
<p>footer</p>
</template>
</my-home>
作用域插槽
对于插槽的编译作用域,记住这样一条规则:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
普通插槽是无法访问子组件中的数据的,当在插槽中想使用子组件的数据时,就要用到作用域插槽。
举个栗子:
现在有一个表格组件,表格的列名是通过子组件提供的,绑定在 <slot> 元素上的 attribute col 被称为插槽 prop。
<thead>
<slot name="thead" v-for="item in cols" :col="item"></slot>
</thead>
cols数据
cols: ["序号", "书名", "单价", "日期", "作者"]
在插槽内容中接收并使用作用域插槽,使用col来定义子组件提供的插槽 prop 名字:
<my-table>
<template #thead=“col”>
<tr>
<th>{{col}}</th>
</tr>
</template>
</my-table>