demand

Last time encountered a requirement that dynamic form configuration load another dynamic form configuration component, using jSON2Render has been able to achieve this function, specific implementation [dynamic interface json2Render] dynamic interface load custom template components

The children component can be placed in the corresponding slot. The children component can be placed in the corresponding slot when the children component is referenced. The children component can be placed in the corresponding slot when the children component is referenced. Implementations provide just a few simple layout components with styles to create multiple styles of components

This feature was not supported in the last version of Json2Render and has since been added

The effect

Take a look at the final result. This example is based on Vue3

The configuration of dynamic components is defined as follows

{
  "fields": [{"component": "h1"."props": {
        "style": { "fontSize": "40pt"}},"children": [{"component": "span"."text": "Title:" },
        // Has a named slot
        { "component": "slot"."name": "header"}]}, {"component": "p"."text": "The body" },
    // Default slot, and pass props to scope for children
    { "component": "slot"."props": { "attrValue": "aaaaa"}}}]Copy the code

References dynamic components and displays content in internal slots

{
  "datasource": {
    // Data source used to load dynamic components remotely, automatically
    "template": {
      "type": "fetch"."url": "/data/components/slotcmp.json"."auto": true."props": { "method": "GET"."params": {}},"defaultData": false}},"fields": [{"component": "div"."children": [{"component": "v-jrender"."condition": "$:template.data"."props": "$:template.data".// V-jrender did not support children, now supports children
          "children": {
            / / the default slot
            "default": [
              // Use the transform expression to obtain the attrValue attribute in the scope passed by the parent
              { "component": "span"."text": "#:inner text ${scope.attrValue}"}]./ / named slot
            "header": [{ "component": "span"."text": "Title slot content"}]}}]}Copy the code

The final effect is as follows

If you use the V-JRender component directly, you can add content to the children of v-jRender directly if the configuration contains a component that is slot

<script setup> import { ref } from 'vue' const fields = ref([{ component: 'div', children: [{ component: 'slot' }] }]) </script> <template> <v-jrender :fields="fields"> <! <div>content</div> </v-jrender> <template>Copy the code

The principle of

Concept of slot

Vue has a slot feature. When defining a component, you can add a slot in a location. When using the component, the children node of the component will render to the location of the defined slot

<button type="submit">
  <slot></slot>
</button>
Copy the code

Slots can also be named, allowing the children node to be rendered to a location with a specific name

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
Copy the code

The vue3 runtime instance has a Slots object. Its members are a collection of methods named after the slots in the component. Each of these methods returns a VNode array of children defined in the corresponding slot

// The current object slots member
const ctx = {
  slots: {
    default(scope) {
      / / return vnodes
    },
    header(scope) {
      / / return vnodes
    },
    footer(scope) {
      / / return vnodes}}}Copy the code

Json2render vUe-based render extension

Json2render based vue3 implementation provides hook extension operation in each node setup link, this operation can realize the pre-processing of the node before rendering, change the node attributes according to the conditions, this process will only be performed in the first initialization process of the node, Does not affect the performance of the interface when responding to data changes

A hook is defined as follows

() = >(field, next) = > {
  // Field is the definition of the current node
  // We can preprocess the field property and change the property
  next(field)
}
Copy the code

If you want to support slot, you need to implement a hook. The process is that the parent node performs the hook through all the children. When the component value of the child is slot, the child is identified as the slot node, and the slot node is used to display the contents of the slot. Use the name attribute of Child (default) to find the name method in slots and execute it. Replace the children element with the returned vNode set. The children element can be rendered in the slot location during rendering

about

There are a lot of things involved in the implementation of Json2Render. In the latest version, the main thing is to add dependency injection mechanism, so that it can reasonably extend the new function and share the children slots defined by all the children nodes. Specific reference project jSON2Render, net slow access to domestic mirror