每说一次再见,
就是死去一点点。
--《漫长的告别》雷蒙钱德勒
什么是插槽
在 Vue 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope这两个目前已被废弃但未被移除且仍在文档中的attribute。
插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题在这里就点出来了,是显示不显示和怎样显示。
由于插槽是一块模板,所以对于任何一个组件,从模板种类的角度来区分的话,可以分为非插槽模板和插槽模板两大类:
-
非插槽模板指的是html模板,比如div、span、ul、table这些,非插槽模板的显示与隐藏以及怎样显示由组件自身控制;
-
插槽模板是slot,它是一个空壳子,因为它的显示与隐藏以及最后用什么样的html模板显示由父组件控制。但是插槽显示的位置却由子组件自身决定,slot写在组件template的什么位置,父组件传过来的模板将来就显示在什么位置。
子组件决定位置,父组件决定内容
插槽的分类
插槽一共就三大类:
-
匿名插槽(也叫默认插槽): 没有命名,有且只有一个
-
具名插槽: 相对匿名插槽组件slot标签带name命名的
-
作用域插槽: 子组件内数据可以被父页面拿到(解决了数据只能从父页面传递给子组件)
匿名插槽(默认插槽)
说明:匿名插糟只需要一个,示例如下:
- 子组件(SlotChild.vue):
<button type="submit">
<slot>Submit</slot>
</button>
可在子组件的slot标签中设置一个默认值,当父组件不提供值时,默认值会进行填充。
- 父页面:
<SlotChild>
Save
</SlotChild>
渲染结果
<button type="submit">
Save
</button>
总结,在匿名插槽中,父组件内无需使用template包裹内容
具名插槽(name)
说明:和匿名插槽比较,就是必须起名对应,可以有多个具名插槽,且具名插槽可以在一个组件中出现N次,出现在不同的位置,实例如下:
- 子页面
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
一个不带 name 的 出口会带有隐含的名字“default”
- 父组件
<SlotChild>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</SlotChild>
现在<template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot 的 <template>中的内容都会被视为默认插槽的内容。
- 渲染结果
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>
注意:
-
可使用动态插槽名:v-slot:[dynamicSlotName]
-
具名插槽可缩写:v-slot:header 可以被重写为 #header
作用域插槽
说明:父组件可接取子组件传递过来的值,例如:user="user" :text="text"类似属性的数据。实际上,对比前面两种插槽,我们可以叫它带数据的插槽,示例如下:
- 子组件
<span>
<slot v-bind:user="user" v-bind:text="text">
{{ user.lastName }}
</slot>
</span>
- 父组件
<SlotChild>
<template v-slot:default="slotProps">
<p>{{ slotProps.user.firstName }}</p>
<p>{{ slotProps.text }}</p>
</template>
</SlotChild>
数据传递过程如下图所示:
总结,在使用上v-slot时,只需要考虑好下面两点即可:
-
是否需要命名(匿名插槽,具名插槽)
-
父页面是否需要取存在子页面的数据(作用域插槽)
参考文章: Vue 作用域插槽