vue3 h函数中如何使用插槽

前言

vue3已经出了有一段时间了,越来越多的小伙伴开始用vue3来写项目。开发过程中难免会用到h函数, 有时候会使用h函数封装一些组件,封装组件又会用到插槽。所以呢对于在h函数中如何使用插槽稍作了整理,希望能帮到帮接触h函数的小伙伴。

这里只讲解插槽的用法,不涉及h函数如何使用,如需了解h函数用法,可查阅官网文档-渲染函数

什么是h函数

h()hyperscript 的简称——意思是“能生成 HTML (超文本标记语言) 的 JavaScript”。这个名字来源于许多虚拟 DOM 实现默认形成的约定。一个更准确的名称应该是 createVnode(),但当你需要多次使用渲染函数时,一个简短的名字会更省力。

使用插槽

插槽使用方式这里可分为两种,下面一一介绍。

第一种方式 (使用slots.xxxxx?.())
  • 默认插槽

    这里是一个子组件A.ts

    import { h, defineComponent } from 'vue'
    export default defineComponent({
        setup(_, { slots }) {
            return () => h('span', slots.default?.())
        }
    })
    
  • 具名插槽

    这里是一个子组件B.ts

    import { h, defineComponent } from 'vue'
    export default defineComponent({
        setup(_, { slots }) {
            return () => h('span', slots.foo?.())
        }
    })
    

    这个foo就是具名插槽的名字

  • 作用域插槽

    这里是一个子组件C.ts

    import { h, defineComponent } from 'vue'
    export default defineComponent({
        setup(_, { slots }) {
            return () => h('span', slots.footer?.({ msg: '这是一条来自作用域插槽(C组件)传递的数据', list: ['a', 'b', 'c', 'd'] }))
        }
    })
    

    { msg: '这是一条来自作用域插槽(C组件)传递的数据', list: ['a', 'b', 'c', 'd'] } 这个对象就是向外部传递的数据

  • 在父组件中使用

    这是父组件Content.ts

    import { h, defineComponent } from 'vue'
    import A from './A'
    import B from './B'
    import C from './C'
    export default defineComponent({
        setup() {
            return () => h('div', [
                h(A, () => h('div', '我是默认插槽')),
              	// 注意 `null` 是必需的
    						// 以避免 slot 对象被当成 prop 处理
                h(B, null, { foo: () => h('div', '我是具名插槽') }),
              	// 注意 `null` 是必需的
    						// 以避免 slot 对象被当成 prop 处理
                h(C, null, {
                    // 通过解构得到插槽作用域的参数
                    footer: ({ msg, list }: { msg: string, list: string[] }) => [
                        h('h2', '我是作用域插槽'),
                        h('div', `msg: ${msg}`),
                        h('div', `list: 接收到了作用域插槽(C组件的List)---> ${list}`),
                    ]
                }),
            ])
        }
    })
    

在这里插入图片描述

第二种方式 (使用renderSlot)
  • 默认插槽

    这里是一个子组件A.ts

    import { renderSlot, h, defineComponent } from 'vue'
    export default defineComponent({
        setup(_, { slots }) {
            return () => h('div', renderSlot(slots, 'default'))
        }
    })
    
  • 具名插槽

    这里是一个子组件B.ts

    import { renderSlot, h, defineComponent } from 'vue'
    export default defineComponent({
        setup(_, { slots }) {
            return () => h('div', renderSlot(slots, 'foo'))
        }
    })
    

    这个foo就是具名插槽的名字

  • 作用域插槽

    这里是一个子组件C.ts

    import { renderSlot, h, defineComponent } from 'vue'
    export default defineComponent({
        setup(_, { slots }) {
            return () => h('div', renderSlot(slots, 'footer', { msg: '这是一条来自作用域插槽(C组件)传递的数据', list: ['a', 'b', 'c', 'd'] }))
        }
    })
    

{ msg: '这是一条来自作用域插槽(C组件)传递的数据', list: ['a', 'b', 'c', 'd'] } 这个对象就是向外部传递的数据

  • 父组件中使用

    这是父组件Content.ts

    import { h, defineComponent } from 'vue'
    import A from './A'
    import B from './B'
    import C from './C'
    export default defineComponent({
        setup() {
            return () => h('div', [
                h(A, () => h('div', '我是默认插槽')),
                // 注意 `null` 是必需的
                // 以避免 slot 对象被当成 prop 处理
                h(B, null, { foo: () => h('div', '我是具名插槽') }),
                // 注意 `null` 是必需的
                // 以避免 slot 对象被当成 prop 处理
                h(C, null, {
                    // 通过解构得到插槽作用域的参数
                    footer: ({ msg, list }: { msg: string, list: string[] }) => [
                        h('h2', '我是作用域插槽'),
                        h('div', `msg: ${msg}`),
                        h('div', `list: 接收到了作用域插槽(C组件的List)---> ${list}`),
                    ]
                }),
            ])
        }
    })
    
    

    两种方式区别不大,就是一个使用renderSlot, 一个使用slots.xxxxx?.()的方式。

在这里插入图片描述

其他

如果想了解Tsx中如何使用插槽可参考Tsx中使用插槽

Logo

前往低代码交流专区

更多推荐