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 ~