用原生JS封装一个Table组件

在写项目的时候,我们经常会用一些组件,比如:模态框、表格、分页等。组件的应用大大减少了项目的开发成本,同时也提高了代码的质量等。所以,封装组件成为了每个人的必须拥有的技能。本篇文章将使用原生JS封装一个Table组件。
组件封装
实现目标
以antd中的Table组件为目标,实现以下功能:

传width值控制表格宽度。
columns与dataSource中的数据相对应,没有对应数据的地方显示为空。
实现columns中的render函数方法。
对columns数据中key值的检查,没有或者重复,给出警告。
columns中width可设置列宽
columns中align值控制内容在表格中所处的位置。

搭建结构
首先,先搭建一下代码的结构
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) }})()复制代码
接下来,我们来做一个异常处理
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. T A B L E H E A D = t h i s . c r e a t e H e a d ( ) ; / / t b o d y t h i s . TABLE_HEAD = this.createHead(); // tbody this. TABLE_BODY = this.createBody(); // 向table中添加thead this. T A B L E . a p p e n d C h i l d ( t h i s . TABLE.appendChild(this. TABLE_HEAD); // 向body中插入table document.body.appendChild(this.KaTeX parse error: Expected 'EOF', got '}' at position 8: TABLE);}̲复制代码 创建thead函数 …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.KaTeX parse error: Expected 'EOF', got '}' at position 61: …AD_TH[j])); }̲ // 向thead中添…THEAD.appendChild(this. T H E A D T R ) ; / / t h e a d r e t u r n t h i s . 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})复制代码
这份数据,很显然,是会报错的
https://weavi.com/18045772
https://weavi.com/18045754
https://weavi.com/18045747
https://weavi.com/18045726
https://weavi.com/18045738
修改一下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}) }}]复制代码

这就不报错了,至此,我们完成了目标的几个功能。

发布了60 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/a59612/article/details/104319437