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)
- Columns Each object should contain:
- 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).
- Each entry in columns is an object (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