官网文档,对插槽做出相关的定义,例如 「默认插槽」、「具名插槽」和「作用域插槽」 。那现在我们用另一种方式来解析 插槽(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()
。
(PS: 说着说着感觉就有点 「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,
]);
};
},
};