在寫項目的時候,咱們常常會用一些組件,好比:模態框、表格、分頁等。組件的應用大大減小了項目的開發成本,同時也提升了代碼的質量等。因此,封裝組件成爲了每一個人的必須擁有的技能。本篇文章將使用原生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
還有不小的差距,還須要我繼續努力完善它。
文中代碼可能會有不合理或者錯的地方,還但願你們指出來,咱們共同窗習,共同進步~
最後,分享一下個人公衆號,你們快來關注呀~