Again, official documents are the standard

Vue3 render function location

H () function parameters: official website

h(
  // {String | Object | Function} tag
  // An HTML tag name, a component, an asynchronous component, or a functional component
  / / required
  'div'.// {Object} props
  // Objects corresponding to attributes, prop, and events. This is used in templates.
  // Optional.{} | |null.// {String | Array | Object} children
  // Subvnodes, built using 'h()',
  // Or use a string to get a "text VNode" or a slotted object.
  // Optional.
  [
    'Some text comes first.',
    h('h1'.'A headline')])Copy the code
  1. What does the third argument to h represent when passed in different types
    • The first one we pass in is a string, which means there’s no other element in this element, you can set the text, and the text will be displayed in this element
    • The second one is passed to Array, which means that inside the current element, there may be multiple elements separated by commas, and the Array can have multiple h functions, if it has the next level
    • The third passed Object means that you can set slots, named slots, and default slots

Use of v-if and V-for in rendering functions

  1. As the rendering function can not use the instructions in VUE, as long as the operation can be easily completed in native JavaScript, vue rendering function will not provide a proprietary alternative method, you can use if, ternary expression to complete the operation of the instruction V-if, using map to complete the operation of the V-for instruction

V-if or if/if else/ternary expression

v-for or map

  1. Normal loop array, using native JS map method instead of V-for, loop data, when using components, normal import components can be used
import { h, defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'contentlist'.setup() {
    const arr = ref([
      { id: 0.name: 'HTML' },
      { id: 1.name: 'CSS3' },
      { id: 2.name: 'javaScript'}])return () = > {
      return h('ul'.null, [
        arr.value.map(item= > {
          return h('li', { key: item.id }, item.name)
        })
      ])
    }
  }
})
Copy the code
  1. Another way to use loops is that sometimes you might want to implement nested components, that is, components that are like recursive components, or components that want to show a hierarchy, can be implemented by rendering functions
/ / the parent component<template>
  <menuChild size="4">
    <h1>hello</h1>
    <menuChild size="4">
      <h2>hello</h2>
    </menuChild>
    <menuChild size="4">
      <h3>hello</h3>
      <h4>hello</h4>
      <menuChild size="4">
        <h5>hello</h5>
        <h6>hello</h6>
      </menuChild>
    </menuChild>
  </menuChild>
</template>
<script setup>
import menuChild from './menusub.js'
</script>
<style  lang="scss" scoped>
</style>
Copy the code
/ / child component
import { h, defineComponent, provide, ref } from 'vue'
import './menusub.css'
export default defineComponent({

  name: 'menuChild'.setup(props, { slots, attrs }) {
    const slot = slots.default ? slots.default?.() : []
    return () = > {
      return h(
        'div'.null,
        [
          slot.map(item= > {
            return h('div', { class: `mt-${attrs.size}` }, item)
          })
        ]
      )
    }
  }
})
Copy the code

Events inside the render function (V-ON)

  1. Rendering functions do not use instructions, so when handling events in rendering functions, you need to name @ with a big hump starting with on
import { h, defineComponent } from 'vue'
export default defineComponent({
  name: 'about'.setup() {
    const listclick = () = > {
      console.log('I'm triggered.');
    }
    return () = > {
      return h('button', {onClick: listclick
      },'Click the button')}}})Copy the code
  1. If you need to fetch the current list data while loop rendering data, then process it
import { h, defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'contentlist'.setup() {
    const arr = ref([
      { id: 0.name: 'HTML' },
      { id: 1.name: 'CSS3' },
      { id: 2.name: 'javaScript'}])const childList = (item) = > {
      console.log(item);
    }
    return () = > {
      return h('ul'.null, [
        arr.value.map(item= > {
          return h('li', {
            key: item.id,
            onClick: () = > childList(item)
          }, item.name)
        })
      ])
    }
  }
})
Copy the code
  1. How do I get event objects? There are two ways to get event objects
    • By default, the event is clicked, no parameters are passed, and the event object is received by default when the event is registered
       import { h, defineComponent, ref } from 'vue'
        export default defineComponent({
          name: 'contentlist'.setup() {
            const arr = ref([
              { id: 0.name: 'HTML' },
              { id: 1.name: 'CSS3' },
              { id: 2.name: 'javaScript'}])const childList = (e) = > {
              console.log(e);
            }
            return () = > {
              return h('ul'.null, [
                arr.value.map(item= > {
                  return h('li', {
                    key: item.id,
                    onClick: childList
                  }, item.name)
                })
              ])
            }
          }
        })
    Copy the code
    • In the second example, when writing the render function, you may need to get the event object as well as the current row data. When registering the event, you need to pass the event object along with the current row data through the arrow function
    import { h, defineComponent, ref } from 'vue'
    export default defineComponent({
      name: 'contentlist'.setup() {
        const arr = ref([
          { id: 0.name: 'HTML' },
          { id: 1.name: 'CSS3' },
          { id: 2.name: 'javaScript'}])const childList = (e, item) = > {
          console.log(e, item);
        }
        return () = > {
          return h('ul'.null, [
            arr.value.map(item= > {
              return h('li', {
                key: item.id,
                onClick: $event => childList($event, item)
              }, item.name)
            })
          ])
        }
      }
    })
    Copy the code

Data transfer between components

slot

In vue3, slots.default is always a function that needs to be used as a call

Default receiving slot

/ / the parent component<template>
  <div>
    <slotscontent>
      <template #default>
        <h1>Slot data</h1>
      </template>
    </slotscontent>
  </div>
</template>
<script setup>
import slotscontent from './slotscontent'
</script>
Copy the code
// Render function component
import { h, defineComponent, provide, ref } from 'vue'
export default defineComponent({
  name: 'slotscontent'.setup(props, { slots }) {
    return () = > {
      return h('div'.null, [slots.default?.()])
    }
  }
})
Copy the code

A named slot

The parent component sets the #title component, and when the child component receives the slot content, it needs to get the element passed by the parent through slot.title ()

<template>
  <div>
    <slotscontent>
      <template #title>
        <h1>A named slot</h1>
      </template>
    </slotscontent>
  </div>
</template>

<script setup>
import slotscontent from './slotscontent'
</script>
Copy the code
import { h, defineComponent, provide, ref } from 'vue'

export default defineComponent({
  name: 'slotscontent'.setup(props, { slots }) {
    return () = > {
      return h('div'.null, [slots.title?.()])
    }
  }
})
Copy the code

Also set the slot for the render function component

As rendering function component, it is important to note if the child components through the slots. The default () to receive the content, if the parent component calls are subcomponents when the incoming string | | array, the console will be a warning.

Non-function value encountered for default slot. Prefer function slots for better performance. Default slots encounter non-functional values. Prefer feature slots for better performance.

To avoid unnecessary warnings about the way objects are selected, pass the slot content

// The first layer render function component
import { h, defineComponent } from 'vue'
import slotschild from './slotschild'
export default defineComponent({
  name: 'slotscontent'.setup(props, { slots }) {
    return () = > {
      return h('div'.null, [
        slots.title?.(),
        h(slotschild, null,
          {
            default: () = > h('h4'.null.'Same render function component')})])}}})Copy the code

If you have a lot of named slots, you can define them with different names, like default above, and then pass slots. To get the corresponding component content

// Layer 2 render function component
import { h, defineComponent} from 'vue'
export default defineComponent({
  name: 'slotschild'.setup(props, { slots }) {
    return () = > {
      return h('h2'.null, [slots.default?.()])
    }
  }
})
Copy the code

The father the son

/ / the parent component<template>
  <div>
    <slotscontent :title="title">
      <template #title>
        <h1>A named slot</h1>
      </template>
    </slotscontent>
  </div>
</template>

<script setup>
import slotscontent from './slotscontent'
import { ref } from 'vue'

const title = ref('Data passed by parent component')

</script>
Copy the code
import { h, defineComponent } from 'vue'
import slotschild from './slotschild'

export default defineComponent({
  name: 'slotscontent'.props: {
    title: {
      type: String}},setup(props, { slots }) {
    console.log(props)
    return () = > {
      return h('div'.null, [
        slots.title?.(),
        props.title
      ])
    }
  }
})
Copy the code

Passes to the parent of the render function component

/ / the parent component
import { h, defineComponent, ref } from 'vue'
import slotschild from './slotschild'

export default defineComponent({
  name: 'slotscontent'.setup(props, { slots }) {

    const title = ref('Parameter passing for both render function components')

    return () = > {
      return h('div'.null, [
        slots.title?.(),
        h(slotschild, // The child component can be used directly in the first argument of the h function
          {
            title: title.value // Pass data to child components
          },
          {
            default: () = > h('h4'.null.'Same render function component')})])}}})Copy the code
/ / child component
import { h, defineComponent } from 'vue'
export default defineComponent({
  name: 'slotschild'.props: { // The subcomponent uses props to receive data
    title: {
      type: String}},setup(props, { slots }) {
    console.log(props)
    return () = > {                   // Use the data passed by the parent component
      return h('h2'.null.'Subcomponents receive:${props.title}`)}}})Copy the code

Child parent emit

/ / child component
import { h, defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'slotscontent'.emits: ['childchange'].// The child sends custom events
  setup(props, { slots, emit }) {
    // Pass parameters to the parent component as custom events
    const txt = ref('Custom Event Passing Parameters') 
    return () = > {
      return h('div'.null, [
        slots.title?.(),
        h('button', {
          // Note that the arrow function is used,
          // If not, it doesn't work and is called directly
          onClick: () = > emit('childchange', txt.value)
        }, 'Button trigger event')}}})Copy the code
<template>
  <div>
    <slotscontent  @childchange="childchange"></slotscontent>
  </div>
</template>

<script setup>
import slotscontent from './slotscontent'
import { ref } from 'vue'
const childchange = (value) = > { // Receive data from the child component
  console.log(value);
}
</script>
Copy the code

Emit to render function component

/ / child component
import { h, defineComponent } from 'vue'

export default defineComponent({
  name: 'slotschild'.emits: ['carryparameter'.'nocarryparameter'].setup(props, { slots, emit }) {
    return () = > {
      return [
        h('button', {
          // Pass parameters
          onClick: () = > emit('carryparameter'.1)},'Carry parameters'),
        h('button', {
          // No arguments are passed
          onClick: () = > emit('nocarryparameter'),},'No parameters')]}}})Copy the code
import { h, defineComponent, ref } from 'vue'
import slotschild from './slotschild'

export default defineComponent({
  name: 'slotscontent'.setup(props, { slots, emit }) {
    const nums = ref(0)
    const carryparameter = (value) = > { // Carry parameters
      nums.value = nums.value += value
    }
    const nocarryparameter = () = > { // Does not carry parameters
      console.log('No parameters');
    }

    return () = > {
      return h('div'.null, [
        slots.title?.(),
        h(slotschild, {
          // Does not carry any parameter receiving mode
          onNocarryparameter: nocarryparameter,
          // Carry parameters
          onCarryparameter: (value) = > carryparameter(value)
        }),
        h('h1'.null, nums.value)
      ])
    }
  }
})
Copy the code

Slot of the props

  1. If you know enough about slots, you can set attributes to slots as you go along, and by setting attributes to slots, you can pass data to the parent component, in the case of templates
/ / the parent component<menu> <! -- Subcomponent -->
    <template #item={ id} >| | # item = "slotProps" to receive all of them<p>{{ id }}</p> || <p>{{ slotProps.id }}</p>
    </template>
</menu>/ / child component<template>
    <slot name="item" :id="id"></slot>
</template>
<script setup>
    import { ref } from 'vue'
    const id = ref(0)
</script>
Copy the code
  1. Switch to a rendering function once

/ / the parent component<template>
  <div>
    <articleContent :list="list">
      <template #bts="{ id }">
        <button @click="removeList(id)">Delete {{id}}</button>
      </template>
    </articleContent>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import articleContent from './article'
const list = ref([
  { id: 0.name: 'First data' },
  { id: 1.name: 'Second data' },
  { id: 2.name: 'Third piece of data' },
  { id: 3.name: 'Article 4 Data'}])const removeList = (id) = > {
  const idx = list.value.findIndex(item= > item.id == id);
  list.value.splice(idx, 1);
}
</script>

<style  scoped>
</style>
Copy the code
  • When a child component passes data to its parent by slot, you need to do this in the render function slot.bts? .({id: child.id}), passing the argument to the parent component
  • Vue2 uses $slots to get this value. Vue3 uses slotProps to get all the data that the child component passes to the parent component through slots. We recommend using deconstruction to get the desired value
/ / child component
import { h, defineComponent, ref } from 'vue'

export default defineComponent({
  props: {
    list: {
      type: Array}},name: 'articleContent'.setup(props, { slots }) {

    return () = > {
      return h('ul'.null, [
        props.list.map(child= > {
          return h('li', { key: child.id }, [
            child.name,
            slots.bts?.({ id: child.id })
          ])
        })
      ])
    }
  }
})
Copy the code

Props (Slot) of the render function component

/ / child component
import { h, defineComponent, ref } from 'vue'
export default defineComponent({
  name: 'child'.setup(props, { slots, attrs }) {
    const str = ref('Data passed by child components')

    return () = > {
      return h('div'.null, [
        slots.default?.({ str: str.value })
      ])
    }
  }
})
Copy the code

Props stores all the data that the child component passes to the parent component through slot. This name is not fixed, it can be slotProps, or it can be structured to get the desired value

/ / the parent component
import { h, defineComponent } from 'vue'
import child from './child'

export default defineComponent({

  name: 'father'.setup() {
    return () = > {
      return h(child, null, {
        default: (props) = > h('h1'.null, props.str)
      })
    }
  }
})
Copy the code

Attrs contains attribute bindings and events that do not function as component props or custom events in the parent scope. When a component does not declare any prop, it contains all parent-scoped bindings and can pass in the internal component with V-bind =”$attrs” — useful when creating higher-order components

/ / child component
import { h, defineComponent, ref } from 'vue'
export default defineComponent({
  name: 'child'.props: {
    size: {
      type: Number}},setup(props, { slots, attrs }) {
    const str = ref('Data passed by child components')

    return () = > {
      return h('div'.null, [
        slots.default?.({ str: str.value }),
        // The child uses attrs to get the value passed by the parent
        h('span', { class: attrs.class }, 'hello')}}})Copy the code
/ / the parent component
import { h, defineComponent } from 'vue'
import child from './child'

export default defineComponent({

  name: 'father'.setup() {
    return () = > {
      return h(child, { size: 4.class: 'item' }, {
        default: (slotProps) = > h('h1'.null, slotProps.str)
      })
    }
  }
})
Copy the code

Custom instruction, to learn…

Built-in components to learn…

JSX, to learn..