Vue 中 slot (插槽)是什么? 有什么作用?

3,108 阅读2分钟

slot 是什么?

slot 又名插槽,是 Vue 的内容分发机制,组件内部的模板引擎使用 slot 元素作为承载分发内容的出口。插槽slot 是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot 又分三类,默认插槽,具名插槽和作用域插槽。

  • 默认插槽:又名匿名查抄,当 slot 没有指定 name 属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。
  • 具名插槽:带有具体名字的插槽,也就是带有 name 属性的 slot,一个组件可以出现多个具名插槽。
  • 作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。

实现原理:当子组件 vm 实例化时,获取到父组件传入的 slot 标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到 slot 标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

// 父组件
<template>
    <div id="father">
        <son>
            <!-- 下面的节点如果没有使用插槽,将不会显示 -->
            
            // 旧版本中的写法
            <!-- 默认插槽 -->
            <div>0000000000</div>
            <!-- 具名插槽 -->
            <div slot="a">11111111111</div>
            <div slot="b">2222222222</div>
            <!-- 作用域插槽:获取子组件中内部定义一个数据`msg` -->
            <div slot="c" slot-scope="slotProps">
                {{slotProps.msg}}
            </div>
            
            // 新版本中的写法:v-slot:插槽名 或 #插槽名
            <template v-slot:c="slotProps"> 
                {{slotProps.msg}} 
            </template> 
            <!-- 也可以缩写为 #插槽名 -->  
            <template #c="slotProps">   // slotProps是绑定在 <slot> 元素上的 attribute 被称为插槽 prop
                {{slotProps.msg}} 
            </template>
        </son>
    </div>
</template>

<script>
import son from "./son.vue";
export default {
    name: father,
    components: {
        son
    }
};
</script>
// 子组件
<template>
    <div id="son">
        <!-- 插槽,允许父组件里面的元素在此处插入并显示 -->
        <!-- 默认插槽 -->
        <slot></slot>
        <!-- 具名插槽 -->
        <slot name="a"></slot>
        <slot name="b"></slot>
        <!-- 作用域插槽 -->
        <slot name="c" :msg="msg"></slot>   
    </div>
</template>
<script>
export default {
    name: "son",
    data () {
        return {
            msg: "子组件的数据"
        }
    }
};
</script>

slot 有什么作用?

  1. 扩展组件能力,提高组件的复用性;
  2. 使用插槽可以将一些比较复杂的父传子的通信去掉,直接在父组件中完成后利用插槽显示到子组件中(这是由于父组件模板的内容在父组件作用域内编译,子组件模板的内容在子组件作用域内编译)。