深入理解vue中的插槽(slot)

1. 插槽的本质

组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?插槽可以理解为模板提供内容,<slot> 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。

那么插槽到底是怎么实现替换,怎么运行的。

先看一个案例: 子组件通过setup中slots接收,使用createElementVNode进行渲染。

父组件:

vue 复制代码
<SlotDemo>
    <template v-slot:default="{ title }">
        {{ title }}
    </template>
</SlotDemo>

子组件:

vue 复制代码
import { createElementVNode } from 'vue';

export default {
    setup(props, {slots}) {
        const _default = slots.default()
        console.log('打印***_default', _default)
        return () => {
            return createElementVNode('div', {}, [_default])
        }
    }
}
</script>

子组件定义了默认插槽,父组件传入默认插槽的内容,子组件使用setup语法进行接收,可以看到slots本质是一个对象,对象的键就是插槽的名称,对象的值是一个函数,作用域插槽需要传递数据,就是这个函数的参数。

可以打印下slots:

运行这个函数,得到虚拟节点:

子组件可以通过createElementVnode进行渲染

这样就可以看出插槽的

2. 插槽的使用

2.1 默认插槽

子组件 使用默认或者写

js 复制代码
<slot name="default"></slot>
// 或者
<slot title="默认插槽"></slot>

父组件 三种写法

js 复制代码
// 直接写
默认插槽
// 或者
<template v-slot:default>
    默认插槽(v-slot:default)
</template>
// 或者
<template #default>
    默认插槽(v-slot:default)
</template>

2.2 具名插槽

默认插槽不满足使用需求,那么具名插槽可以解决,为每一个插槽添加名称,就可以进行区分。

子组件:

js 复制代码
<slot name="header"></slot>

父组件:

js 复制代码
<template #header>
    具名插槽
</template>
// 或者
<template v-slot:header>
    具名插槽
</template>

2.3 作用域插槽

如果子组件的内容需要通过插槽传递到外部父组件的插槽中,那么作用域插槽就可以解决问题。我们可以为插槽添加属性,注意name字段是不可以添加的,因为已经被定义为插槽的名称,多个属性会收集成一个对象,传递给父组件的模版中,父组件通过v-slot:xxx=obj接受,这里可以解构

子组件:

js 复制代码
<slot name="content" v-bind="{ a: 1, b: 2 }" />
// 或者
<slot name="content" :a="1" :b="2" />

父组件:

js 复制代码
 <template #content="obj">
    作用域插槽{{ obj.a }}
</template>
// 或者
<template v-slot:content="{ a, b }">
    作用域插槽{{ a }}
</template>

注意:插槽传递的内容,其他插槽是不可以使用的

2.4 动态插槽

我们常见的ui组件库element表格,操作栏可以我们自己定义插槽。使用的就是动态插槽。

如果插槽的名称需要外部自定义,那么动态插槽可以满足要求,动态插槽是用外部传入的名称,定义子组件插槽的名称。通过子组件定义:name="dynamicName" 父组件v-slot:[dynamicName]书写。

子组件:

js 复制代码
<slot :name="dynamicName" :a="1" :b="2"></slot>

父组件:

js 复制代码
<template v-slot:[dynamicName]="{ a, b }">
    动态插槽{{ a }}-{{ b }}
</template>

3. 总结

最后总结一下:插槽的实现就是对于子组件来说就是一个对象,键是插槽的名称,值是一个函数,用于渲染父组件传递的内容。

插槽的使用有几种:

  • 默认插槽:如果子组件没有具名插槽,那么父组件提供的内容将被插入到子组件的默认插槽中。
  • 具名插槽 :如果需要多个插槽及对应不同的内容,可以为插槽添加名称,并通过<template v-slot:xxx><slot name="xxx">进行传递。
  • 作用域插槽:允许子组件通过插槽向父组件传递数据。通过在插槽内部定义属性,并通过父组件提供的对象将数据传递给父组件来实现。
  • 动态插槽 :允许父组件动态地指定插槽的名称。子组件可以使用动态的名称来定义插槽,并在父组件中通过v-slot:[dynamicName]来指定插槽。

如有错误,请指正O^O!

相关推荐
diemeng11197 分钟前
AI前端开发技能变革时代:效率与创新的新范式
前端·人工智能
bin91532 小时前
DeepSeek 助力 Vue 开发:打造丝滑的复制到剪贴板(Copy to Clipboard)
前端·javascript·vue.js·ecmascript·deepseek
晴空万里藏片云4 小时前
elment Table多级表头固定列后,合计行错位显示问题解决
前端·javascript·vue.js
曦月合一4 小时前
html中iframe标签 隐藏滚动条
前端·html·iframe
奶球不是球4 小时前
el-button按钮的loading状态设置
前端·javascript
kidding7234 小时前
前端VUE3的面试题
前端·typescript·compositionapi·fragment·teleport·suspense
Σίσυφος19006 小时前
halcon 条形码、二维码识别、opencv识别
前端·数据库
学代码的小前端6 小时前
0基础学前端-----CSS DAY13
前端·css
css趣多多7 小时前
案例自定义tabBar
前端
姑苏洛言8 小时前
DeepSeek写微信转盘小程序需求文档,这不比产品经理强?
前端