likes
comments
collection
share

面试官:vue插槽有什么用?插槽的本质是什么?先有问题再有答案 插槽的设计目的是什么? 插槽如何使用? 我们能用插槽做什

作者站长头像
站长
· 阅读数 140

先有问题再有答案

  1. 插槽的设计目的是什么?
  2. 插槽如何使用?
  3. 我们能用插槽做什么?
  4. 如何理解默认插槽 具名插槽 作用域插槽?
  5. 插槽的本质是什么?
  6. 为什么插槽不能访问子组件的作用域?

设计目的

插槽 (slot) 特性的设计主要是为了实现组件内容的可重用和内容分发。这是一种让父组件可以向子组件动态插入内容的特性。

我们可以将任意内容放在组件的标签中,然后在组件的模板中使用 <slot> 标签来决定这些内容的位置。当一个组件渲染的时候, <slot> 将会被替换为它之间的内容。

Vue 插槽的设计可以解决以下需求:

  1. 内容分发 (Content Projection):插槽可以让开发者在使用一个组件的时候,向组件内部动态传入任意的 DOM 结构。这在开发类似于 Dialog、Card 这样的容器类型组件的时候非常有用。

  2. 作用域插槽 (Scoped Slot):通过作用域插槽,父组件可以获取到子组件内部的数据,达到更复杂的定制和控制

使用方式

插槽的使用可以分为两部分 首先声明一个插槽 然后传入一个具体的内容替代声明的插槽。

这里使用插槽 实现一个MultColumnList多列列表组件

效果demo

面试官:vue插槽有什么用?插槽的本质是什么?先有问题再有答案 插槽的设计目的是什么? 插槽如何使用? 我们能用插槽做什

源码

MultColumnList.vue组件

<template>
    <div class="list">
        <div v-for="(item, index) of props.list" :key="index" :style="itemStyle" class="itemClass">
            <slot name="item" :item="item"></slot> // 使用slot标签声明插槽占位
        </div>
        <div v-for="index of fillList" :key="index" :style="itemStyle" class="itemClass"></div>
    </div>
</template>

demo.vue

<template>
  <List :list="list" :column="4">
    <template #item="{ item }">  // 替换插槽内容
      <div class="item">{{ item.name }}</div>
    </template>
  </List>
</template>

组件完整源码 vue3-mult-column-list

本质 :插槽的本质就是函数

这里使用下面的例子做具体说明。

面试官:vue插槽有什么用?插槽的本质是什么?先有问题再有答案 插槽的设计目的是什么? 插槽如何使用? 我们能用插槽做什 提供一个Layout组件 可以将页面分为三部分。 header, content, footer。

从上图可以看出 Layout && Layout1 在效果上是等价的。

Layout1实现

<template>
<div class="container">
 <slot name="header"></slot>
 <slot></slot>
 <slot name="footer"></slot>
</div>
</template>

这是我们常规的实现组件的一种方式。

Layout实现

<script>
import { h } from 'vue'
export default {
    setup(props, 
    { slots }) {
        console.log('test slots ', slots)
        const header = slots.header();
        const content = slots.default();
        const footer = slots.footer();
        return () => {
            return h('div', null, [
                ...header,
                ...content,
                ...footer,
            ]);
        };
    },
};
</script>

代码解释:

h函数:h 函数是 Vue.js 中用于创建 VNode 的核心函数,简化了手写渲染函数的过程。它的基本签名为: h(type, propsOrChildren, children),

  • type 参数是一个字符串(一个 HTML 元素的标签名)、一个组件,或者是一个异步组件。
  • propsOrChildren 参数是一个对象,包含了传递给这个 VNode 的 props,或者是用于设置这个元素的 DOM 属性。如果没有 props,而直接传递了 children,那么这个参数可以是一个子元素或子元素的数组。
  • children 参数是 VNode 的子节点,可以是一个字符串(如果是文本节点)、一个 VNode,或者是一个 VNode 数组。

slots对象: slots 用于访问组件传入的内容插槽。 面试官:vue插槽有什么用?插槽的本质是什么?先有问题再有答案 插槽的设计目的是什么? 插槽如何使用? 我们能用插槽做什 这里打印了slots对象 可以看到slots是一个proxy对象 而且slots里面包含了传入的具体插槽属性 值为一个函数。

插槽属性

 const header = slots.header();
 const content = slots.default();
 const footer = slots.footer();

这几行代码使用函数调用的方式访问插槽。slots.header()、slots.default() 和 slots.footer() 分别调用了名为 header、默认 (default) 和 footer 的插槽。

面试官:vue插槽有什么用?插槽的本质是什么?先有问题再有答案 插槽的设计目的是什么? 插槽如何使用? 我们能用插槽做什

可以看到调用插槽函数后返回的具体内容是一个vnode节点数组,这些vnode是可以交个h函数,用于渲染出真实dom节点。

总结

所以插槽的本质就是函数 在回头来看下我们之前实现的列表组件 以函数的视角在带入分析下。

 <List :list="list" :column="4">
    <template #item="{ item }">  // #item 即为函数名  
      <div class="item">{{ item.name }}</div> // 函数的返回值
    </template>
  </List>

#item :插槽名字即为函数名 "{ item }": 所谓的作用域插槽 实际上是函数的参数。 插槽内部的div: 函数的返回值

可以看成如下代码:

 <List :list="list" :column="4">
   {{slots.item(({item})=>{
   return <div class="item">{{ item.name }}</div> })}}
  </List>

这也解释了为什么 插槽内容无法访问子组件中的数据了 因为插槽是在父组件调用的函数,所以只能访问父组件的作用域。

转载自:https://juejin.cn/post/7405152755818102835
评论
请登录