javascriptvue.jsrenderslotvue-functional-component

Scoped Slots & render() & h() function


This is a simplified situation. In reality, my code is more complex and larger. I am making a table component.

I am trying to pass data from a table to the column-component slot, which I pass through the data prop. I think I can do this through the Celll.vue functional component. But I am not sure that my reasoning is correct.

An example of what I want to get:

<table-component :data="dataTable">
    <column-component v-slot="slotProps">
      <span>Name:</span>
      <!-- GET DATA HERE -->
      <!-- <span>{{ slotProps }}</span> -->
    </column-component>

    <column-component v-slot="slotProps">
      <span>Age:</span>
      <!-- GET DATA HERE -->
      <!-- <span>{{ slotProps }}</span> -->
    </column-component>

    <column-component v-slot="slotProps">
      <!-- GET DATA HERE -->
      <span>City:</span>
      <!-- <span>{{ slotProps }}</span> -->
    </column-component>
  </table-component>

...

data() {
    return {
      dataTable: [
        { name: "Alex", age: "20", city: "Msk" },
        { name: "Bob", age: "22", city: "Paris" },
        { name: "Dilan", age: "21", city: "London" },
      ],
    };
  },

codesandbox: LIVE EXAMPLE

TableComponent.vue

<template>
  <table>
    <tr v-for="(row, rowIndex) in data" :key="rowIndex">
      <Celll
        v-for="(col, colIndex) in columns"
        :key="colIndex"
        :vnodes="col"
        :row="data"
      />
    </tr>
  </table>
</template>

<script>
import Celll from "./Celll.vue";

export default {
  components: {
    Celll,
  },
  props: {
    data: Array,
  },
  data() {
    return {
      columns: [],
    };
  },
  mounted() {
    this.columns = this.$slots.default();
  },
};
</script>

ColumnComponent.vue

<template>
  <slot />
</template>

<script>
export default {};
</script>

Celll.vue

<script>
import { h } from 'vue';

export default {
  props: {
    vnodes: {
      type: Object,
      required: true,
    },
    row: {
      type: [String, Number, Object, Array],
      required: true,
    },
  },

  render() {
    return h('td', null, this.vnodes);
  },
};
</script>

Solution

  • <Celll
      v-for="(col, colIndex) in columns"
      :key="colIndex"
      :col="col" // add this
      :row="row"
    
    <script>
    import { h } from 'vue';
    
    export default {
      props: {
        // add this
        col: {
          type: Object,
          required: true,
        },
        row: {
          type: Object,
          required: true,
        },
      },
      render() {
        // edit this
        return h('td', null, this.col.children.defaul(this.row));
      },
    };
    </script>