插槽 --适用于父组件访问子组件
一、概念
1.概念
- Slot 通俗的理解就是"占坑",在组件模板中占好了位置,当使用该组件标签的时候,组件标签里面的内容就会自动填坑(替换组件模板中slot位置)
- 并且可以作为承载分发内容的出口
2.作用
允许你在
使用组件时
,向组件内部插入内容
(HTML、组件、甚至是函数),让组件可以根据这些内容进行渲染。
3.本质
- 插槽是 Vue 提供的一个"内容占位符"。
父组件
可以向这个"占位符"中插入任意内容
。子组件
可以决定这些内容在哪里显示
。
二、插槽的基本使用
- 插槽就是"占一个位置",等别人来填内容
- 就像写了一个组件,里面留了一个空位,别人用这个组件的时候,可以自己决定空位放什么内容
举例来说,这里有一个 <FancyButton>
组件
js
<FancyButton>
Click me! <!-- 插槽内容 -->
</FancyButton>
而 <FancyButton>
的模板是这样的
js
<button class="fancy-btn">
<slot></slot> <!-- 插槽出口 -->
</button>
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
最终渲染出的 DOM 是这样:
js
<button class="fancy-btn">Click me!</button>
三、插槽的分类
名称 | 说明 |
---|---|
默认插槽 | 插入内容,不指定名字 |
具名插槽 | 插入内容,指定名字 |
作用域插槽 | 插槽内容可以访问子组件的数据 |
1.默认插槽
我们要在页面显示三个类别,每个类别下面有不同的文字,本来是我们把数据传给子组件然后使用v-for遍历生成的文字信息,但是产品经理突然让你把美食类的下面换成图片,电影类下面换成视频,怎么搞?
子组件:
js
<template>
<div class="category">
<h3>{{ title }}类</h3>
<ul>
<slot>我是一个插槽,当使用者没有传递具体结构时,我会出现</slot>
</ul>
</div>
</template>
父组件App.vue:
js
<template>
<div class="container">
<Category title="美食">
<!--往slot插入东西-->
<img src="http://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
</Category>
<Category title="游戏">
<!--往slot插入东西-->
<li v-for="(game, index) in games" :key="index">
{{ game }}
</li>
</Category>
<Category title="电影">
<!--往slot插入东西-->
<video controls src="http://clips.vorwaerts-gmbh.de/big_buck.bunny.mp4"></video>
</Category>
</div>
</template>
<script>
import Category from './components/Category.vue';
export default {
name: "App",
components: { Category },
data() {
return {
//foods: ['火锅', '烧烤', '小龙虾', '牛排'],
games: ['战神4', '极品飞车', '鬼泣', '超级玛丽'],
// films: ['《教父》', '《复仇者联盟》', '《绿皮书》', '《阿甘》']
}
},
}
</script>
2.具名插槽
子组件使用name属性起个名,父组件里面使用slot="名字"找到对应的坑位
html
父组件中:
<template>
<div>
<Category>
<div slot="center">中间的结构</div>
<a slot="center" href="http://www.zzy.com">中间的结构</a>
<template v-slot:footer> 最新写法,要配合template使用
<div>底部的结构</div>
<h4>欢迎你</h4>
</template>
</Category>
</div>
</template>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
</div>
</template>
3.作用域插槽
有一天,产品经理让你把每个部分的数据换个形式,换成下边这样,咋整?
这里就用到了作用域插槽,如果数据不在App中了,而在Category.vue中,然后App.vue要用到数据,这时我们就可以在Category.vue中使用slot标签给父组件App传值,写法很像当时父给子传值的props写法,在标签里搞个:games="games",然后用到插槽的地方必须使用template标签包裹,并且配置scope属性来接收数据,接过来的是一个对象
其实这个功能使用默认插槽完全可以实现,但是默认插槽是指数据在使用插槽的文件里的,那么如果数据在别的地方(比如本案例的Category.vue文件),就得用作用域插槽
html
Category.vue文件
<template>
<div class="category">
<h3>{{ title }}类</h3>
<slot :games="games">默认内容</slot>
</div>
</template>
<script>
export default {
name: 'Category',
props: ['title'],
data() {
return {
games: ['战神4', '极品飞车', '鬼泣', '超级玛丽']
}
},
};
</script>
html
App.vue文件
<template>
<div class="container">
<Category title="游戏">
<template scope="youxis">
<!-- {{ youxis.games }} -->
<!-- { "games": [ "战神4", "极品飞车", "鬼泣", "超级玛丽" ] } -->
<ul>
<li v-for="(game, index) in youxis.games" :key="index">
{{ game }}
</li>
</ul>
</template>
</Category>
<Category title="游戏">
<template scope="{games}">
<ol>
<li v-for="(game, index) in games" :key="index">
{{ game }}
</li>
</ol>
</template>
</Category>
<Category title="游戏">
<template slot-scope="{games: youxis}">
<h4 v-for="(game, index) in youxis" :key="index">
{{ game }}
</h4>
</template>
</Category>
</div>
</template>
<script>
import Category from './components/Category.vue';
export default {
name: "App",
components: { Category },
}
</script>