在写项目的时候,咱们常常会用一些组件,好比:模态框、表格、分页等。组件的应用大大减小了项目的开发成本,同时也提升了代码的质量等。因此,封装组件成为了每一个人的必须拥有的技能。本篇文章将使用原生JS
封装一个Table
组件。javascript
以antd
中的Table
组件为目标,实现如下功能:css
传width
值控制表格宽度。前端
columns
与dataSource
中的数据相对应,没有对应数据的地方显示为空。java
实现columns
中的render
函数方法。git
对columns
数据中key
值的检查,没有或者重复,给出警告。github
columns
中width
可设置列宽web
columns
中align
值控制内容在表格中所处的位置。 数组
首先,先搭建一下代码的结构antd
window.Table(function(){
class Table {
constructor(options) {
// 获取所须要数据
this.columns = options.columns;
this.dataSource = options.dataSource;
this.width = options.width;
this.init(); // 调用初始化函数
}
// 初始化
init() {
}
}
return function proxy(options = {}) {
options = Object.assign({
columns: [],
dataSource: [],
width: '80%',
}, options);
return new Table(options)
}
})()
复制代码
接下来,咱们来作一个异常处理app
1.若是options
不为对象、columns
、dataSource
不为数组,则报错
if(!Array.isArray(options?.columns)) {
throw new Error('error:columns must be a array');
}
if(!Array.isArray(options?.dataSource)) {
throw new Error('error:dataSource must be a array');
}
if(options === null || typeof options !== "object") {
throw new Error('error:options must be a object');
}
复制代码
2.当columns
的key
没有或者重复时,给出警告
if(!Array.isArray(options?.columns)) {
throw new Error('error:columns must be a 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;
}
}
}
}
}
复制代码
既然是一个组件,那么就应该有对应的UI
样式,因此接下来这一步,须要建立节点
init() {
this.createElement();
}
// 建立dom节点函数,两个参数: 1.节点类型 2.css样式
create(type, cssText) {
let ele = document.createElement(type);
ele.style.cssText = cssText;
return ele;
}
createElement() {
}
复制代码
建立table
、thead
、tbody
createElement() {
// table
this.$TABLE = this.create('table', `
width: ${this.width};
`);
// thead
this.$TABLE_HEAD = this.createHead();
// tbody
this.$TABLE_BODY = this.createBody();
// 向table中添加thead
this.$TABLE.appendChild(this.$TABLE_HEAD);
// 向body中插入table
document.body.appendChild(this.$TABLE);
}
复制代码
建立thead函数
createHead() {
let { columns } = this;
let THEAD_TH = null;
// 建立thead
this.$THEAD = this.create("thead", `background: #e3e3e3`);
// 建立tr
this.$THEAD_TR = this.create("tr");
// 遍历建立th,而且向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;
}
// 遍历向tr中添加th节点
for(let j = 0; j < THEAD_TH; j++) {
this.$THEAD_TR.appendChild(THEAD_TH.appendChild(THEAD_TH[j]));
}
// 向thead中添加tr节点
this.$THEAD.appendChild(this.$THEAD_TR);
// 返回thead
return this.$THEAD;
}
复制代码
如今的样式
建立tbody
函数
createBody() {
let { dataSource, columns } = this;
// 初始化数据
let TBODY_TR = null,
TBODY_TD = null,
TBODY = this.create("tbody");
// 遍历生成tbody节点下的tr和td
for(let i = 0; i < dataSource.length;i++) {
// 建立tr
TBODY_TR = this.create('tr');
for(let j = 0;j < columns.length;j++) {
// 建立td
TBODY_TD = this.create('td', `
border: 1px solid #999;
text-align: ${columns[j]?.align};
`);
// 传入的render是函数
if(columns[j]?.render && typeof columns[j]?.render === "function") {
// 执行render函数,传入行值和列值,而且得到返回值
let render = columns[j]?.render(dataSource[i][columns[j]?.dataIndex], dataSource[i]);
// 若是返回值是一个dom节点,则向td里插入节点
if(typeof render === "object") {
TBODY_TD.appendChild(render);
} else { // 不然直接innerHTML
TBODY_TD.innerHTML = render;
}
} else { // 没有传render时,直接插入对应值
TBODY_TD.innerHTML = dataSource[i][columns[j].dataIndex] || ''
}
// 向tr中插入td
TBODY_TR.appendChild(TBODY_TD);
// 向tbody中插入tr
TBODY.appendChild(TBODY_TR);
}
}
return TBODY;
}
复制代码
如今,就完成了咱们的基本功能,来看一下效果
上面的效果,咱们传入的数据是这样的
const columns = [{
title: '姓名',
dataIndex: 'name',
align: 'center',
key: 'name',
}, {title: '年龄',
dataIndex: 'age',
}, {title: '工做',
dataIndex: 'job',
key: 'name',
}, {
title: '操做',
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 = '删除';
element.onclick = click.bind(this, data.record);
return element;
}
function click(record) {
console.log(record);
}
const dataSource = [{
name: '小红',
age: '111',
job: '前端'
}, {
age: '111'
}, {
}, {
name: '小红1',
job1: '前端'
}]
Table({columns, dataSource})
复制代码
这份数据,很显然,是会报错的
修改一下columns
的数据
const columns = [{
title: '姓名',
dataIndex: 'name',
align: 'center',
key: 'name',
}, {title: '年龄',
dataIndex: 'age',
key: 'age',
}, {title: '工做',
dataIndex: 'job',
key: 'job',
}, {
title: '操做',
key: 'action',
render: (text, record) => {
return create('a', 'color: blue', {record})
}
}]
复制代码
这就不报错了,至此,咱们完成了目标的几个功能。
文中代码已经上传到github
中,地址为:table
本篇文章以antd
的Table
组件为目标,封装了一个本身的Table
组件,功能上和antd
还有不小的差距,还须要我继续努力完善它。
文中代码可能会有不合理或者错的地方,还但愿你们指出来,咱们共同窗习,共同进步~
最后,分享一下个人公众号,你们快来关注呀~