Vue中的插槽

  • 我们已经了解到父组件是可以通过 props 将数据传给子组件的,它可以是任何类型的 JavaScript 值。但是 模板内容(html片段)呢?在某些情况下,我们可能希望将模板片段传递给子组件,并让子组件在其自己的模板中渲染该片段,由此引出 插槽
  • slot(插槽)是 vue 为 组件的封装者 提供的能力。允许开发者在封装组件时,把 不确定的、希望由用户指定的部分 定义为插槽(即父组件向子组件传递带数据的标签,当一个子组件有不确定的结构时,就需要用到插槽了[slot])。可以把插槽认为是组件封装期间,为用户预留的内容的占位符。 注意:插槽内容是在父组件中编译后,在传递给子组件的.

作用:

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

图解:

image

插槽的分类:

1.默认插槽(简单)

  • 通常来说我们组件中内的标签是无法放任何外部组件内容的,如果想子组件中的内容, 由外部的组件来决定我们可以使用默认插槽,在组件内声明 slot 标签

代码解析:

  • App父组件(省略css样式)
    <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 = '电影'>
    <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    </Category>

    <Category title = '测试插槽默认值'/>
    </div>
    </template>

    <script>
    // 引入组件
    import Category from './components/Category'
    export default {
    name:'App',
    // 注册组件
    components:{Category},
    data() {
    return {
    foods : ['青菜','牛肉','猪肉','鸡肉'],
    games : ['CSGO' , 'Apex' , 'Raionbow Six'],
    films : ['让子弹飞','功夫','天下无贼','明日战记']
    }
    },
    }
    </script>
  • Category子组件(省略css样式)
    <template>
        <div class="Category">
            <h3>{{title}}</h3>
            <!-- 定义一个插槽(slot就是插槽的入口) -->
            <!-- 不写的话你在App组件中写的结构体是即便是被解析了也不会显示 -->
            <slot>这是插槽的默认值,如果没有东西填入就会显示这段文字</slot>
        </div>
    </template>

    <script>
        export default {
            name : 'Category',
            // 接收父组件(App)传过来的数据(美食,电影,游戏等数据,以及标题)
            props : ['title']
        }
    </script>

结果展示:

image

2.具名插槽(简单)

  • 具名插槽,顾名思义就是给这个插槽起个名字,插槽在使用 name 属性绑定名字后, 在组件被调用的时候,组件内的标签通过 slot 属性来决定某个标签具体渲染哪一个插槽

代码解析:

  • App父组件(省略css样式)
    <template>
    <div class="container">
    <Category title = '美食'>
    <!-- 给结构体赋予slot属性用于指定解析过后插入位置(slot标签) -->
    <img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
    <a slot="footer" href="#">更多美食</a>
    </Category>

    <Category title = '游戏'>
    <ul slot="center">
    <li v-for="(item,index) in games" :key="index">{{item}}</li>
    </ul>
    <div class="foot" slot="footer">
    <a href="#">单机游戏</a>
    <a href="#">网络游戏</a>
    </div>
    </Category>

    <Category title = '电影'>
    <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    <!-- Vue2.6新特性,使用 template标签可以使用 v-slot:footer 代替 slot="footer"-->
    <template v-slot:footer>
    <div class="foot">
    <a href="#">经典</a>
    <a href="#">热门</a>
    <a href="#">推荐</a>
    </div>
    <h4>欢迎前来观影</h4>
    </template>
    </Category>

    <Category title = '测试插槽默认值'/>
    </div>
    </template>

    <script>
    // 引入组件
    import Category from './components/Category'
    export default {
    name:'App',
    // 注册组件
    components:{Category},
    data() {
    return {
    foods : ['青菜','牛肉','猪肉','鸡肉'],
    games : ['CSGO' , 'Apex' , 'Raionbow Six'],
    films : ['让子弹飞','功夫','天下无贼','明日战记']
    }
    },
    }
    </script>
  • Category子组件(省略css样式)
    <template>
    <div class="Category">
    <h3>{{title}}</h3>
    <!-- 定义一个插槽(slot就是插槽的入口) -->
    <!-- 不写的话你在App组件中写的结构体是即便是被解析了也不会显示 -->
    <!-- 这里给插槽设置一个name属性用于指定标签内结构体二第插入位置 -->
    <slot name="center">这是插槽的默认值,如果没有东西填入就会显示这段文字1(center插槽)</slot><br><br>
    <slot name="footer">这是插槽的默认值,如果没有东西填入就会显示这段文字2(footer插槽)</slot>
    </div>
    </template>

    <script>
    export default {
    name : 'Category',
    // 接收父组件(App)传过来的数据(美食,电影,游戏等数据,以及标题)
    props : ['title']
    }
    </script>

结果展示:

image

3.作用域插槽(较为拗口,难理解)

  • 要想了解作用域插槽, 先了解需求之后比较好理解: 有时候数据在子组件中,但是却想让父组件来决定具体怎么展示,这里是:数据在子组件(这里的Category组件即子组件)的自身,但根据数据生成的结构需要组件的使用者(App组件即父组件)来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
  • 这时候我们可以通过作用域插槽, 让子组件通过属性绑定的方式,把子组件的数据绑定到子组件中的某个属性上
  • 父组件就可以通过slot-scope = slot拿到子组件中挂载在插槽中的数据,之后通过 比如 slot.attribute 来得到具体的数据(ps: elementui 中的表格就是使用的作用域插槽)
  • 注意在父组件中,如果要拿到子组件通过属性绑定在插槽中的数据需要使用 template 标签

代码解析:

  • App父组件(省略css样式)
    <template>
    <div class="container">
    <Category title = '游戏'>
    <!-- 作用与插槽要配合 template标签来使用 -->
    <!-- slot-scope="yx" 这里的属性值可以随意取 -->
    <!-- 当然也可以填入name属性来指定插入位置(具名插槽) -->
    <template slot-scope="yx">
    <ul>
    <li v-for="(item,index) in yx.games" :key="index">{{item}}</li>
    </ul>
    </template>
    </Category>

    <Category title = '游戏'>
    <template slot-scope="yx">
    <ol>
    <li v-for="(item,index) in yx.games" :key="index">{{item}}</li>
    </ol>
    </template>
    </Category>

    <Category title = '游戏'>
    <template slot-scope="yx">
    <h4 v-for="(item,index) in yx.games" :key="index">{{item}}</h4>
    </template>
    </Category>

    <Category title = '测试插槽默认值'/>
    </div>
    </template>

    <script>
    // 引入组件
    import Category from './components/Category'
    export default {
    name:'App',
    // 注册组件
    components:{Category},

    }
    </script>
  • Category子组件(省略css样式)
    <template>
    <div class="Category">
    <h3>{{title}}</h3>
    <!-- 定义一个插槽(slot就是插槽的入口) -->
    <!-- 不写的话你在App组件中写的结构体是即便是被解析了也不会显示 -->
    <!-- :games="games" 将数据发送给父组件(App),指定作用域接收使用 -->
    <slot :games="games">这是插槽的默认值,如果没有东西填入就会显示这段文字</slot>
    </div>
    </template>

    <script>
    export default {
    name : 'Category',
    // 接收父组件(App)传过来的数据(美食,电影,游戏等数据,以及标题)
    props : ['title'],
    data() {
    return {
    games : ['CSGO' , 'Apex' , 'Raionbow Six'],
    }
    },
    }
    </script>

结果展示:

image

这篇博客引用了作者为”╰☆阳光のboy“的文章
原文链接为:CSDN