1.什么是插槽:

插槽(slot)可以让我们在自定义组件的时候把一部分内容预留出来,留给使用该组件的人去自定义,同时我们还可以传递一些数据供其使用。

2.插槽的定义:
  • 格式:
<slot name="插槽名称" :xxx="数据1" :yyy="数据2">默认内容</slot>
  1. name可以不写,默认值为"default",这种插槽称为不具名插槽或者默认插槽,但是只能有一个,有name的称为具名插槽
  2. 传参和正常组件的数据绑定没有区别,数据格式不限,个数不限
  3. 默认内容在插槽没有被匹配时才生效
  • 例子:
<template>
    <div>
        <header>
            <!--定义一个叫header的插槽,传参data -->
            <slot name="header" :data="data"></slot>
        </header>
        
        <div>MyComponent组件自己的内容1</div>
        
        <!-- 这是默认插槽(也叫不具名插槽)-->
        <!-- 等价于 <slot name="default" :middle="data.middle"></slot> -->
        <slot :middle="data.middle"></slot> 
        
        <div>MyComponent组件自己的内容2</div>
        
        <footer>
       	    <!--定义一个叫footer的插槽,传参msg,bottom -->
            <slot name="footer" :msg="data.footer" :bottom="data.bottom"></slot>
        </footer>
    </div>
</template>
<script>
export default {
  name: "MyComponent",
  data() {
    return {
       data: {
       	  header: "header-slot",
       	  middle: "default-slot",
       	  footer: "footer-slot",
       	  bottom: "bottom-slot",
       }
     }
  }
}
</script>
3.插槽的使用

vue 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的特性 —— vue官网

官方已经废弃了slot和slot-scope(但仍然可用),推荐使用v-slot,但是为了全面介绍插槽,两种写法此处都会介绍

为了便于描述,我称以下使用插槽的格式(格式1和格式2)为plug(插头),对应默认插槽的叫 默认plug

  • 格式1(slot和slot-scope):
 <template slot="插槽名称" slot-scope="scope">
 	<!-- 自定义内容 -->
 </template>
  1. slot的值和插槽定义时的插槽名称对应,这样就可以替换对应的插槽部分,实现plug和插槽的匹配
  2. 如果是匹配默认插槽,slot可以省略,即<template slot-scope=“scope”>,或者slot的值可省略,即<template slot slot-scope=“scope”>,以下称它为“默认plug”
  3. 多个plug的slot同名时(含默认plug),只有最后一个有效,前面的会失效(被丢弃)
  4. slot-scope用于接收参数,它的值是一个对象,可自定义名称,它包含了对应插槽定义时传入的所有参数,可通过scope.xxx, scope.yyy取值,支持解构写法,如:slot-scope=“{xxx, yyy}”
  5. plug的作用域为它位于的当前组件,它并不能访问对应插槽的作用域
  6. 请不要嵌套使用plug,因为它会导致作用域不明确
  7. 插槽匹配原则(简单总结,也适用于v-slot):
    A. slot有值的情况下会通过名称匹配,匹配不到则丢弃;
    B. slot没有值(或者名称为“default”)的情况下,会匹配默认插槽,默认插槽不存在则丢弃;
    C. 只有在默认插槽存在默认plug不存在的情况下,组件标签内多余的内容才会替换默认插槽的内容,否则会被丢弃;
    D. 对于默认插槽,在默认plug不存在组件标签内没有多余的内容情况下,其定义内的默认内容才会生效;对于具名插槽对应的plug不存在默认内容会生效
  • 例子1:
<template>
    <div>
        <my-component>
        	<!-- 对接名称为"header"的插槽 -->
            <template slot="header" slot-scope="scope">
                <h1>{{scope.data.header}}</h1>
            </template>

            <!-- my-component中没有指定slot的部分会被全部放到默认插槽内(在默认plug不存在的情况下) -->
            <p>default content A</p>
            <p>and default content B</p>
            <!-- 默认plug
            <template slot-scope="scope">
            	<p>{{ scope.middle }}</p>
            </template>
            -->

			<!-- 对接名称为"footer"的插槽 -->
            <template slot="footer" slot-scope="scope">
                <p>{{ scope.msg + "," + scope.bottom}}</p>
            </template>
        </my-component>
    </div>
</template>
<script>
    import MyComponent from './MyComponent.vue'
    export default {
        components: { MyComponent }
    }
</script>
  • 格式2(v-slot):
<template v-slot:插槽名称="scope">
 <!-- 自定义内容 -->
</template>
  1. 如果是匹配默认插槽可以写成<template v-slot=“scope”>或者<template v-slot:default=“scope”>
  2. v-slot可简写为“#”,即<template #插槽名称=“scope”>,
    但是对于默认插槽只能写成 #default=“scope” 不能写成 #=“scope”
  3. 结合1和2,默认plug有三种写法:v-slot, v-slot:default,#default
  4. v-slot的值同slot-scope的值,可解构,即v-slot=“{ xxx, yyy }”
  5. v-slot只是格式1的不同写法,它的其他特性可参考格式1中的说明
  • 例子2:
<template>
    <div>
        <my-component>
        	<!-- 对接名称为"header"的插槽 -->
            <template v-slot:header="scope">
                <h1>{{scope.data.header}}</h1>
            </template>
            
         	<!-- 默认plug,对接默认插槽(不具名插槽)-->
         	<!-- 等价于<template #default="{ middle }"> -->
            <template v-slot="{ middle }">
            	<p>{{ middle }}</p>
            </template>
			
			<!-- 在默认plug已存在的情况下,my-component中多余的内容会被丢弃 -->
			<!-- 比如下面的内容没有匹配到任何的插槽,同时默认的插槽也被占用 -->
			<!-- 所以下面的内容会被丢弃,这是插槽匹配中的一个重要特性-->
			<p>default content.</p>

  			<!-- 对接名称为"footer"的插槽 -->
            <template #footer="{ msg, bottom }">
                <p>{{ msg + "," + bottom}}</p>
            </template>
        </my-component>
    </div>
</template>
<script>
    import MyComponent from './MyComponent.vue'
    export default {
        components: { MyComponent }
    }
</script>
Logo

鸿蒙生态一站式服务平台。

更多推荐