0%

说说Vue的插槽

插槽是什么

slot(插槽)不是Vue独有的概念,来源自Html规范。

在Vue中,插槽存在的意义是增强组件的表现力。诚然,我们可以在组件设计时尽可能完善功能,但是数据的表现方式肯定是有限的。通过组件插槽,可以突破这种限制,组件的调用方也可以参与组件表现的设计。

Vue组件和外界有3条管道:参数插槽事件。参数和事件,传递的是数据,而插槽显然不是。通过插槽,外界给组件传递的是定制的表现方式

这里有一个例子,很好的诠释了以上内容:同一个组件,相同的数据,通过插槽可以有多种不同的表现,后面的内容会针对这个例子详细解释Vue插槽的相关内容。

在组件中定义插槽

什么情况下需要?

想要把表现方式让渡给外界的部分都可以定义成插槽。

如何定义插槽?

使用<slot></slot>标签包裹的内容就是一个插槽。

如何定义插槽的默认值?

<slot></slot>标签包裹的内容就是插槽的默认值,在外界不提供插槽内容的时候显示默认值。

具名插槽

具名插槽就是有名字的插槽,起名字的作用就是区分一个组件内的多个插槽。给slot标签添加name属性就定义了一个具名插槽。比如:

1
2
3
<slot name="slotname">
...
</slot>

给具名插槽传递内容,需要使用具名插槽的名字。

匿名插槽

没有名字的插槽就是匿名插槽。传递内容时,没有指定名字的内容,都会传递给匿名插槽。理论上,一个组件应该只有一个匿名插槽。

使用组件插槽

不传递内容

使用组件时,在组件的一对标签中的内容就会传递给组件的插槽。

例子中的第一次组件调用,就没有传递任何内容给插槽:

1
2
<comp1 :content="info">
</comp1>

ps:如果组件插槽没有默认值,那么就没有任何内容在插槽中显示。

传递内容给匿名插槽

而第二次调用组件,给组件中的匿名插槽传递了内容:

1
2
3
<comp1 :content="info">
<h1 class="redTitle" >This is Custom Title</h1>
</comp1>

这个例子中,传递的内容:<h1 class="redTitle" >This is Custom Title</h1>,会替换掉组件中匿名插槽的内容。

#传递内容给具名插槽
例子中第三次调用组件,就是这样的情况:

1
2
3
<comp1 :content="info">
<img slot="img" src="https://images.unsplash.com/photo-1529416272270-05ffe151a74c?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ&s=b006e47d690b0a651bfbda4201c55b46" class="small_img" alt="This is a Custom image"/>
</comp1>

这个例子中,通过img的slot属性,给组件的img插槽传递了内容,原来的内容被替换。根据官方的文档,也可以像下面这样传递内容:

1
2
3
4
5
<comp1 :content="content">
<template slot="img" >
<img src="https://images.unsplash.com/photo-1529416272270-05ffe151a74c?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ&s=b006e47d690b0a651bfbda4201c55b46" class="small_img" alt="This is a Custom image"/>
</template>
</comp1>

可见两者的区别在于使用template标签包裹传递的内容以及slot属性定义的位置。

当需要定制的表现和数据相关时

以上的几个例子,虽然在调用组件时传递了定制的表现内容(改变了默认的title内容和外观、更换了图片),但是有一个共同的特点就是:插槽中没有使用任何数据。

有一定经验的开发者肯定不满足于此,因为有时数据和表现往往是难以分开的。上面例子中第4和第5次调用组件就是这样的情况:

1
2
3
4
5
6
7
8
9
10
11
<comp1 :content="info">
<div slot="autor">autor:{{author}}</div>
</comp1>

<comp1 :content="info">
<template slot="content" slot-scope="slotProps">
<div>
<span>{{slotProps.content}}</span>
</div>
</template>
</comp1>

第4次调用组件比较容易理解,传入的author并不在组件中定义,也没有作为参数传递给组件,而是作为定制内容传递给了对应插槽。

第5次调用组件需要注意了,content的定义在插槽上。我们来看插槽的定义:

1
2
3
<slot name="content" :content="content" :flag="true">
<p>{{content}}</p>
</slot>

我们发现与前面所有例子不同的地方是似乎 slot标签“绑定”了两个属性,contentflag。实际也是这样,这里同时做了参数声明和参数传值。不管在定义插槽的时候绑定多少个属性,它们都被附加在了一个对象上。在调用组件时,获取到了这个对象,就可以在组件外得到组件内的值了。

在调用组件时,通过slot-scope属性,就定义了上面所说对象的句柄。

在例子中第6次调用组件,证实了以上推测。