插槽
案例分析
我们首先建立一个vue脚手架,修改App.vue,并自定义一个组件为category.vue,实现三个表单,如下所示。
<template>
<div class="container">
<Category title="美食" :listdata="foods"/>
<Category title="游戏" :listdata="games"/>
<Category title="电影" :listdata="films"/>
</div>
</template>
<script>
import Category from "./components/Category.vue";
export default {
name: "App",
components: { Category },
data() {
return {
foods:['吃饭','吃饭','吃饭'],
games:['游戏','游戏','游戏'],
films:['电影','电影','电影'],
}
},
};
</script>
<style>
.container {
display: flex;
/* 主轴对齐方式 */
justify-content: space-around;
}
</style>
<template>
<div class="category">
<h1>{{ title }}</h1>
<ul>
<!-- 遍历App.vue传过来的参数listdata -->
<li v-for="(item,index) in listdata" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
name: "Category",
props: ['listdata', 'title'],
};
</script>
<style>
.category {
background-color: skyblue;
width: 200px;
height: 300px;
}
h1 {
text-align: center;
background-color: orange;
}
</style>
默认插槽
现在,修改案例需求,要求美食表单中显示图片,电影表单中显示视频,游戏表单中不改变。我们使用的方法是把App.vue中的组件标签,写成有开始和结束标签的形式,然后在标签中间加上一些具体内容,在子组件Category中使用默认插槽<slot></slot>
,指示vue将具体内容安插到slot内。
//App.vue代码
<template>
<div class="container">
<!-- 在组件标签的另一种写法中,即有开始和结束标签的写法,加入标签体内容 -->
<Category title="美食">
<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="" />
</Category>
<Category title="游戏">
<ul>
<li v-for="(item, index) in games" :key="index">{{ item }}</li>
</ul>
</Category>
<Category title="电影">
<!-- controls是控制视频播放的属性 -->
<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: ["游戏", "游戏", "游戏"],
films: ["电影", "电影", "电影"],
};
},
};
</script>
<style scoped>
.container {
display: flex;
/* 主轴对齐方式 */
justify-content: space-around;
}
video {
width: 100%;
}
img {
width: 100%;
}
</style>
//category.vue代码
<template>
<div class="category">
<h1>{{ title }}</h1>
<!-- slot是插槽的意思,告诉vue,在App.vue中组件标签内的内容,放在此处 -->
<slot>
这里可以加一些默认值,当没有传递组件标签内的具体结构时,就会显示
</slot
>
</div>
</template>
<script>
export default {
name: "Category",
props: [ "title"],
};
</script>
<style>
.category {
background-color: skyblue;
width: 200px;
height: 300px;
}
h1 {
text-align: center;
background-color: orange;
}
</style>
具名插槽
具名插槽就是具有名字的插槽,当vue组件中出现多个插槽使用时,就得给每个插槽取个名字才可以避免混乱。在slot标签内增加name属性即可。具体使用如下:
//App.vue代码
<template>
<div class="container">
<!-- 在组件标签的另一种写法中,即有开始和结束标签的写法,加入标签体内容 -->
<Category title="美食">
<!-- 加上slot插槽名字,就告诉vue,该内容往叫center的插槽内放 -->
<img
slot="center"
src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg"
alt=""
/>
<!-- 加上slot插槽名字,就告诉vue,该内容往叫footer的插槽内放 -->
<a slot="footer" href="http://www.atguigu.com">更多美食</a>
</Category>
<Category title="游戏">
<ul slot="center">
<li v-for="(item, index) in games" :key="index">{{ item }}</li>
</ul>
<!-- 加上slot插槽名字,就告诉vue,该内容往叫footer的插槽内放 -->
<a slot="footer" href="http://www.atguigu.com">单机游戏</a>
<!-- 加上slot插槽名字,就告诉vue,该内容往叫footer的插槽内放 -->
<a slot="footer" href="http://www.atguigu.com">网络游戏</a>
</Category>
<Category title="电影">
<!-- controls是控制视频播放的属性 -->
<video slot="center"
controls
src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
></video>
<a slot="footer" href="http://www.atguigu.com">网络游戏</a>
<a slot="footer" href="http://www.atguigu.com">网络游戏</a>
<a slot="footer" href="http://www.atguigu.com">网络游戏</a>
</Category>
</div>
</template>
<script>
import Category from "./components/Category.vue";
export default {
name: "App",
components: { Category },
data() {
return {
foods: ["吃饭", "吃饭", "吃饭"],
games: ["游戏", "游戏", "游戏"],
films: ["电影", "电影", "电影"],
};
},
};
</script>
<style scoped>
.container {
display: flex;
/* 主轴对齐方式 */
justify-content: space-around;
}
video {
width: 100%;
}
img {
width: 100%;
}
</style>
//category.vue代码
<template>
<div class="category">
<h1>{{ title }}</h1>
<!-- slot是插槽的意思,告诉vue,在App.vue中组件标签内的内容,放在此处 -->
<!-- slot标签内的属性name是给插槽起名字 -->
<slot name="center">
这里可以加一些默认值,当没有传递组件标签内的具体结构时,就会显示
</slot>
<slot name="footer">
这里可以加一些默认值,当没有传递组件标签内的具体结构时,就会显示
</slot>
</div>
</template>
<script>
export default {
name: "Category",
props: ["title"],
};
</script>
<style>
.category {
background-color: skyblue;
width: 200px;
height: 300px;
}
h1 {
text-align: center;
background-color: orange;
}
</style>
最后输出效果如下:
作用域插槽
继续上边的例子,现在我们只保留游戏表单,页面显示三个游戏表单,在代码中,App.vue是组件category的使用者,数据也放在了App.vue中。现在提出新需求,对每个表单中的列表内容,显示不同,第一个是无序列表显示,第二个是有序列表显示,第三个变为h4标题显示。那么我们App.vue,即category的使用者怎么得到放在category组件内的数据呢?
App.vue代码
<template>
<div class="container">
<Category title="游戏">
<!-- 要想拿到插槽反向传过来给插槽使用者的数据,就必须包裹上一个template -->
<!-- v-slot是作用域的意思,等号后边的内容可以随便写,该内容接受反向传过来的数据,以对象的形式 -->
<template v-slot:default="games">
<ul>
<li v-for="(item, index) in games.ShuJu" :key="index">{{ item }}</li>
</ul>
</template>
</Category>
<Category title="游戏">
<template v-slot:default="games">
<ol>
<li v-for="(item, index) in games.ShuJu" :key="index">{{ item }}</li>
</ol>
</template>
</Category>
<Category title="游戏">
<template v-slot:default="games">
<h4 v-for="(item, index) in games.ShuJu" :key="index">{{ item }}</h4>
</template>
</Category>
</div>
</template>
<script>
import Category from "./components/Category.vue";
export default {
name: "App",
components: { Category },
};
</script>
<style scoped>
.container {
display: flex;
/* 主轴对齐方式 */
justify-content: space-around;
}
</style>
category中代码
<template>
<div class="category">
<h1>{{ title }}</h1>
<!-- 这就是把data中的games数据传递给了插槽的使用者 -->
<slot v-bind:ShuJu="games">
这里可以加一些默认值,当没有传递组件标签内的具体结构时,就会显示
</slot>
</div>
</template>
<script>
export default {
name: "Category",
props: ["title"],
data() {
return {
games: ["游戏", "游戏", "游戏"],
};
},
};
</script>
<style>
.category {
background-color: skyblue;
width: 200px;
height: 300px;
}
h1 {
text-align: center;
background-color: orange;
}
</style>
实际输出效果
总结