日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

html5 table的表头拖动,可拖动table表头的实现

發(fā)布時間:2025/3/20 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 html5 table的表头拖动,可拖动table表头的实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

自己做的項目碰到這樣一個需求,就是對所有的表格添加表頭可以拖動的效果。我一想,這不簡單,分分鐘鐘給你做出來。拿起我的電腦,啪啪啪就敲起來了。

一定是哪里不對,以我的聰明才智,結(jié)果應(yīng)該不是這樣的,然后凈下心來,好好理了下思路后,總算是做出來了。

至于結(jié)果嘛,我肯定是做出來的,像下面這種:

準備

首先要說明的是,我們的項目使用的表格大概只分為兩類,一類是表頭不固定,就是普通的表格,另一類是表頭固定,tbody部分是可以滾動的。需要說明的是,表頭固定的那種是需要用兩個table去實現(xiàn),做過的人應(yīng)該也都明白。前者看起來比較簡單,因為寬度是受thead里的th影響的,后者看起來就不好處理,因為你用兩個table就會出現(xiàn)下面的情況:

emmm,這和我們想象的應(yīng)該不一樣,這可咋整,感覺處理起來很麻煩啊。想起看過element-ui中的表格,似乎有拖動表頭的實現(xiàn),先打開控制臺看下結(jié)構(gòu)吧:

呃,話說長這么大我都沒用過

和這兩個標簽,但仔細觀察上面有個width,看到這大概也知道是怎么回事了,打開MDN看下相關(guān)屬性的描述,和想的一樣,width能控制當前列的寬度。

寬度的控制我們是解決了,還有一個問題,就是拖動后,其他列的寬度改怎么改變,如下:

a

b

c

d

如果我拖動a列,改變的寬度應(yīng)該怎樣分配到b,c,d上,我這里是這樣處理的,b、c、d有個屬性去表示該列是否已經(jīng)被拖動過了,如果b、c、d都沒拖動過,那么把a改變的寬度平分到b、c、d三列的寬度上,如果b、c、d都改變了話,那么只改變最后一列d的寬度。好了,思路已經(jīng)有了,我們可以去實現(xiàn)了。

事實證明,如果按照上面的設(shè)計就太蠢了,已經(jīng)改成只改變拖動列后面的列且這些列沒有改變過寬度。

實現(xiàn)

首先html結(jié)構(gòu)大概是這樣的:

ab

12

js方面

constructor (id, options) {

this._el = document.querySelector(`#${id}`);

// 實際使用中需要對dom結(jié)構(gòu)進行判斷,這里就不做了

this._tables = Array.from(this._el.querySelectorAll('table'));

setTimeout(() => this._resolveDom());

this.store = {

dragging: false, //是否拖動

draggingColumn: null, //拖動的對象

miniWidth: 30, //拖動的最小寬度

startMouseLeft: undefined, //鼠標點擊時的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);

//不管是一個table還是兩個,都把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);

}

//拖動時的占位線

const hold = document.createElement('div');

hold.classList.add('resizable-hold');

this._el.appendChild(hold);

上面這塊就是添加節(jié)點的,對dom進行處理,為了復用,這里我們不管你是表頭固定還是表頭不固定,我們都拆分為兩個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事件,當鼠標指針距離右邊緣小于8的時候,改變指針形狀,然后改變store里的狀態(tài),表示此時點擊是可以拖動的了。

然后就是mousedown+mousemove+mouseup來處理拖動了:

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';

};

// 寬度是這樣分配的,舉個?,如果a,b,c,d,他們每個都有個changed狀態(tài),默認false,拖過a,a.changed改為true,改變的寬度就由剩下的b,c,d平攤,如果都改變了,就讓最后一個元素d背鍋

const handleOnMouseUp = (event) => {

if (this.store.dragging) {

const { startColumnLeft } = this.store;

const finalLeft = parseInt(hold.style.left, 10);

const columnWidth = finalLeft - startColumnLeft;

const index = +target.dataset.index;

HColgroup.children[index].width = columnWidth;

if (index !== this.store.HColumns.length - 1) {

this.store.HColumns[index].isChange = true;

}

const deltaLeft = event.clientX - this.store.startMouseLeft;

const changeColumns = this.store.HColumns.filter(v => !v.isChange && +v.el.width > 30);

changeColumns.forEach(item => {

item.el.width = +item.el.width - deltaLeft / changeColumns.length;

});

this.store.BColumns.forEach((item, i) => {

item.el.width = this.store.HColumns[i].el.width;

});

//...init store

}

document.removeEventListener('mousemove', handleOnMouseMove);

document.removeEventListener('mouseup', handleOnMouseUp);

document.onselectstart = null;

document.ondragstart = null;

// noclick主要是用來判斷是點擊還是拖動,防止拖動觸發(fā)排序

setTimeout(() => {

target.classList.remove('noclick');

}, 0);

};

document.addEventListener('mouseup', handleOnMouseUp);

document.addEventListener('mousemove', handleOnMouseMove);

}

};

Tr.addEventListener('mousedown', handleMouseDown);

預覽效果 (chrome + Safari + Firefox)

總結(jié)

覺得很有意思也很有用的東西,也讓自己漲了很多姿勢,源碼,已經(jīng)做成類的形式,使用起來還算簡單,因為是突然提出的需求,還未做過多測試,可能存在不知道的bug。

祝福

寫在最后,馬上就要過年了,心情還是非常happy的。那么,我就在這里提前祝大家新年大吉、、吧,皮一下才開心,哎嘿嘿。拜拜~

后續(xù)補充

更改了寬度改變的方式,應(yīng)該是只改變拖動列后面的列的寬度。有BUG,colgroup放在了thead下面,導致在safari下面有BUG,已經(jīng)修復了,看的不仔細,但上面的代碼還沒有改,看代碼的化還是去看源碼,我沒發(fā)現(xiàn)這個問題,別人幫我找出來的。

emmmmm,又發(fā)現(xiàn)了一個問題,就是拖動最后一列時。。。我想想,先睡了==

總結(jié)

以上是生活随笔為你收集整理的html5 table的表头拖动,可拖动table表头的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。