Writing in the front

When writing projects, we often use components such as modal boxes, tables, pagination, etc. The application of component greatly reduces the development cost of the project, but also improves the quality of the code. As a result, encapsulating components has become a must-have skill for everyone. This article will use native JS to wrap a Table component.

Component packaging

Achieve the goal

The Table component in ANTD is targeted to achieve the following functions:

  • Pass the width value to control the table width.

  • Columns correspond to the data in the dataSource, and the columns without corresponding data are displayed as empty.

  • Implement the render function method in columns.

  • Warning of no or duplicate key values in columns data.

  • Column width specifies the column width

  • The align value of columns controls the position of the content in the table.

Building structure

First, let’s structure the code

window.Table(function(){

    class Table {

        constructor(options) {

            // Get the required data

            this.columns = options.columns;

            this.dataSource = options.dataSource;

            this.width = options.width;



            this.init();   // Call the initialization function

        } 



        / / initialization

        init() {



        }

    }



    return function proxy(options = {}{

        options = Object.assign({

            columns: [].

            dataSource: [].

            width'80%'.

        }, options);

        return new Table(options)

    }

}) ()

Copy the code

Next, let’s do an exception handling

1. If options is not an object, columns, or dataSource is not an array, an error message is displayed

if(!Array.isArray(options? .columns)) {

    throw new Error('Error: Columns must be an array');

}

if(!Array.isArray(options? .dataSource)) {

    throw new Error('Error: dataSource must be an array');

}

if(options === null || typeofoptions ! = ="object") {

    throw new Error('Error: Options must be an object');

}

Copy the code

2. If the columns key does not exist or is repeated, a warning is provided

if(!Array.isArray(options? .columns)) {

    throw new Error('Error: Columns must be an array');

else {

    for(let i = 0; i < options? .columns.length; i++) {

        for(let j = i + 1; j < options? .columns.length; j++) {

            if(! options? .columns[i]? .key) {

                console.error('warning:Each item in columns should have a key');

                break;

            } else {

                if(options? .columns[i]? .key === options? .columns[j]? .key) {

                    console.error('warning:The key for each item in columns should be unique');

                    break;

                }

            }

        }

    }

}

Copy the code

Since it is a component, it should have a corresponding UI style, so the next step is to create the node

init() {

    this.createElement();

}

// Create a DOM node function with two arguments: 1. node type 2. CSS style

create(type, cssText) {

    let ele = document.createElement(type);

    ele.style.cssText = cssText;

    return ele;

}

createElement() {



}

Copy the code

Create table, thead, and tBody

createElement() {

    // table

    this.$TABLE = this.create('table', `

        width: ${this.width};

    `);

    // thead

    this.$TABLE_HEAD = this.createHead();

    // tbody

    this.$TABLE_BODY = this.createBody();



    // Add thead to table

    this.$TABLE.appendChild(this.$TABLE_HEAD);



    // Insert table into body

    document.body.appendChild(this.$TABLE);

}

Copy the code

Create thead function

createHead() {

    let { columns } = this;

    let THEAD_TH =  null;

    / / create the thead

    this.$THEAD = this.create("thead", `background: #e3e3e3`); 

    / / create the tr

    this.$THEAD_TR = this.create("tr");                         

    // Iterate over creating th and adding content to th

    for(let i = 0; i< columns.length; i++) {

        THEAD_TH  = this.create("th", `

                        border: 1px solid #999;

width: ${item? .width};

                    `)

        THEAD_TH.innerHTML = columns[i].title;

    }

    // Add th node to tr

    for(let j = 0; j < THEAD_TH; j++) {

        this.$THEAD_TR.appendChild(THEAD_TH.appendChild(THEAD_TH[j]));

    }

    // Add the tr node to thead

    this.$THEAD.appendChild(this.$THEAD_TR);

    / / returns the thead

    return this.$THEAD;

}

Copy the code

Current style

Create the tBody function

createBody() {

    let { dataSource, columns } = this;

    // Initialize the data

    let TBODY_TR = null.

        TBODY_TD = null.

        TBODY = this.create("tbody");     



    // Iterate to generate tr and TD under tBody

    for(let i = 0; i < dataSource.length; i++) {

        / / create the tr

        TBODY_TR = this.create('tr');     

        for(let j = 0; j < columns.length; j++) {

            / / create the td

            TBODY_TD = this.create('td'.`

                border: 1px solid #999;

                text-align: ${columns[j]? .align};

            `
);

            // The render passed in is the function

            if(columns[j]? .render &&typeofcolumns[j]? .render ==="function") {

                // Execute the render function, pass in the row and column values, and get the return values

                letrender = columns[j]? .render(dataSource[i][columns[j]?.dataIndex], dataSource[i]);

                // If the return value is a DOM node, insert the node into td

                if(typeof render === "object") {

                    TBODY_TD.appendChild(render);

                } else {  // Otherwise go directly to innerHTML

                    TBODY_TD.innerHTML = render;

                }

            } else {  // Insert the corresponding value directly without render

                TBODY_TD.innerHTML = dataSource[i][columns[j].dataIndex] || ' '

            }

            // Insert TD into tr

            TBODY_TR.appendChild(TBODY_TD);

            // Insert tr into tbody

            TBODY.appendChild(TBODY_TR);

        }

    }

    return TBODY;

}

Copy the code

Now that we’re done with our basic functionality, let’s see what happens

The effect above is that the data we pass in looks like this

const columns = [{

    title'name'.

    dataIndex'name'.

    align'center'.

    key'name'.

}, {title'age'.

    dataIndex'age'.

}, {title'work'.

    dataIndex'job'.

    key'name'.

}, {

    title'operation'.

    key'action'.

    render(text, record) = > {

       return create('a'.'color: blue', {record})

    }

}]



function create(type, cssText, data{

    let element = document.createElement(type);

    element.style.cssText = cssText;

    element.innerHTML = 'delete';

    element.onclick = click.bind(this, data.record);

    return element;

}

function click(record{

    console.log(record);

}

const dataSource = [{

    name'little red'.

    age'111'.

    job'front end'

}, {

    age'111'

}, {

}, {

    name'little red 1'.

    job1'front end'

}]

Table({columns, dataSource})

Copy the code

This data, of course, is subject to error

Modify the columns data

const columns = [{

    title: 'name'.

    dataIndex: 'name'.

    align: 'center'.

    key: 'name'.

}, {title: 'age'.

    dataIndex: 'age'.

    key: 'age'.

}, {title: 'work'.

    dataIndex: 'job'.

    key: 'job'.

}, {

    title: 'operation'.

    key: 'action'.

    render: (text, record)= > {

       return create('a'.'color: blue', {record})

    }

}]

Copy the code

This will not be an error, and at this point we have accomplished several of the goals.

conclusion

The code in this article has been uploaded to Github at table

This paper takes ANTD’s Table component as the target and encapsulates a Table component of its own. There is still a big gap between antD and ANTD in function, and I still need to continue my efforts to improve it.

The code may have unreasonable or wrong places, but also hope that we point out, we learn together, common progress ~

Finally, share my public number, everyone come to pay attention to ~