tbody
部分是可以滾動(dòng)的。需要說明的是,表頭固定的那種是需要用兩個(gè)table
去實(shí)現(xiàn),做過的人應(yīng)該也都明白。前者看起來比較簡單,因?yàn)閷挾仁鞘?code>thead里的th
影響的,后者看起來就不好處理,因?yàn)槟阌脙蓚(gè)table就會(huì)出現(xiàn)下面的情況:
emmm,這和我們想象的應(yīng)該不一樣,這可咋整,感覺處理起來很麻煩啊。想起看過
element-ui
中的表格,似乎有拖動(dòng)表頭的實(shí)現(xiàn),先打開控制臺(tái)看下結(jié)構(gòu)吧:
呃,話說長這么大我都沒用過
<colgroup>
和<col>
這兩個(gè)標(biāo)簽,但仔細(xì)觀察上面有個(gè)width
,看到這大概也知道是怎么回事了,打開MDN看下相關(guān)屬性的描述,和想的一樣,width
能控制當(dāng)前列的寬度。寬度的控制我們是解決了,還有一個(gè)問題,就是拖動(dòng)后,其他列的寬度改怎么改變,如下:
如果我拖動(dòng)a列,改變的寬度應(yīng)該怎樣分配到b,c,d上,我這里是這樣處理的,b、c、d有個(gè)屬性去表示該列是否已經(jīng)被拖動(dòng)過了,如果b、c、d都沒拖動(dòng)過,那么把a(bǔ)改變的寬度平分到b、c、d三列的寬度上,如果b、c、d都改變了話,那么只改變最后一列d的寬度。好了,思路已經(jīng)有了,我們可以去實(shí)現(xiàn)了。
事實(shí)證明,如果按照上面的設(shè)計(jì)就太蠢了,已經(jīng)改成只改變拖動(dòng)列后面的列且這些列沒有改變過寬度。
實(shí)現(xiàn)
首先html結(jié)構(gòu)大概是這樣的:
<table> <thead> <tr> <th>a<th> <th>b<th> </tr> </thead> <tbody> <tr> <th>1<th> <th>2<th> </tr> </tbody> </table>
js方面
constructor (id, options) { this._el = document.querySelector(`#${id}`); // 實(shí)際使用中需要對(duì)dom結(jié)構(gòu)進(jìn)行判斷,這里就不做了 this._tables = Array.from(this._el.querySelectorAll('table')); setTimeout(() => this._resolveDom()); this.store = { dragging: false, //是否拖動(dòng) draggingColumn: null, //拖動(dòng)的對(duì)象 miniWidth: 30, //拖動(dòng)的最小寬度 startMouseLeft: undefined, //鼠標(biāo)點(diǎn)擊時(shí)的clientX startLeft: undefined, //th右離table的距離 startColumnLeft: undefined, //th左離table的距離 tableLeft: undefined, //table離頁面左邊的距離, HColumns: [], BColumns: [], }; };
添加dom:
const [ THeader ] = this._tables; let TBody; const Tr = THeader.tHead.rows[0]; const columns = Array.from(Tr.cells); const Bcolgroup = document.createElement('colgroup'); const cols = columns.map((item, index) => { const col = document.createElement('col'); item.dataset.index = index; col.width = +item.offsetWidth; return col; }); cols.reduce((newDom, item) => { newDom.appendChild(item); return newDom; }, Bcolgroup); const HColgroup = Bcolgroup.cloneNode(true); THeader.appendChild(HColgroup); //不管是一個(gè)table還是兩個(gè),都把header和body提出來 if (this._tables.length === 1) { const [ , tbody ] = Array.from(THeader.children); tbody.remove(); TBody = THeader.cloneNode(); TBody.appendChild(Bcolgroup); TBody.appendChild(tbody); this._el.appendChild(TBody); } else { [ , TBody ] = this._tables; TBody.appendChild(Bcolgroup); } //拖動(dòng)時(shí)的占位線 const hold = document.createElement('p'); hold.classList.add('resizable-hold'); this._el.appendChild(hold);
上面這塊就是添加節(jié)點(diǎn)的,對(duì)dom
進(jìn)行處理,為了復(fù)用,這里我們不管你是表頭固定還是表頭不固定,我們都拆分為兩個(gè)table
,這樣處理起來也方便的多。
然后就是處理手指移到列右側(cè)cursor
的值設(shè)為col-resize
:
handleMouseMove(evt) { //... if (!this.store.dragging) { const rect = target.getBoundingClientRect(); const bodyStyle = document.body.style; if (rect.width > 12 && rect.right - event.pageX < 8) { bodyStyle.cursor = 'col-resize'; target.style.cursor = 'col-resize'; this.store.draggingColumn = target; } else { bodyStyle.cursor = ''; target.style.cursor = 'pointer'; this.store.draggingColumn = null; } } };
需要注意的是,getBoundingClientRect()
獲取的rigth
是元素右側(cè)距離頁面左邊緣的距離,不是離頁面右邊緣的距離。這里就是給thead
的tr
添加mousemove
事件,當(dāng)鼠標(biāo)指針距離右邊緣小于8的時(shí)候,改變指針形狀,然后改變store
里的狀態(tài),表示此時(shí)點(diǎn)擊是可以拖動(dòng)的了。
然后就是mousedown
+mousemove
+mouseup
來處理拖動(dòng)了:
const handleMouseDown = (evt) => { if (this.store.draggingColumn) { this.store.dragging = true; let { target } = evt; if (!target) return; const tableEle = THeader; const tableLeft = tableEle.getBoundingClientRect().left; const columnRect = target.getBoundingClientRect(); const minLeft = columnRect.left - tableLeft + 30; target.classList.add('noclick'); this.store.startMouseLeft = evt.clientX; this.store.startLeft = columnRect.right - tableLeft; this.store.startColumnLeft = columnRect.left - tableLeft; this.store.tableLeft = tableLeft; document.onselectstart = () => false; document.ondragstart = () => false; hold.style.display = 'block'; hold.style.left = this.store.startLeft + 'px'; const handleonMouseMove = (event) => { const deltaLeft = event.clientX - this.store.startMouseLeft; const proxyLeft = this.store.startLeft + deltaLeft; hold.style.left = Math.max(minLeft, proxyLeft) + 'px'; }; // 寬度是這樣分配的,舉個(gè)以上就是如何實(shí)現(xiàn)可拖動(dòng)table表頭的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!