# 插槽的本质

复习插槽的概念:

  • 子组件:通过 slot 来设置插槽
  • 父组件:使用子组件时可以往 slot 的位置插入模板内容

插槽使用层面的本质:父组件向子组件传递模板内容

  • 默认插槽:拥有默认的一些内容
  • 具名插槽:给你的插槽取一个名字
  • 作用域插槽:数据来自于子组件,通过插槽的形式传递给父组件使用

# 父组件传递内容的本质

传递的是一个对象:

{
  default: function(){ ... },
  xxx: function(){ ... },
  xxx: function(){ ... },
}
1
2
3
4
5

对于上面的例子来讲,父组件传递的就是这样的一个对象:

{
  default: function(){
    // 注意返回值是对应结构的虚拟 DOM
    return (
    	 <div class="card-content">
        <img src="./assets/landscape.jpeg" alt="Beautiful landscape" class="card-image" />
        <p>探索未知的自然风光,记录下每一个令人惊叹的瞬间。加入我们的旅程,一起见证世界的壮丽。</p>
      </div>
    )
  },
  header: function(){
    return (
    	<div>摄影作品</div>
    )
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

父组件向子组件传递过去的东西本质上是函数,通过调用这些函数,能够得到对应结构的虚拟 DOM.

# 子组件设置插槽的本质

其实就是对父组件传递过来的函数进行调用,得到对应的虚拟 DOM.

const slots = {
  default: function(){ ... },
  xxx: function(){ ... },
  xxx: function(){ ... },
}; // 该对象是父组件传递过来的对象
slots.default(); // 得到要渲染的虚拟DOM
slots.header(); // 得到要渲染的虚拟DOM
slots.xxx(); // 得到要渲染的虚拟DOM
1
2
3
4
5
6
7
8

进行验证

最后,我们需要对上面的说法进行验证。

import { defineComponent, h, ref } from "vue";
import styles from "./CardComponent.module.css";

export default defineComponent({
  name: "CardComponent",
  setup(_, { slots }) {
    const title = ref("这是子组件标题222");
    const deaultSlotsVNode = slots.default();
    let headerSlotsVnode = null;
    // 如果传递了header插槽,就调用header插槽
    if (slots.header) {
      headerSlotsVnode = slots.header({
        title: title.value,
      });
    }
    // 但是要注意,调用了之后,不见得有值,所以要判断一下
    if (!headerSlotsVnode.length) {
      headerSlotsVnode = h("div", null, "默认标题");
    }
    return () => h("div", { class: styles.card }, [h("div", { class: styles["card-header"] }, headerSlotsVnode), h("div", { class: styles["card-body"] }, deaultSlotsVNode)]);
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22