vue - 插槽详解

什么是插槽

官方文档是这样说明插槽的:

Vue 实现了一套内容分发的 API, 这套 API 的设计灵感源自 Web 规范草案, 将 <slot> 元素作为承载分发内容的出口。

插槽,简单说,插槽就是杯子,杯子里面装的是饮料还是牛奶,由外部倒入什么来决定 ,就好比下面的代码,有一个子组件,他有部分内容,需要根据我当前页面需要来展示,将html模板传入到子组件就需要使用插槽。

如下所示,定义一个子组件item,用solt标签定义一个默认插槽,为在父组件使用时,需要传递到item组件的模板,占个位置。 这样在父组件在item子组件中编写的html模板就会被渲染到子组件。

默认插槽

// 父组件
<template>
<tab>
    <item >
        <div>装一杯牛奶</div>
    <item>
<tab>
</template>
  
// item子组件
<template>
    <div>
        <slot></slot>  //默认插槽   在父组件使用item子组件,item标签包裹的内容将默认被渲染到子组件的solt中
        <h1>我是杯子</h1>           
    </div>
</template>

这样的好处,显而易见,可以让组件模块化更清晰,同时复用性更高。不至于我要一杯茶,我就要定义一个组件,我要一杯牛奶我又定义一个组件,有了插槽,我只需要定义一个杯子,要喝什么由使用的传入内容决定。

上述代码也叫默认插槽,就是默认把模板全部渲染到 solt 中,如果需要指定渲染,就需要使用具名插槽,简单说就是起一个名字,告诉他小红该坐那儿,小明该坐那儿

具名插槽

//父级
<template>
    <div>
        <layout>
            <template v-solt:header>头部标题</template>
            <div>显示的内容</div>
            <template v-solt:footer>尾部</template>
        </layout>
    </div>
</template>

//layout子组件
<template>
    <div>
        <layout>
            <h1>layout子组件</h1>
            <slot name="header"></slot>  //这种就叫具名插槽
            <slot></slot>   //如果不指定名字,就会将模板中未匹配到的内容渲染到默认插槽中,这里为显示的内容
            <slot name="footer"></slot>
        </layout>
    </div>
</template>

一个不带 name 的 <slot> 出口会带有隐含的名字“default”。

在向具名插槽提供内容的时候, 我们应该在<template> 元素上使用 v-slot 指令, 并以 v-slot 的参数的形式提供其名称: v-slot:heade

现在 <template> 元素中的所有内容都将会被传入相应的插槽。 任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容

作用域插槽

父组件提供了模板给子组件,那么子组件如何反馈给父组件呢,例如:我定义了一个杯子,我需要告诉使用的人,我这个杯子,只能装300mL,这时我们就需要用v-slot来接收子组件上通过v-bind绑定的值。

作用域插槽,就是能让插槽内容访问到子组件中才有的数据

//父级
<template>
    <div>
        <cup>
            <template v-slot:size="data">   // 这里将包含所有插槽 prop 的对象命名为 data, 也可以命名为其他的名字 
                  {{ data.msg }}
            </template>
            // vue 2.6 之前的写法, 用 slot 接收 name, slot-scope 接收子组件绑定的数据
            //<div solt="size" slot-scope="data">
            //    {{data.msg}}
    	    //</div>
        </cup>
    </div>
</template>

//cup子组件
<template>
    <div>
        <slot name="size" :msg="msg"></slot>  // 绑定在 <slot> 元素上的特性被称为插槽 prop。
    </div>
</template>
<script>
export default {
    data(){
    	return{
    	    msg:'300mL大小的杯子'
	}
    }
}
</script>

解构prop的写法,ES6 语法, 与上面的写法等价

//父级
<template>
    <div>
        <cup>
            <template v-slot:size="{ msg }">    
                  {{ msg }}
            </template>

            // 解构 并重命名
            //<template v-slot:size="{ msg : info }">    
            //      {{ info }}
            //</template>
        </cup>
    </div>
</template>

上面有说到 vue2.6之前插槽的版本,之后vue官方废弃了上面的语法,改为v-solt来代替,区别在于

  • vue 2.6 之后的版本 v-slot 指令合并了solt 和solt-scope 这两个attribute,写法更加简洁
  • 语义化更明显
  • 2.6之前的写法会出现作用域混淆的问题

独占默认插槽

v-slot 只能添加在一个 <template> 上 (只有一种例外情况), 这一点和已经废弃的 slot 特性不同。而这个例外就是 独占默认插槽。

当被提供的内容只有默认插槽时, 组件的标签才可以被当作插槽的模板来使用。 这样我们就可以把 v-slot 直接用在组件上:

父组件
<template>
    <item v-slot:default="data"> //v-slot:default可以不加 v-slot="data"
        {{ data.msg }}
    <item>
</template>
      
     
//item子组件
     <template>
         <div>
             <slot :msg="msg"></slot>//默认插槽         
         </div>
     </template>

默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确。下面是官方的例子:

<!-- 无效,会导致警告 -->
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
  <template v-slot:other="otherSlotProps">
    slotProps is NOT available here
  </template>
</current-user>

注意:只要出现多个插槽, 请始终为所有的插槽使用完整的基于 <template> 的语法

动态插槽名

v-slot 支持2.6的动态参数写法

<layout>
  <template v-slot:[attributeName]>
    ...
  </template>
</layout>

这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data property attributeName,其值为 "header",那么这个绑定将等价于 v-slot:header。

具名插槽的缩写

v-slot 也有缩写, 即把参数之前的所有内容( v-slot: ) 替换为字符 # 。 例如 v-slot:header 可以被重写为 #header

//父级
<template>
    <div>
        <layout>
            <template #header>头部标题</template>  // 具名插槽的缩写
            <div>显示的内容</div>
            <template v-solt:footer>尾部</template>
        </layout>
    </div>
</template>

//layout子组件
<template>
    <div>
        <layout>
            <h1>layout子组件</h1>
            <slot name="header"></slot>  //这种就叫具名插槽
            <slot></slot>   //如果不指定名字,就会将模板中未匹配到的内容渲染到默认插槽中,这里为显示的内容
            <slot name="footer"></slot>
        </layout>
    </div>
</template>

注意: 该缩写只在其有参数(例如:name)的时候才可用。

参考:https://blog.csdn.net/marendu/article/details/106288627

posted @ 2020-08-06 17:30  精灵W的博客  阅读(374)  评论(0编辑  收藏  举报