19、插槽


1、为什么使用插槽

组件的插槽是为了让我们封装的组件更加具有扩展性。让使用者可以决定组件内部的一些内容到底展示什么。
例子:下图移动端的导航栏
在这里插入图片描述
导航栏我们必然会封装成一个插件,比如nav-bar组件。一旦有了这个组件,我们就可以在多个页面中复用了。
如何封装组件合适:
抽取共性,保留不同。
最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。是搜索框,还是文字,还是菜单。由调用者自己来决定。

2、插槽的概念

插槽的关键字slot,默认情况下,组件中的模板会覆盖组件中的原始内容(即自定义标签对内部的内容会不显示),解决办法就是使用插槽。
插槽共分为3种:匿名插槽、具名插槽、作用域插槽

2.1、匿名插槽

匿名插槽的作用: 保留组件中的所有原始标签内容,这种插槽被称为匿名插槽,它保留了原始数据,除了具名插槽标签中的内容,即凡是标签中具有slot=top的属性标签。我们可以直接在组件中写上slot标签对,就可以在根元素中的引用的组件中间显示所写的内容。
匿名插槽:<slot></slot>
举例1:第一次使用插槽
需求,我们做一个如下的组件,但是我们想在各个组件中添加不同的内容,比如在第一个和第四个组件中加上button,第三个组件中加上p标签,第三个组件中加上i标签。这个时候就需要用到我们的插槽。
在这里插入图片描述

<div id="app">
        <cpn>
            <button type="button">按钮</button>
        </cpn>
        <cpn>
            <p>这是段落标签</p>
        </cpn>
        <cpn>
            <i>这是i标签</i>
        </cpn>
        <cpn>
            <button type="button">按钮</button>
        </cpn>
    </div>
    <template id="mycpn">
        <div style="border: 1px solid red;margin-top: 20px;line-height: 10px;">
            <h4>这是子组件的内容</h4>
            <!-- 使用插槽 -->
            <slot></slot>
        </div>
    </template>
    <script src="./Vuejs/vue2-6-12.js"></script>
    <script>
        let cpn = {
            template:"#mycpn",
        }
        new Vue({
            el:"#app",
            data:{
            },
            components:{
                "cpn":cpn,
            }
        })
    </script>

在这里插入图片描述
这里的slot可以理解成占位符,或者说是子组件暴露的一个让父组件传递自定义内容的接口。我们也可以在slot中添加默认内容,如做出下面修改:

<slot><button type="button">按钮</button></slot>

在我们的#app中创建如下cpn:

<div id="app">
        <cpn>
            <button type="button">按钮</button>
        </cpn>
        <cpn>
            <p>这是段落标签</p>
        </cpn>
        <cpn>
            <i>这是i标签</i>
        </cpn>
        <cpn>
            <button type="button">按钮</button>
        </cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>

在这里插入图片描述
由此我们知道在slot中加上默认样式,倘若组件中添加了其他样式,如上面的p标签和i标签,这个时候我们的默认样式就会被覆盖,只有不添加任何内容,才会显示我们的默认样式。

2.2、具名插槽

当子组件的功能复杂时,子组件的插槽可能并非是一个。比如我们封装一个首页的子组件,可能就需要三个插槽,分别代表头部、中间、底部。那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?这个时候,我们就需要给插槽起一个名字。
凡是具有name属性的slot标签,就被称为具名插槽即<slot name=top>(在子组件中写,写的位置不同,在引用该模板的页面中显示的位置也会不一样)。
作用:
①、 在组件的原始内容的某个标签中,添加slot=top属性,指明该标签所对应的 插槽的名称
②、在组件模板中通过调用slot标签,设置name=top属性,会自动将对应的标 签内容添加至当前slot标签所在的位置
注意:原始内容凡是具有slot属性的标签,内容只能添加至组件模板中具有相同值 的name属性的slot标签中。
具名插槽:<slot name=top></slot>
在这里插入图片描述
举例2:具名插槽的引入:

<div id="app">
        <cpn>
            <span>张三</span>
        </cpn>
    </div>
    <template id="mycpn">
        <div style="border: 1px solid red;margin-top: 20px;line-height: 10px;">
            <h4>这是子组件的内容</h4>
            <!-- 使用插槽 -->
            <p>姓名:<slot>姓名</slot></p>
            <p>性别:<slot>性别</slot></p>
            <p>年龄:<slot>年龄</slot></p>
        </div>
    </template>
    <script src="./Vuejs/vue2-6-12.js"></script>
    <script>
        let cpn = {
            template:"#mycpn",
        }
        new Vue({
            el:"#app",
            data:{
            },
            components:{
                "cpn":cpn,
            }
        })
    </script>

在这里插入图片描述
当我们创建了多个插槽,但只想使用其中一个的时候,我们发现使用匿名插槽的方法会让所有的创建的插槽都被使用,如上例中,我们只想姓名打印出张三,而其他位置不变,但是最终结果是三个位置都打印出张三。这个时候我们就要用到具名插槽。
在这里插入图片描述
举例3:使用具名插槽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>插槽学习</title>
</head>
<body>
    <div id="app">
        <cpn>
            <span slot="uname">张三</span>
            <span slot="uage"></span>
            <span slot="usex">18</span>
        </cpn>
    </div>
    <template id="mycpn">
        <div style="border: 1px solid red;margin-top: 20px;line-height: 10px;">
            <h4>这是子组件的内容</h4>
            <!-- 使用插槽 -->
            <p>姓名:<slot name="uname">姓名</slot></p>
            <p>性别:<slot name="uage">性别</slot></p>
            <p>年龄:<slot name="usex">年龄</slot></p>
        </div>
    </template>
    <script src="./Vuejs/vue2-6-12.js"></script>
    <script>
        let cpn = {
            template:"#mycpn",
        }
        new Vue({
            el:"#app",
            data:{
            },
            components:{
                "cpn":cpn,
            }
        })
    </script>
</body>
</html>

在这里插入图片描述
我们也可以使用v-bind动态绑定我们的name属性。

2.3、作用域插槽

官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念:
官方给出了一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

 <div id="app">
        <cpn></cpn>
    </div>
    <template id="mycpn">
        <div>
            <h2>我能不能显示出来呢?</h2>
        </div>
    </template>
    <script src="./Vuejs/vue2-6-12.js"></script>
    <script>
        let cpn = {
            template:"#mycpn",
            data(){
                return{
                    isshow:false
                }
            }
        }
        new Vue({
            el:"#app",
            data:{
                isshow:true,
            },
            components:{
                "cpn":cpn,
            }
        })
    </script>

在这里插入图片描述
我们在使用cpn的时候,整个组件的使用过程是相当于在父组件中出现的。
那么他的作用域就是父组件,使用的属性也是属于父组件的属性。
因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。

因此我们的作用域插槽就解决了这个问题,父组件替换插槽的标签,但是内容是由子组件来提供。当组件需要在多个父组件多个界面展示的时候,将内容放在子组件插槽中,父组件只需要告诉子组件使用什么方式展示界面。
子组件中包括一组数据,比如:pLanguages: [‘JavaScript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]
内容在子组件,希望父组件告诉我们如何展示,怎么办呢?
利用slot作用域插槽就可以了。
举例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>作用域插槽的基本使用</title>
    </head>
    <body>
        <!-- 父组件 -->
        <div id="app">
            <!-- 使用组件 -->
            <cpn></cpn>
            <!-- 以数组的形式展示 -->
            <cpn>
                <!-- 使用v-slot接收具名插槽abc的数据,并把他命名成aa(名称是自定义) -->
                <template v-slot="aa">
                    {{aa.abc}}
                </template>
            </cpn>
            
            <!-- 以水平方向 ‘-’的方式来显示 -->
            <cpn>
                <!-- 使用v-slot接收具名插槽abc的数据,并把他命名成aa(名称是自定义) -->
                <template v-slot="bb">
                    <!-- {{bb.abc}}- -->
                    {{bb.abc.join(' - ')}}
                </template>
            </cpn>
            
            <cpn>
                <!-- 使用v-slot接收具名插槽abc的数据,并把他命名成aa(名称是自定义) -->
                <template v-slot="bb">
                    <!-- {{bb.abc}}- -->
                    {{bb.abc.join(' * ')}}
                </template>
            </cpn>
        </div>
        
        <!-- 子组件的模板 -->
        <template id="mycpn">
            <div style="border: 2px solid #FF0000; margin: 20px 50px;">
                <h4>这是子组件的内容</h4>
                
                <!-- 作用域插槽:v-slot -->
                <!-- 定义具名插槽abc 并且传入数据pLanguages -->
                <slot :abc="pLanguages">
                    <ul v-for="item in pLanguages">
                        <li>{{item}}</li>
                    </ul>
                </slot>
        </template>
        
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
        <script type="text/javascript">
            
       // 创建子组件选项对象
       let cpn ={
        template:'#mycpn',
        data(){
            return{
              ishow:false,
              pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++']

            }
        }
       }
        // 创建实例
        var app=new Vue({
                el:'#app',
                data:{
                    ishow:true,//vue实例中的属性
                },
                components:{
                    // 注册cpn组件
                    cpn
                }
            })
        </script>
    </body>
</html>
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值