1. An overview of the

Learning elder-UI source code can be a good way to improve the level of Vue, but elder-UI el-table source code is very complex, and the component is written using the render function method, rather than vue single file, which makes it difficult to read its source code, so I am learning, in order to master el-Tab At the heart of le, I did two things. First, I simplified the code and removed too much detail. Number two, write an HTML and run all your code in HTML

2. The target

Implement the use of the following EL-Table components, including display columns through PROP and custom columns through Template

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
</head>
<body>
    <div id="app">
        <el-table :data="tableData">
            <el-table-column prop="name" label="Name"></el-table-column>
            <el-table-column label="Address">
                <template slot-scope="scope">{{scope.row.address}}</template>
            </el-table-column>
        </el-table>
    </div>
</body>
<script>
var vm = new Vue({
    el: '#app'.data: {
        tableData: [{
            name: 'Joe'.address: No. 1 qingyuan Road, Qingyang District, Chengdu
        }, {
            name: 'bill'.address: No. 2 Qingyuan Road, Qingyang District, Chengdu}]}})</script>
Copy the code

Step 4.

3.1 Defining the state manager

Mimic vuex’s structure and create a TableStore class that defines the COMMIT method and mutations object

// State manager
class TableStore {
    constructor(){
        this.states = {
            data: null./ / table data
            columns: [] // Table column definition}}commit(name, ... args){/ / call mutations
        this.mutations[name].apply(this[this.states].concat(args))
    }
}
The definition of / / mutations
TableStore.prototype.mutations = {
    // Set table data
    setData(states, data) {
        states.data = data
    },
    // Insert column definitions
    insertColumn(states, column) {
        states.columns.push(column)
    }
}
Copy the code

3.2 Defining the EL-Table Component

Responsible for:

  • Initialize the state manager
  • The default slot accepts the table-column component
  • Use the table-header and table-body components
Vue.component('el-table',{
    template: `<div class="el-table">
        <! -- Hide column: slot contains table-column -->
        <div class="hidden-columns">
            <slot></slot>
        </div>
        <! -- -- -- > meter
        <div class="el-table__header-wrapper">
            <! -- Table header component -->
            <table-header :store="store"></table-header>
        </div>
        <! - table body -- -- >
        <div class="el-table__body-wrapper">
            <! Table body component -->
            <table-body :store="store"></table-body>
        </div>
    </div>', props: ['data'],//table data(){return {store: new TableStore() // Status manager}}, watch: {data: {immediate: This.store.com MIT ('setData', value)}}}})Copy the code

3.3 Defining the EL-table-column component

Responsible for: Generate column definitions (including table header names, column field names, render methods) and put them in the state manager for use by table-header and table-body components

Vue.component('el-table-column', {template: `<div></div>`.props: ['label'.'prop'].computed: {
        owner() {// Find the outer component that owns the table
            return this.$parent; }},created() {  
        // Generate column definitions
        let column = {
            label: this.label,// The list header displays the name
            property: this.prop,// The name of the column used
            renderCell: null// The method used for rendering
        };
        let renderCell = column.renderCell;
        let _self = this;
        // Generate a render method for the column
        column.renderCell = function (createElement, data) {
            // There are slots
            if (_self.$scopedSlots.default) {
                // Render scope slot
                renderCell = () = > _self.$scopedSlots.default(data);
                // Use effect:
                //<template slot-scope="{row}">
                //<span>{{row.address}}</span>
                //</template>
            }else{
            // There is no slot
                renderCell = function () {
                    let { row } = data
                    let  property = column.property;
                    // The direct return time is short
                    return row[property]
                }
                
      
*/
} // Generate a render function return createElement('div', { 'class': { cell: true } },renderCell()) } // Generate column definitions this.columnConfig = column }, mounted(){ // Add the column definition to the state manager for table-body table-header use this.owner.store.commit('insertColumn'.this.columnConfig) } }) Copy the code

3.4 Defining the Table-header component

Responsible for rendering the table header of the list according to the column definition in the state manager

Vue.component('table-header', {props: ['store'].computed: {
        columns() { // Get the column definition in the status manager
            return this.store.states.columns; }},render(createElement) { Create a vNode with createElement
        / * : < table class = "el - table__header" > < thead > < th > < div > name < / div > < / th > < th > < div > address < / div > < / th > < thead > < / table > * /
        return createElement('table', {class: {'el-table__header': true}}, [
            createElement('thead'.this.columns.map(column= >{
                    return createElement('th',[createElement('div',column.label)])
                })
            )
        ])
    }
})
Copy the code

3.5 Defining the Table-body Component

Responsible for rendering table body data through column definitions and data in the state manager

/ / table - body components
Vue.component('table-body', {props: ['store'].computed: {
        data() { // Get the list data in the status manager
            return this.store.states.data;
        },
        columns() { // Get the column definition in the status manager
            return this.store.states.columns; }},render(createElement) { Create a vNode with createElement
        / * : < table class = "el - el - table__body" > < tr > < td >...    */
        return createElement('table', {class: {'el-el-table__body': true}}, 
            this.data.map((row) = >{
                return createElement('tr'.this.columns.map(column= >{
                    return createElement('td',[column.renderCell.call(null,createElement,{row})])
                }))
            })
        )
    },
})
Copy the code

4 Effect and complete code

preview

5. Learn more

Vue object render method learning