yaquawa
yaquawa

Reputation: 7338

How to render multiple slots in Vue3?

How can I render the following template in Vue3 setup() function using the h() function?

<label v-for="service in services" :key="service">
  <slot name="before" :service="service"></slot>
    foobar
  <slot name="after" :service="service"></slot>
</label>

Upvotes: 2

Views: 5670

Answers (1)

tony19
tony19

Reputation: 138226

The h() arguments are:

// @returns {VNode}
h(
  // {String | Object | Function } tag
  // An HTML tag name, a component or an async component.
  // Using function returning null would render a comment.
  //
  // Required.
  'div',

  // {Object} props
  // An object corresponding to the attributes, props and events
  // we would use in a template.
  //
  // Optional.
  {},

  // {String | Array | Object} children
  // Children VNodes, built using `h()`,
  // or using strings to get 'text VNodes' or
  // an object with slots.
  //
  // Optional.
  [
    'Some text comes first.',
    h('h1', 'A headline'),
    h(MyComponent, {
      someProp: 'foobar'
    })
  ]
)

The component's setup() arguments are below. setup() can also return a render function (a function that returns a VNode from h()):

setup(
  // {Object} Component prop values
  props,

  // {Object} Contains `attrs`, `emit`, and `slots`
  context
)

The context's slots property contains functions for each given slot. These functions receive arguments that are passed to the slot as props, and each function returns the corresponding slot's VNode. For example, to get the before slot's VNode and pass a slot prop of service, call context.slots.before({ service: 'myService' }).

So the equivalent render function of your template would look similar to the following:

import { h } from 'vue'

export default {
  props: {
    services: {
      type: Array,
      default: () => [],
    },
  },
  setup({ services }, { slots }) {
    return () =>
      services.map((service) =>
        h(                             //
          'label',                     //
          {                            // <label :key="service">
            key: service,              //
          },                           //
          [
            slots.before({ service }), //   <slot name="before" :service="service" />
            'foobar',                  //   foobar
            slots.after({ service })   //   <slot name="after" :service="service" />
          ]
        )                              // </label>
      )
  },
}

demo

Upvotes: 6

Related Questions