前言
對于動態(tài)獲取數(shù)據(jù)的表格聚至,如果期望單元格內(nèi)容不折行酷勺,就要設(shè)定足夠的寬度,同時又希望表格內(nèi)容盡量緊湊扳躬,但是脆诉,由于數(shù)據(jù)不確定,所以無法預(yù)設(shè)寬度贷币,怎么辦呢击胜?有這樣一種辦法:
方案
- 先讓表格渲染
- 引入CSS class來讓單元格內(nèi)容單行顯示
- 遍歷表體的.cell,算出每個元素的
scrollWidth
片择,匯總到二維數(shù)組里 - 考察二維數(shù)組的每個一級元素的每個單元格的寬度潜的,找出最大值
-
<el-table-column>
設(shè)置的width
都等于各自列的最大值即可
這個方案按理說,會發(fā)生表格閃爍字管,因為先渲染啰挪,又調(diào)整列寬的緣故。為了解決這個問題嘲叔,我想到了visibility: hidden;
亡呵,當(dāng)hidden
時,表格依然會渲染硫戈,只不過不顯示锰什,此時就可以計算各種寬度,等計算好,賦值好汁胆,再visible
即可梭姓。
恰好可以借用loading
變量實現(xiàn)hidden
和visible
的切換。
template
- 給表格組件加上這個:
ref="listTable" class="columns-fit" :class="loading ? null : 'visible'"
- 給每個
<el-table-column>
加上width
嫩码,如下:
<el-table-column type="selection" align="center" :width="colWidthList[0]" />
<el-table-column label="序號" align="center" prop="id" :width="colWidthList[1]" />
...
...
其中下標(biāo)表示第幾個列誉尖。你可以給有些列不設(shè)width
,或者設(shè)置固定數(shù)值铸题,此時其他列的下標(biāo)無需調(diào)整铡恕,但是如果列順序變了,下標(biāo)必須重排丢间。
style
在某個全局引入的scss文件寫入:
.columns-fit {
.el-table__header-wrapper, .el-table__body-wrapper {
visibility: hidden;
}
&.visible {
.el-table__header-wrapper, .el-table__body-wrapper {
visibility: visible;
}
}
.el-table__body-wrapper {
overflow: auto;
}
td>.cell {
display: inline-block;
white-space: nowrap;
width: auto;
overflow: auto;
}
}
script
先不說本方案探熔,先說原始的請求數(shù)據(jù)列表的代碼大致是這樣:
getList() {
this.loading = true;
list(this.queryParams).then(response => {
this.list = response.data;
this.total = response.total;
this.loading = false;
});
},
然后我們對它略改造,加上一句:
getList() {
this.loading = true;
list(this.queryParams).then(response => {
this.list = response.data;
this.total = response.total;
this.$nextTick(() => {
setTimeout(() => {
this.colWidthList = this.$adjustColumnWidth(this.$refs['listTable'].$el);
this.loading = false;
});
});
});
},
colWidthList
去data
里定義一個空數(shù)組烘挫,用來存每個col的最終寬度诀艰。
比較迷的是setTimeout
,你是不是不知道我為啥加一句這個墙牌?當(dāng)表格沒有橫向滾動條涡驮,用下方的代碼計算出來的每個單元格的scrollWidth
會有錯誤暗甥,原因是Element UI的某些計算規(guī)則比較迷喜滨,它先計算一遍,然后微調(diào)一遍撤防,會讓單元格稍微變化幾像素虽风,而setTimeout
從JS底層說是宏任務(wù),可以等待Element UI對單元格的調(diào)整結(jié)束寄月,這樣辜膝,得到的scrollWidth
才是準(zhǔn)的。
adjustColumnWidth
函數(shù)需要寫入一個全局JS:
export default function(el) {
let widthList = [];
el.querySelectorAll('.el-table__body tr').forEach((tr) => {
tr.querySelectorAll('td').forEach((td, i) => {
if (!widthList[i]) {
widthList[i] = [];
}
widthList[i].push(td.scrollWidth);
});
});
return widthList.map(width => Math.max(...width));
}
main.js里引入:
import adjustColumnWidth from '@/utils/adjustColumnWidth';
Vue.prototype.$adjustColumnWidth = adjustColumnWidth;
到此OK漾肮。
使用特別說明
1. 本方案不考慮表頭的單元格溢出厂抖,請另外考慮
Element UI里面有這樣的樣式,其中由于text-overflow
的值沒有none
克懊,也就是說忱辅,text-overflow
一旦寫上了就無法取消,導(dǎo)致表頭無法像表身一樣呈現(xiàn)單行且無省略號的狀態(tài)谭溉,因此也就無法取得我們想要的表頭單元格的scrollWidth
墙懂,所以,本方案不計算表頭單元格的寬度扮念。這就導(dǎo)致了一個問題:
如果某列的表頭字符很長损搬,但表身內(nèi)容很短,這樣計算得到的width
會比表頭字符還要短,表頭會出現(xiàn)折行巧勤。
結(jié)論:要么嵌灰,你就接受這種折行的設(shè)定,要么颅悉,就給col寫死固定的伞鲫、足夠的width
值。
2. 刪除列签舞、調(diào)整列順序時秕脓,:width="colWidthList[n]"
的下標(biāo)要記得對應(yīng)修改
請記得對應(yīng)修改。下標(biāo)應(yīng)該永遠(yuǎn)是列的排序序號儒搭。
3. 瀏覽器窗口由小窗拉大到大窗吠架,表格寬度不變,右側(cè)出現(xiàn)空白搂鲫,怎么解決傍药?
首先說,width
屬性是Element UI官方屬性魂仍,如果全部列都設(shè)置了width
拐辽,那么官方也沒有辦法讓表格自適應(yīng)容器寬度,所以這其實并不是本方案的鍋擦酌。
我這里提個解決方案:
監(jiān)聽window.onsize
俱诸,動態(tài)修改colWidthList
,等比放大赊舶,代碼我就不寫了睁搭,因為本身這個需求就是極小概率出現(xiàn)的需求。
4. 不要給所有表格都用本方案
如果表格明顯內(nèi)容稀松笼平,就堅決不要使用本方案园骆,因為沒必要。
5. 不要給所有列都用本方案
假如某列的內(nèi)容忽長忽短寓调,短的只有幾個字锌唾,長的有50個字,那么這一列顯然不適合使用自適應(yīng)列寬夺英,因為會造成大面積的空白晌涕,請給該列鎖定width
。
6. 本方案的缺點
本方案為了不讓表格抖動秋麸,造成了2個負(fù)面效果:
會讓表格消失幾十到幾百毫秒甚至幾秒渐排,根據(jù)ajax請求速度而定。如果不采用本方案灸蟆,表格只是被loading遮罩遮住幾十到幾百毫秒至幾秒驯耻,而且遮罩往往半透明亲族,能看到表格的隱約內(nèi)容,是一種具有“高級感”的設(shè)計可缚。
設(shè)置
width
會導(dǎo)致大規(guī)模的UI回流和重繪霎迫,頁面會非常輕微、不易覺察的卡頓一下帘靡,不過好在Element UI做政企系統(tǒng)多知给,可以強迫用戶使用現(xiàn)代瀏覽器,所以問題很輕微描姚。
總之涩赢,如果需求方對界面美觀比較在意,對輕微的轩勘、不易察覺的卡頓不太在乎筒扒,那么可以考慮本方案,如果追求極致流暢绊寻,則請不要使用本方案花墩。