Post

Vue Slots Through a Function Lens

Reinterpreting Vue's default, named, and scoped slots as function calls to build a clearer mental model.

用另一种方式来理解 slot 的本质——把它当成函数调用。

子组件(comp)有这样的格式:

1
2
3
4
5
6
7
8
9
//comp.vue

<template>
  <div>
    <slot></slot>
    <slot name="slot1"></slot>
    <slot name="slot2" msg="hello"></slot>
  </div>
</template>

在父组件使用的时候,按照对应的标识,传入标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
//index.vue

<Comp>
      <p>默认插槽</p>

      <template #slot1>
        <p>具名插槽</p>
      </template>

      <template #slot2="{ msg }">
        <p>作用域插槽:</p>
      </template>
    </Comp>

在父组件使用 comp 时,相当于传递了一个对象,三个属性,值均为函数:

1
2
3
4
5
{
    default: function(){},
    slot1: function(){},
    slot2: function(){}
  }

comp 内部调用对应的方法——<slot></slot> 等价于调 props.default()。说着说着感觉有点 React 的味道了。

用 JS 来实现 comp 组件:

1
2
3
4
5
6
7
8
9
10
//comp.js

import { createElementVNode } from "vue";
export default {
  setup() {
    return () => {
      return createElementVNode("div", null, []); // 创建虚拟节点
    };
  },
};

拿到参数,

1
2
3
4
5
6
7
8
9
export default {
  setup(props, ctx) {
    //两个参数 第二个参数包含了一些其他信息
    console.log("ctx", ctx);
    return () => {
      return createElementVNode("div", null, []); // 创建虚拟节点
    };
  },
};

执行对应的方法,

1
2
3
4
5
6
7
8
export default {
  setup(props, { slots }) {
    const defaultVNode = slots.default(); // 调用默认方法
    return () => {
      return createElementVNode("div", null, [...defaultVNode]);
    };
  },
};

因此,原先的 comp.vue 可以写成 comp.js,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//comp.js

import { createElementVNode } from "vue";
export default {
  setup(props, { slots }) {
    const defaultVnode = slots.default();
    const slot1Vnode = slots.slot1();
    const slot2Vnode = slots.slot2({
      msg: "hello",
    });
    return () => {
      return createElementVNode("div", null, [
        ...defaultVnode,
        ...slot1Vnode,
        ...slot2Vnode,
      ]);
    };
  },
};
This post is licensed under CC BY 4.0 by the author.