Vue插槽的使用介绍,你真的会用吗

390 阅读5分钟
插槽是什么?

插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。简单理解就是子组件中留下个“坑”,父组件可以使用指定内容来补“坑”。以下举例子帮助理解。

分类

vue的插槽有三种:分别是默认插槽、具名插槽、作用域插槽

插槽

  • 默认情况下,使用组件的时候不能在组件标签内填充内容的

  • 插槽的作用:在使用组件的时候,在组件标签内填充的内容,能成功渲染

    <template id="info">
        <div>
            <p>我是组件</p>
        </div>
    </template>
    
    <div id="app">
        <info>
            <!--在使用组件时,填充的内容不能渲染-->
            <P>使用组件标签时填充的元素</P>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
            },
        },
    });
    

插槽的使用

  • 定义组件的时候使用slot标签在组件内部”留坑“,那么在使用组件的时候,填充的内容就会渲染在坑上

  • 在使用slot标签留坑的时候也可以指定坑内的默认内容,如果指定了坑的默认内容,那么在使用组件的时候没有填充内容,则渲染slot标签的默认内容。如果指定了坑的默认内容,那么在使用组件的时候填充内容,则渲染填充内容。

    <template id="info">
        <div>
            <p>我是组件</p>
            <!--使用solt标签在组件内容留坑处理-->
            <slot>
                <!--并且可以指定默认的填充内容,也可以不指定默认的填充内容-->
                <p>我是组件坑内的内容</p>
            </slot>
        </div>
    </template>
    
    <div id="app">
        <info>
            <!--
          1.在使用组件时,填充了内容就会显示填充的内容
          2.如果没有填充内容就会显示组件slot标签的默认内容 -->
            <P>使用组件标签时填充的元素</P>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
            },
        },
    });
    

slot标签注意点

  • 默认一对slot标签就会渲染一次组件填充的全部内容,多次slot标签则渲染多次

    <template id="info">
        <div>
            <p>我是组件</p>
            <!--两对slot标签就会渲染填充的内容两次-->
            <slot>
                <p>我是组件坑内的内容</p>
            </slot>
            <slot>
                <p>我是组件坑内的内容</p>
            </slot>
        </div>
    </template>
    
    <div id="app">
        <info>
            <P>使用组件标签时填充的元素</P>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
            },
        },
    });
    

插槽的命名

  • 给slot标签添加name属性可以指定插槽的名称

  • 使用的时候需要给填充的内容绑定slot="插槽名称",填充到指定的插槽

    <template id="info">
        <div>
            <p>我是组件</p>
            <slot name="one">
                <p>我是组件坑内的内容</p>
            </slot>
            <slot name="two">
                <p>我是组件坑内的内容</p>
            </slot>
        </div>
    </template>
    
    <div id="app">
        <info>
            <!--这种填充方式存在指令属性冗余问题,因为需要多次绑定slot属性-->
            <P slot="one">使用组件标签时填充的内容1</P>
            <P slot="one">使用组件标签时填充的内容11</P>
            <P slot="one">使用组件标签时填充的内容111</P>
            <P slot="two">使用组件标签时填充的内容2</P>
            <P slot="two">使用组件标签时填充的内容22</P>
            <P slot="two">使用组件标签时填充的内容222</P>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
            },
        },
    });
    
  • 使用v-slot指令和template标签解决上述问题

    <template id="info">
        <div>
            <p>我是组件</p>
            <slot name="one">
                <p>我是组件坑内的内容</p>
            </slot>
            <slot name="two">
                <p>我是组件坑内的内容</p>
            </slot>
        </div>
    </template>
    
    <div id="app">
        <info>
            <template v-slot:one>
                <P>使用组件标签时填充的内容1</P>
                <P>使用组件标签时填充的内容11</P>
                <P>使用组件标签时填充的内容111</P>
            </template>
            <template v-slot:two>
                <P>使用组件标签时填充的内容2</P>
                <P>使用组件标签时填充的内容22</P>
                <P>使用组件标签时填充的内容222</P>
            </template>
            <!--简写-->
            <template #one>
                <P>使用组件标签时填充的内容1</P>
                <P>使用组件标签时填充的内容11</P>
                <P>使用组件标签时填充的内容111</P>
            </template>
            <template #two>
                <P>使用组件标签时填充的内容2</P>
                <P>使用组件标签时填充的内容22</P>
                <P>使用组件标签时填充的内容222</P>
            </template>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
            },
        },
    });
    

具名插槽

  • 匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次。出现在不同的位置。下面的例子,就是一个有两个具名插槽和单个插槽的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。

父组件:

<template>
  <div class="father">
    <h3>这里是父组件</h3>
    <child>
      <div class="tmpl" slot="up">
        <span>菜单1</span>
        <span>菜单2</span>
        <span>菜单3</span>
        <span>菜单4</span>
        <span>菜单5</span>
        <span>菜单6</span>
      </div>
      <div class="tmpl" slot="down">
        <span>菜单-1</span>
        <span>菜单-2</span>
        <span>菜单-3</span>
        <span>菜单-4</span>
        <span>菜单-5</span>
        <span>菜单-6</span>
      </div>
      <div class="tmpl">
        <span>菜单->1</span>
        <span>菜单->2</span>
        <span>菜单->3</span>
        <span>菜单->4</span>
        <span>菜单->5</span>
        <span>菜单->6</span>
      </div>
    </child>
  </div>
</template>

子组件:

<template>
  <div class="child">
    // 具名插槽
    <slot name="up"></slot>
    <h3>这里是子组件</h3>
    // 具名插槽
    <slot name="down"></slot>
    // 匿名插槽
    <slot></slot>
  </div>
</template>

可以看到,父组件通过html模板上的slot属性关联具名插槽。没有slot属性的html模板默认关联匿名插槽。

作用域插槽

  • 用域插槽就是带数据的插槽, 就是让父组件在填充子组件插槽内容时也能使用子组件的数据

  • 子组件通过v-bind指令传递

  • 父组件通过slot-scope接收

    <template id="info">
        <div>
            <p>我是组件</p>
            <slot v-bind:names= "name"></slot>
        </div>
    </template>
    
    <div id="app">
        <info>
            <template slot-scope="obj">
                <P>使用组件标签时填充的元素 {{ obj.names }}</P>
            </template>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
                data: function () {
                    return {
                        name: "lnj",
                    }
                }
            },
        },
    });
    
  • 整合优化:使用v-slot指令

    <template id="info">
        <div>
            <p>我是组件</p>
            <slot v-bind:names= "name"></slot>
        </div>
    </template>
    
    <div id="app">
        <info>
            <!--
          1.v-slot:插槽名称="通过什么变量接收"
          2.数据会以对象的形式保存到变量中
          3.匿名插槽的名称为default -->
            <template v-slot:default="obj">
                <P>使用组件标签时填充的元素 {{ obj.names }}</P>
            </template>
        </info>
    </div>
    
    new Vue({
        el: '#app',
        components:{
            "info":{
                template:"#info",
                data: function () {
                    return {
                        name: "lnj",
                    }
                }
            },
        },
    });
    

在 2.6.0 中,为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute。新语法的由来可查阅这份 RFC。注意slot版本变化,vue2中仍可以使用slot与slot-scope,但是vue3只能使用v-slot了,切记,避免踩坑。

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿