Managing children from inside the Vue rendering function

I am trying to create a seemingly simple component in Vue.js - just a loading bar with an additional header, content and optional footer using the JS Rendering Function. The idea is for him to do something like this:

<panel>

  <panel-header> Header </panel-header>

     [ The panel content goes here ]

  <panel-footer> Footer </panel-footer>

</panel>

My question is: how can I include the "child components" (header bar and footer bar) with their specific classes (for example, the header bar class) in the rendering function, keep them optional as well, but allow complete freedom when linking a panel body with its own classes (i.e. panel-body and props.title class)?

In other words: how can I control the children, but the individual components, but I have [children] to fill the middle of the panel?

My sctipt rendering looks something like this:

import classNames from 'classnames';

export const props = {
tag: {
  type: String,
  default: "div"
},
className: {
  type: String
},
align: {
  type: String,
  default: 'left'
},
title: {
  type: String,
},
header: {
  type: String,
}
};

export default {
 functional: true,
 props,
 render(h, { props, data, children }) {
  const dataObj = {
    class: classNames(
      'card',
      props.align ? 'text-' + props.align : '',
      props.className ? props.className : ''
    ),
 };
 const title = [
  h('h4', {
    class: 'card-title'
  }, props.title)
];

 const content = [
   h('div', {
     class: 'card-body'
   })
 ];
return h(props.tag, dataObj, [title, children] );
}
};

Best regards, Paco Pachichi

EDIT: I know that as soon as I do this, as stated above, I will get the desired effect - having the title, content and footer in the panel, in the correct order. But what if I wanted to add some properties only to the contents of the panels, not including the footer and header? Thus, they will be considered children and, therefore, obey my manipulations. I would like to consider them as separately, but inside the same function.

+4
source share
1 answer

, , .

console.clear()

const PanelHeader = {
  template: `<div>Im a panel header</div>`
}

const PanelFooter = {
  template: `<div>Im a panel Footer</div>`
}

const Panel = {
  functional: true,
  render(h, context){
    // find the header if there is one. Note that if there is more than
    // one panel-header, only the first one will be used
    let header = context.children.find(c => c.componentOptions && c.componentOptions.tag === "panel-header")
    // same deal for the footer
    let footer = context.children.find(c => c.componentOptions && c.componentOptions.tag === "panel-footer")
    // filter out anything that isn't header/footer
    let body = context.children.filter(c => c !== header && c !== footer)
    
    // layout as desired.
    return h('div', [header, body, footer])
  }
}

new Vue({
  el: "#app",
  components: {Panel, PanelHeader, PanelFooter}
})
<script src="https://unpkg.com/vue@2.5.3"></script>
<div id="app">
  <panel>
    <panel-footer></panel-footer>
    some stuff
    <panel-header></panel-header>
  </panel>
  <hr>
  <panel>
    some stuff
  </panel>
  <hr>  
  <panel>
    <panel-footer></panel-footer>
    some stuff
  </panel>
</div>
Hide result

, . .

+1

Source: https://habr.com/ru/post/1689792/


All Articles