search

Home  >  Q&A  >  body text

Vue 3 trick to wrap all items in custom components using render functions

I'm trying to build my own sortable component. I want to pass a list of items to it's default slot. The sortable component should then wrap all passed items with a custom v-draggable component.

<v-sortable handle=".handle">
    <template :key="index" v-for="(item, index) in items">
        <some-complex-component :item="item"></some-complex-component>
    </template>
</v-sortable>

Now, using my v-sortable component, I'm trying to use a custom v-draggable component to wrap all given nodes in the default slots. My v-sortable component looks like this:

import { h } from 'vue';

export default {
    name: 'v-sortable',
    props: {
        handle: {
            type: String,
            required: false,
            default: () => {
                return null;
            }
        },
    },
    render () {
        const draggableItems = this.$slots.default().map(slotItem =>
            h('v-draggable', { handle: this.handle }, [slotItem])
        )
        return draggableItems;
    }
}

This works as expected, except that my custom component v-draggable does not render as a vue component. All items will be wrapped in html tags named . How do I proceed to actually resolve the v-draggable component into a Vue component?

P粉926174288P粉926174288382 days ago591

reply all(2)I'll reply

  • P粉147747637

    P粉1477476372023-12-28 20:53:19

    Components can be specified explicitly in the render function:

    h(VDraggable, ...)

    Globally registered components that cannot be imported (e.g. from third-party libraries) can be resolved via resolveComponent.

    reply
    0
  • P粉514458863

    P粉5144588632023-12-28 15:08:06

    Try to import and register directly and use:

    import { h } from 'vue';
    import VDraggable from 'path/to/v-draggable'
    export default {
        name: 'v-sortable',
        props: {
            handle: {
                type: String,
                required: false,
                default: () => {
                    return null;
                }
            },
        },
        render () {
            const draggableItems = this.$slots.default().map(slotItem =>
                h(VDraggable, { handle: this.handle }, [slotItem])
            )
            return draggableItems;
        }
    }
    

    It is recommended to pass items as props and use them directly in the render function:

    <v-sortable handle=".handle" :items="items">
    </v-sortable>
    

    Subassembly:

    import { h } from 'vue';
    import VDraggable from 'path/to/v-draggable'
    export default {
        name: 'v-sortable',
        props: {
            items:{
             type:Array,
             default: () =>[]
            },
            handle: {
                type: String,
                required: false,
                default: () => {
                    return null;
                }
            },
        },
        render () {
            const draggableItems = this.items.map(slotItem =>
                h(VDraggable, { handle: this.handle }, [item])
            )
            return draggableItems;
        }
    }
    

    reply
    0
  • Cancelreply