前言
学习组件的slot(插槽)前,必须先学习组件基础。插槽是建立在组件之上的。我刚开始做vue项目,拿代码依葫芦画瓢的时候,遇到slot搜了好多篇文章都看不明白。直接看官方文档也看不明白。问题首先是对组件基本不怎么理解,其次是没有亲手去建一个简单项目来理解slot。
使用组件通常也不可避免要用到slot。可以去看看element ui文档,很多组件都有slot。slot说白了就是组件的一块区域空出来,交给用户去填充。最典型例子就是数据表格,其右侧“操作”一列经常包含“编辑 查看 删除”这样,如下图所示。其“操作”一列通常就是使用了slot,这个区域的内容由父组件进行填充。
插槽slot
简单的slot
我们依然沿用前面创建的project1,当然读者自己创建一个新的项目也可以。在src/components目录下创建SimpleSlot.vue
<template>
<div>
这是组件头
<slot>默认slot</slot>
这是组件尾
</div>
</template>
<script>
export default {
name: "SimpleSlot",
};
</script>
第4行就是插槽slot。里面的内容是默认内容,如果父组件不对slot进行填充,那么就显示<slot>标签里的内容,如果父组件填充了,那么就会替换<slot>标签里面默认的内容。
接着我们修改一下App.vue
<template>
<div id="app">
<simple-slot>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</simple-slot>
</div>
</template>
<script>
import SimpleSlot from "./components/SimpleSlot";
export default {
name: "App",
components: {
SimpleSlot,
},
};
</script>
第4-5行的内容将被填充到子组件的<slot>标签内。运行项目可以看到效果:
具名slot
简单的slot就是把子组件标签内的内容全部填充到<slot>当中。如果我们想让组件中的使用多个插槽时,需要使用具名slot。我们在src/components下新建一个组件CustomSlot.vue:
<template>
<div>
<slot name="header">默认header</slot>
<slot>默认slot</slot>
<slot name="footer">默认footer</slot>
<slot name="bottom">默认底部</slot>
</div>
</template>
<script>
export default {
name: "CustomSlot",
};
</script>
第3、5、6行就是使用具名slot。在<slot>标签的name属性设置名字。
接着修改App.vue:
<template>
<div id="app">
<custom-slot>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
<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>
</custom-slot>
</div>
</template>
<script>
import CustomSlot from "./components/CustomSlot";
export default {
name: "App",
components: {
CustomSlot,
},
};
</script>
第4-6行指定填充name为footer的slot的内容。8-10行填充header的内容。没有指定的则填充无具名slot的内容。
运行项目:
可以看到header、footer、和无具名slot都填充了父组件指定的内容,而 <slot name="bottom">因为没被指定填充的内容,则显示原本默认的内容。
v-slot的缩写
和v-bind、v-on一样,v-slot也是可以缩写的,的缩写是#,所以上面App.vue的模版可以写成:
<template>
<div id="app">
<custom-slot>
<template #footer>
<p>Here's some contact info</p>
</template>
<template #header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</custom-slot>
</div>
</template>
插槽作用域
这个插槽作用域,在我看来,其实就是一个插槽数据绑定的作用。比如说父组件想使用插槽内部的数据时,就需要用到它。最常见的例子就是在element-ui等组件的表格中,通常插槽都会有record之类的属性,其中record通常就是该表格某行的记录。这样就可以根据记录的内容判断插槽内该显示什么内容。
说起来比较抽象,我们用实际的例子跑一下就知道了。
首先修改CustomSlot.vue
<template>
<div>
<slot name="header" :title="title">默认header</slot>
<slot :content="content">默认slot</slot>
<slot name="footer" :footer="footer">默认footer</slot>
<slot name="bottom">默认底部</slot>
</div>
</template>
<script>
export default {
name: "CustomSlot",
data() {
return {
title: 'Custom Slot',
footer: 'This is footer',
content: 'This is content',
user: 'admin'
}
}
};
</script>
我们为组件增加data,并与插槽中的属性绑定。后续父组件就可以访问插槽的属性,得以获取子组件的data。
修改App.vue:
<template>
<div id="app">
<custom-slot>
<template #footer="slotProps">
<p>Here's some contact info</p>
<p>{{slotProps.footer}}</p>
</template>
<template #header="slotProps">
<h1>Here might be a page title</h1>
<h1>{{slotProps.title}}</h1>
</template>
<template #default="slotProps">
<p>{{slotProps.content}}</p>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</custom-slot>
</div>
</template>
<script>
import CustomSlot from "./components/CustomSlot";
export default {
name: "App",
components: {
CustomSlot,
},
};
</script>
只要使用#footer="slotProps",我们就可以绑定插槽的作用域。其中slotProps可以自行命名。之后运行项目查看输出:
显然这三处分别就是父组件通过插槽作用域获取的数据,并显示出来。
小结
插槽相关的内容还有很多,例如编译作用域、动态插槽名等。这些内容读者在有一定基础后,可通过官网的文档进行学习。