文章目录

  • 引例
  • 普通插槽
    • 使用方法
    • 插槽的编译
  • 具名插槽
    • template
  • 作用域插槽
  • 插槽总结

引例

想要实现如下效果:

发现3个模块的样式一样,所以可以写一个组件,传递不同的数据实现。
实现代码:
单个样式:Category组件(子组件)
Category.vue:

<template><div class="category"><h3>{{title}}</h3><ul><li v-for="(item,index) in listData" :key="index">{{item}}</li></ul></div></template><script>export default {name: 'CategoryVue',props:['listData','title']}</script><style>.category{width:200px;height: 300px;background: lightseagreen;}h3{text-align: center;background: lightgoldenrodyellow;}</style>

App.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";export default {name: "App",data() {return {foods: ['烧烤', '火锅', '小龙虾', '螺蛳粉'],films: ['《当幸福来敲门》', '《泰坦尼克号》', '《阿甘正传》', '《海上钢琴师》'],games:['王者荣耀','我的世界','和平精英','穿越火线']}},components: {Category}}</script><style lang="css">.container{display: flex;justify-content: space-around;}</style>

那如果想要实现如下效果又该怎么做呢?
(即不同的模块显示的内容格式不一样)——可以通过插槽来实现

普通插槽

插槽标签:

使用方法

  • 插槽一般定义在子组件中,相当于一个占位。
  • 父组件模板中的子组件标签要写成一对的样式,即:
  • 这样中的内容就会显示在子组件标签的位置。
  • 如果中没有内容,标签中的内容就会显示在页面。

这里父组件被称为插槽的使用者

实现:
Category.vue:

<template><div class="category"><h3>{{title}}</h3><slot>我是一个插槽,如果组件标签中没有传递值时,我就显示,否则显示组件传递过来的内容</slot></div></template><script>export default {name: 'CategoryVue',props:['listData','title']}</script><style>.category{width:200px;height: 300px;background: lightseagreen;overflow: hidden;}h3{text-align: center;background: lightgoldenrodyellow;}</style>

App.vue

<template><div class="container"><Category title="美食"><img src="./assets/1.jpg" /></Category><Category title="游戏"><ul><li v-for="(game,index) in games" :key="index">{{game}}</li></ul></Category><Category title="电影"><video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video></Category></div></template><script>import Category from "@/components/Category";export default {name: "App",data() {return {foods: ['烧烤', '火锅', '小龙虾', '螺蛳粉'],films: ['《当幸福来敲门》', '《泰坦尼克号》', '《阿甘正传》', '《海上钢琴师》'],games:['王者荣耀','我的世界','和平精英','穿越火线']}},components: {Category}}</script><style lang="css">.container{display: flex;justify-content: space-around;}img{width: 100%;}video{width: 100%;}</style>

实现效果:

如果App.vue的子组件标签中不放内容,就会将是如下样式:(将slot的内容进行显示)

插槽的编译

app.vue子组件标签中的html代码片段是编译完之后再放到子组件的插槽中去,所以该html代码片段的样式既可以卸载app.vue文件中,也可以写在子组件中。

具名插槽

一个子组件可能有多个插槽,不同的插槽放置不同的内容,为了区分不同的插槽,每个插槽应该有自己的名字,这就是具名插槽

同时app.vue子组件标签中的html代码片段的内容也需要设置slot属性,用于指明该片段放在哪个插槽中。
如果两个片段放在一个插槽中,不会覆盖只是追加。

category.vue(子组件)

<template><div class="category"><h3>{{title}}</h3><slot name="center">我是一个插槽,如果组件标签中没有传递值时,我就显示,否则显示组件传递过来的内容center</slot><slot name="footer">我是一个插槽,如果组件标签中没有传递值时,我就显示,否则显示组件传递过来的内容footer</slot></div></template><script>export default {name: 'CategoryVue',props:['listData','title']}</script><style>.category{width:200px;height: 300px;background: lightseagreen;overflow: hidden;}h3{text-align: center;background: lightgoldenrodyellow;}</style>

app.vue(父组件)

<template><div class="container"><Category title="美食"><img slot="center" href="./assets/1.jpg" /><a slot="footer" href="https://www.baidu.com">点我查看更多</a></Category><Category title="游戏"><ul slot="center"><li v-for="(game,index) in games" :key="index">{{game}}</li></ul><a slot="footer" href="https://www.baidu.com">单机游戏</a><a slot="footer" href="https://www.baidu.com">网络游戏</a></Category><Category title="电影"><video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video><div class="foot" slot="footer"><a href="https://www.baidu.com">经典</a><a href="https://www.baidu.com">热门</a><a href="https://www.baidu.com">推荐</a></div></Category></div></template><script>import Category from "@/components/Category";export default {name: "App",data() {return {foods: ['烧烤', '火锅', '小龙虾', '螺蛳粉'],films: ['《当幸福来敲门》', '《泰坦尼克号》', '《阿甘正传》', '《海上钢琴师》'],games:['王者荣耀','我的世界','和平精英','穿越火线']}},components: {Category}}</script><style lang="css">.container,.foot{display: flex;justify-content: space-around;}img{width: 100%;height: 50%;}video{width: 100%;}</style>

效果:

template

slot属性碰上template标签可以这样写:

eg:

<template v-slot:footer><div class="foot"><a href="https://www.baidu.com">经典</a><a href="https://www.baidu.com">热门</a><a href="https://www.baidu.com">推荐</a></div><h4>欢迎观看电影</h4></template>

作用域插槽

作用域插槽的应用场景:
数据子组件中,而根据数据生成的结构插槽的使用者上。
(插槽的使用者即使用子组件的父组件)。

传递数据
因为插槽的使用者(父组件)需要使用子组件的数据, 所以需要将数据从子组件传递到插槽的使用者中。

  • 子组件的传递方法,利用插槽标签结合v-bind指令进行传递:

    可以传递多个数据
  • 插槽的使用者接收的方法:使用标签的scope属性接收从子组件通过标签传递过来的所有数据,接收到的数据是一个对象。
    也可以使用标签的slot-scope属性接收数据。
    scope和slot-scope接收数据支持解构赋值
<template scope="自己起的变量名"></template>

使用:

  • 子组件category.vue —— 数据在子组件中
<template><div class="category"><h3>{{title}}</h3><slot :games="games">我是一个插槽</slot></div></template><script>export default {name: 'CategoryVue',props: ['title'],data() {return{games: ['王者荣耀', '我的世界', '和平精英', '穿越火线']}}}</script><style>.category{width:200px;height: 300px;background: lightseagreen;overflow: hidden;}h3{text-align: center;background: lightgoldenrodyellow;}</style>
  • 父组件App.vue(插槽的使用者) —— 结构在父组件中
<template><div class="container"><Category title="游戏"><template scope="youxi"><ul><li v-for="(game,index) in youxi.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}"><h4 v-for="(game,index) in games" :key="index">{{game}}</h4></template></Category></div></template><script>import Category from "@/components/Category";export default {name: "App",components: {Category}}</script><style lang="css">.container{display: flex;justify-content: space-around;}</style>

实现的效果:

作用域插槽可以设置名字

插槽总结

  • 插槽的作用:
    让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件