Component needs

  • The corresponding table can be generated by passing a columns configuration file
  • Pass a data to render the corresponding data
  • The data can be processed twice through slots

Component Prop design

parameter type Whether must The sample
columns Array is [{title: ‘name’, dataIndex: ‘name’,customRender:true/false}]
data Array is [{name:’123′}]

Parameter interpretation

  • Columns is an array type (must)
    • Each entry in columns is an object (must)
      • Columns Each object should contain:
        • Title (String) : th corresponding to thead generated from this key (required)
        • DataIndex (String): Render the data of the object according to this key (this key corresponds to the key in data) (required)
        • CustomRender (Boolean): Determine whether to assign a corresponding slot based on this key (optional)
    • Data is an array type (must)
      • Each entry in data is an object whose key must correspond to the dataIndex of the columns above (must).

Expected usage


<y-table :columns="columns" :data="data">
  <template #sex="text">{{ text === 1 ? 'male ':' female '}}</template>
  <template #handle="text,record">
    <div style="display:flex">
      <y-button type='success' @click="test(record)" style="margin-right:10px">Modify the</y-button>
      <y-button type='danger' @click="test(record)">delete</y-button>
    </div>
  </template>
</y-table>

<script>
  data () {
    return {
      columns: [{title: 'name'.dataIndex: 'name'
        },
        {
          title: 'age'.dataIndex: 'age'
        },
        {
          title: 'gender'.dataIndex: 'sex'.customRender: true
        },
        {
          title: 'operation'.dataIndex: 'handle'.customRender: true}].data: [{name: 'Chicken is too beautiful'.age: 39.sex: 1.reload: 3
        },
        {
          name: 'Chicken Too Beautiful 2'.age: 39.sex: 2.reload: 3}}}]</script>
Copy the code

Desired effect

Component implementation

Step 1: Define two props based on the requirements above


props: {
    columns: {
      type: Array.required: true
    },
    data: {
      type: Array.default: () = >[]}}Copy the code

Step 2: Generate the corresponding Thead according to the title of the columns passed in

// Generate thead based on the configuration
_renderHeader (h) {
  return h('thead', { class: 'y-header' }, [
    h('tr', { class: 'y-header-row'},this.columns.map(row= > {
        return h('th', { class: ['y-header-column'.'y-table-left'] }, row.title)
      })
    ])
  ])
}
Copy the code

Step 3: Render the corresponding data according to the dataIndex of columns and the key value of data, and then judge whether to allocate the corresponding slot according to the customRender of columns

// Generate tBody based on configuration, and assign scope slots based on customRender
_renderBody (h) {
  return h('tbody', {},this.data.map(row= > {
      return h('tr', { class: 'y-body-row'},this.columns.map(item= > {
          return h('td', { class: 'y-body-column' }, item.customRender && this.$scopedSlots[item.dataIndex]
            ? this.$scopedSlots[item.dataIndex](row[item.dataIndex], { ... row }) : row[item.dataIndex]) }) ]) }) ]) }Copy the code

The slots that are generated here are scope slots, which are sometimes the gods that encapsulate the component, where the current value is passed to the first argument of the slot, and the current row data is passed to the second argument, so the outside can get data like this

 <template #handle="text,record">
    <div style="display:flex">
      <y-button type='success' @click="test(record)" style="margin-right:10px">Modify the</y-button>
      <y-button type='danger' @click="test(record)">delete</y-button>
    </div>
  </template>
Copy the code

Step 4: Finally assemble the table, return out OK

/ / assembly table
  _renderTable (h) {
    return (
      <table class='y-table'>
        {this._renderHeader(h)}
        {this._renderBody(h)}
      </table>
    )
  }

  render (h) {
    return (
      this._renderTable(h)
    )
  }
Copy the code

conclusion

So far, we have implemented the corresponding configurable table component according to the above requirements. The core of the above two generation methods (_renderHeader,_renderBody) is about 20 lines, for familiar with JSX and scope slots students are easy, hope this article is helpful to you.

Complete logical code

export default {

  props: {

    columns: {

      type: Array.required: true

    },

    data: {

      type: Array.default: () = >[]}},methods: {

    // Format the data

    formatter (row, item) {

      return (item.formatter && item.formatter(row[item.dataIndex])) || row[item.dataIndex]

    },

    // Generate thead based on the configuration

    _renderHeader () {

      const h = this.$createElement

      return h('thead', { class: 'y-header' }, [

        h('tr', { class: 'y-header-row'},this.columns.map(row= > {

            return h('th', { class: ['y-header-column'.'y-table-left'] }, row.title)

          })

        ])

      ])

    },

    // Generate tBody based on configuration, and assign scope slots based on customRender

    _renderBody () {

      const h = this.$createElement

      return h('tbody', {},this.data.map(row= > {

          return h('tr', { class: 'y-body-row'},this.columns.map(item= > {

              return h('td', { class: 'y-body-column' }, item.customRender && this.$scopedSlots[item.dataIndex]

                ? this.$scopedSlots[item.dataIndex](row[item.dataIndex], {

                  row: row

                }) : this.formatter(row, item))

            })

          ])

        })

      ])

    },

    / / assembly table

    _renderTable () {

      return (

        <table class='y-table'>

          {this._renderHeader()}

          {this._renderBody()}

        </table>

      )

    }

  },

  render (h) {

    return (

      this._renderTable()

    )

  }

}

</script>
Copy the code