Skip to content

插槽

插槽的本质是一个返回VNode的函数

在vm上有以下两个属性

vm.$slots

类型:vm.$slots是一个对象,对象里面放着父组件传来的所有的具名插槽默认插槽的数组

typescript
{ 
    [name: string]: ?Array<VNode>
}

为什么是数组

因为父组件使用使用插槽时,默认插槽和同名的具名插槽可以传递多个

vue
<template>
  <Child>
    <span slot="aaa">456</span>
    <span slot="aaa">456</span>
      
    <span slot="bbb">456</span>
    <span slot="ccc">789</span>
      
    <span>789</span>
    <span>789</span>
  </Child>
</template>
vue
<script>
    mounted() {
        console.log(this.$slots);
    },
</script>

打印结果如下所示

image-20250507095925176

vm.$scopedSlots

vm.$scopedSlots也是一个对象,里面存放一个个函数,这些函数的返回值是包含父组件传来的所有插槽数组(包含默认、具名、作用域插槽)

typescript
{ 
    [name: string]: props => Array<VNode> | undefined
}
vue
<template>
  <Child>
    <span slot="aaa">456</span>
    <span slot="aaa">456</span>

    <span slot="bbb">456</span>
    <span slot="ccc">789</span>

    <span slot="ddd" slot-scope="data">{{ data }}</span>

    <span>789</span>
    <span>789</span>
  </Child>
</template>
vue
<script>
    export default {
        mounted() {
            console.log(this.$scopedSlots);
        },
    };
</script>

打印结果如下

image-20250507102530830

可以看到,this.$scopedSlots接收了父组件传来的所有插槽

我们获取下这些函数的返回值

vue
<script>
    export default {
        mounted() {
            const obj = {};
            for (let key in this.$scopedSlots) {
                const Vnode = this.$scopedSlots[key]();
                obj[key] = Vnode;
            }
            console.log(obj)
        },
    };
</script>

image-20250507102744962

不同点

vm.$slotsvm.$scopedSlots都可以获取父组件传递来的插槽,不同的是获取的是数据格式和插槽种类

数据格式:

  • vm.$slots里面是包含所有插槽的数组
  • vm.$scopedSlots里面是返回值为插槽的函数

插槽种类:

  • vm.$slots只可以获取默认、具名插槽
  • vm.$scopedSlots可以获取所有插槽

a-table的骚操作

效果描述

正常使用作用域插槽时,slot标签上的数据都会被放进一个对象

vue
<template>
  <div>
    <slot name="scoped" :num="666" idoName="ikun"></slot>
  </div>
</template>
vue
<Child>
    <span slot="scoped" slot-scope="data">{{ data }}</span>
    <!-- { "num": 666, "idoName": "ikun" } -->
</Child>

也可以使用解构

vue
<Child>
    <span slot="scoped" slot-scope="{num,idoName}">{{ num }},{{idoName}}</span>
</Child>

但是在a-table的插槽中,却可以这样使用

vue
<a-table>
    <span solt="solotName" solt-scope="value,record,index"></span>
</a-table>

可以看到solt-scope="value,record,index"没有结构确可以获取三个数据

原理解析

原理则是a-table的组件源码并不是vue文件,而是使用的渲染函数

js
export default {
    name: "Child",
    data() {
        return {
            value: 666,
            record: {
                name: "ikun",
            },
            index: 0,
        };
    },
    mounted() {},
    methods: {},
    render: function (h) {
        const slotsNodes = [];
        for (let key in this.$scopedSlots) {
            const Vnode = this.$scopedSlots[key](this.value, this.record, this.index);
            slotsNodes.push(Vnode);
        }
        return h("div", [...slotsNodes]);
    },
};
vue
<Child>
    <span slot="scoped" slot-scope="value, record, index">
        {{ value }},{{ record }},{{ index }}
    </span>
</Child>

效果如下

image-20250507110610465

MIT Licensed