欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入了解 vue 中的四种槽:槽--通过槽名映射到 VNode 数组的对象

最编程 2024-07-14 12:25:33
...

一、前言

相信很多的小伙伴在日常开发当中经常使用vue的插槽,通过官方的文档
[插槽](https://v2.cn.vuejs.org/v2/guide/components-slots.html)
我们能够很轻松的学会如何在项目中使用插槽。那么你有没有深入了解在插槽中
使用的vm.$slots具体是什么呢?

二、四种插槽

  • 四种插槽分别是什么

    1. 匿名插槽
    2. 具名插槽
    3. 动态插槽vue3.x ---->为什么强调是vue3.x?请往下看
    4. 作用域插槽
  • 如何使用插槽

1. 匿名插槽
概念:没有具名的插槽,也称为匿名插槽。它可以在组件模板中作为组件内容的占位符

    // 父组件
    <div class="father-component">
        <childTemp>
          <p class="default">这是匿名插槽的内容</p>
        </childTemp>
  </div>
  // 子组件
  <div class="child-component">
    <!-- 这是匿名插槽的内容 -->
    <slot></slot>
  </div>

image.png

2. 具名插槽

概念:具名插槽是指有一个名称(或者多个名称)的插槽,它们可以在组件模板中通过名称引用

// 父组件
<div class="father-component">
    <childTemp>
      <template #header>
        <p>header: 这是具名插槽的内容</p>
      </template>
      <template #body>
        <p>body: 这是具名插槽的内容</p>
      </template>
      <template #footer>
        <p>footer: 这是具名插槽的内容</p>
      </template>
    </childTemp>
</div>
// 子组件
<div class="child-component">
    <slot name="header"></slot>
    <slot name="body"></slot>
    <slot name="footer"></slot>
</div>

image.png3. 动态插槽

概念:动态插槽是 Vue 中的一种特殊类型的插槽,它允许使用者根据具体的业务场景来动态地创建插槽内容

在 Vue 2.x 中,如果我们想要动态地创建插槽内容,通常是使用函数式组件来实现。但是,函数式组件的写法比较麻烦,并且不能像普通组件那样维护自己的状态和生命周期钩子。Vue 3.x 引入了动态插槽的概念,通过使用 v-slot 指令

//父组件
<div class="father-component">
    <childTemp>
      <!-- 动态插槽 -->
      <template #[dynamicSlot]>
	<p>{{ dynamicSlot }}:这是动态插槽的内容</p>
      </template>
    </childTemp>
 </div>
 
setup() {
    const dynamicSlot = ref("dynamicSlot");
    return {
	dynamicSlot
    };
}
// 子组件
<script>
import { createElementVNode } from "vue";
export default {
	name: "",
	setup(props, { slots }) {
		const slotName = slots.dynamicSlot();
                // 其实这里就呼应了标题-- 插槽本身就是映射到 VNode 数组的对象
		return () => {
			return createElementVNode("div", null, [...slotName]);
		};
	}
};
</script>

image.png

4. 作用域插槽

概念:动态插槽是 Vue 中的一种特殊类型的插槽,它允许子组件将自身的数据传递到父组件中进行渲染,通常用于构建通用的 UI 组件。作用域插槽在定义时需要使用 v-slot 指令,并接受一个参数表示插槽名称.

//父组件
<div class="father-component">
    <childTemp>
        <!-- 作用域插槽 -->
        <template #default="props">
           <p>{{ props.actionScope }}</p>
        </template>
    </childTemp>
 </div>
// 子组件
<div class="child-component">
    <!-- 作用域插槽 -->
    <slot :actionScope="actionScope"></slot>
</div>

export default {
    setup() {
        const actionScope = ref("actionScope:这是作用域插槽的内容");
        return {
            actionScope
        };
    }
};

image.png

三、$slots具体是什么 image.png

Vue 插槽是一个对象。在组件实例的 vm.$slots 属性中,每个插槽都表示为一个包含 VNode 的数组,因此 vm.$slots 对象本身就是一个由插槽名映射到 VNode 数组的对象

举例说明

// 父组件
<div class="father-component">
	<childTemp :dynamicSlot="dynamicSlot">
		<!-- 匿名插槽 -->
		<p class="default">这是默认插槽的内容</p>
		<!-- 具名插槽 -->
		<template #header>
                    <p>header: 这是具名插槽的内容</p>
                </template>
		<template #body>
			<p>body: 这是具名插槽的内容</p>
		</template>
		<template #footer>
			<p>footer: 这是具名插槽的内容</p>
		</template>
	</childTemp>
</div>

接下来我们在子组件中打应这个slots

export default {
	name: "",
	setup(props, { slots }) {
		console.log("slots", slots);
	}
};

image.png打印slots出来全是父组件定义插槽生成的VNode,那么我们在子组件是不是能直接拿到VNode渲染呢?答案是肯定可以的!!!我们不妨来试一下

<template>
	<div class="child-component">
		<!-- 		<slot></slot>
		<slot name="header"></slot>
		<slot name="body"></slot>
		<slot name="footer"></slot> -->
	</div>
</template>

<script>
import { createElementVNode } from "vue";
export default {
	name: "",
	setup(props, { slots }) {
		console.log("slots", slots);
		const _default = slots.default();
		const _header = slots.header();
		const _body = slots.body();
		const _footer = slots.footer();
		return () => {
			return createElementVNode("div", null, [..._default, ..._header, ..._body, ..._footer]);
		};
	}
};
</script>

image.png 看到这里相信你不但会使用插槽,还对插槽有更加深入的了解。

image.png