插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。
值得注意的是:在 Vue 2.6.0 中,为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot
指令)。它取代了 slot
和 slot-scope
这两个目前已被废弃但未被移除且仍在文档中的 attribute。
1.默认插槽/匿名插槽
子组件:
// Child.vue
<template>
<div>
<div class="test">
<slot></slot>
</div>
</div>
</template>
父组件:
//Parent.vue
<template>
<div id="app">
<Child>
Your Profile
</Child>
</div>
</template>
当组件渲染的时候,<slot></slot>
将会被替换为“Your Profile”。插槽内可以包含任何模板代码,包括 HTML甚至其它的组件。
如果 <Child/>
的 template
中没有包含一个 <slot>
元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。
2. 具名插槽
具名插槽,顾名思义,也就是给插槽起名字。 匿名插槽只能有一个,而具名插槽可以有n多个,当需要多个插槽时,可以使用<slot>的特性:name。这个特性可以用来定义额外的插槽
子组件:
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
第一种:在 <template>
上使用特殊的 slot
属性,可以将内容从父级传给具名插槽
父组件:
//Parent.vue
<template>
<div id="app">
<Child>
<template 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 slot="footer">
<p>Here's some contact info</p>
</template>
</Child>
</div>
</template>
第二种: 直接把 slot
属性用在一个普通元素上:
父组件:
//Parent.vue
<template>
<div id="app">
<Child>
<h1 slot="header">Here might be a page title</h1>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<p slot="footer">Here's some contact info</p>
</Child>
</div>
</template>
与第一种结果一致 。
注意到这里其实还有一个未命名插槽,也就是默认插槽,捕获所有未被匹配的内容。
V2.6.0之后的更新:
子组件不变,父组件改用v-slot属性。在向具名插槽提供内容的时候,我们可以在一个 <template>
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称:
父组件:
<template>
<div id="app">
<Child>
<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>
</Child>
</div>
</template>
就是这么简单,插槽的名字现在通过 v-slot:slotName
这种形式来使用。
现在 <template>
元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot
的 <template>
中的内容都会被视为默认插槽的内容。
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:
) 替换为字符 #
。例如 v-slot:header
可以被重写为 #header
:
值得注意的是: v-slot
只能添加在 <template>
上 ,这一点和已经废弃的 slot
属性不同,default情况在此不做赘述。
3. 作用域插槽
子组件中数据默认在父组件中是不能访问的,为了让子组件的数据在父级的插槽内容中可用,我们可以将数据作为 <slot>
元素的一个 属性绑定上去:
子组件:
<template>
<div>
<slot :data="data"></slot>
</div>
</template>
<script>
export default {
data: function(){
return {
data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
}
},
}
</script>
在 <template>
上使用的 slot-scope
属性,可以接收传递给插槽的 prop
父组件:
//Parent.vue
<template>
<div id="app">
<Child>
<template slot-scope="slotProps">
{
{slotProps}}
<br/>
{
{slotProps.data}}
</template>
</Child>
</div>
</template>
这里的 slot-scope
声明了被接收的 prop 对象会作为 slotProps
变量存在于 <template>
作用域中。你可以像命名 JavaScript 函数参数一样随意命名 slotProps
。
结果如下:
可以看出slotProps中存储的是所以子组件传递过来的数据组成的对象。
同样地,slot-scope属性也可以直接用于非 <template>
元素 (包括组件):
父组件:
//Parent.vue
<template>
<div id="app">
<Child>
<div slot-scope="slotProps">
<ul>
<li v-for="item in slotProps.data">{
{item}}</li>
</ul>
</div>
</Child>
</div>
</template>
结果如下:
V2.6.0之后的更新:
子组件不变,父组件改用v-slot属性。现在在父级作用域中,我们可以使用带值的 v-slot
来定义我们提供的插槽 prop 的名字
父组件:
//Parent.vue
<template>
<div id="app">
<Child>
<template v-slot="slotProps">
{
{ slotProps.data }}
</template>
</Child>
</div>
</template>
结果不变。
小结:
1. 简单理解 ,默认插槽和具名插槽是父组件既提供样式又提供模板,作用域插槽是数据是子组件自带的 父组件只提供样式
2. V2.6.0之后任何没有被包裹在带有 v-slot
的 <template>
中的内容都会被视为默认插槽的内容,即v-slot不能再用于普通元素