vue.js?Table?組件自定義列寬實(shí)現(xiàn)核心方法
前言
如果你使用過類似于 ElementUI 的組件庫,一定對如下的 API 屬性不眼生,例如:
<!-- Element UI -->
<el-table-column prop="date" label="日期" min-width="150"></el-table-column>
<el-table-column prop="name" label="姓名" width="200"></el-table-column>
<el-table-column prop="province" label="省份" width="200"></el-table-column>
<!-- and-design for vue -->
cols: [
{ title: '日期',dataIndex: 'date',key: 'date', minWidth: 150 },
{ title: '姓名',dataIndex: 'name',key: 'name', width: 200 },
{ title: '省份',dataIndex: 'province',key: 'province', width: 200 },
],上面的例子中,Table 組件支持自定義最小寬度min-width和固定寬度width,如果不設(shè)置,則默認(rèn)填充剩余寬度。
如果你打算自己手動實(shí)現(xiàn)一個 Table 組件,并且對支持定義列寬屬性的實(shí)現(xiàn)毫無頭緒,那這篇文章大概率可以幫你梳理一些邏輯和核心方法的實(shí)現(xiàn)(Vue3)
注:這也許不是最佳的實(shí)現(xiàn)方案。
準(zhǔn)備工作:
這里假定使用的是類似于and-design for vue的屬性傳值方式,即列的屬性配置是通過額外的數(shù)組對象傳入的。
除了title-列表頭名,key-列值對應(yīng)的鍵外,還有這篇文章涉及到的最小寬度minWidth和固定寬度width,并通過組件屬性cols傳入。
colgroup 和 col
這里需要用到<colgroup>和<col>標(biāo)簽,以便更好的去控制每列的屬性信息,兩個標(biāo)簽均支持傳入width屬性控制列寬度,不同的是,<col>控制的是單列的寬度,而<colgroup>可以控制所包含在內(nèi)的。
除此之外,這兩個標(biāo)簽還有如下注意事項(xiàng):
colgroup需在 table 標(biāo)簽中col需在 colgroup 標(biāo)簽中,且只能包含 標(biāo)簽- 兩者均無法為表格創(chuàng)建列,僅控制列的展現(xiàn)形式
- 在 xhtml 中,
col必須含有結(jié)束標(biāo)簽
根據(jù)我們的需求,我們需要單獨(dú)控制每一列的寬度展示,并在瀏覽器寬度變化時實(shí)時的重新計(jì)算并且重新渲染列。
大致的功能如下:
- 含有
width的列,寬度固定,不隨瀏覽器寬度變化而變化 - 含有
minWidth的列,在大于設(shè)定值時,自動填充 table 剩余寬度,小于設(shè)定值時,固定該寬度 - 不包含
width和minWidth的列,自動填充 table 剩余寬度
最終實(shí)現(xiàn)如下渲染效果:
<template>
<colgroup>
<col
v-for="(item, index) in columns"
:key="`table-tr-${index}`"
:name="`table_tr_${index}`"
:width="`${item.width}px`"
/>
</colgroup>
</template>核心實(shí)現(xiàn)
一些常量/變量定義
在 Table 組件初始化的時候,需要定義一些變量以供后續(xù)方法中使用,具體如下:
/** Table 實(shí)例 */
const bpTable = ref(null);
/** 最終用于渲染的 columns 表頭列表 */
const columns = ref([]);
/** 表格所占的實(shí)際寬度 px */
const _table_width = ref("");
/** 在沒有設(shè)定寬度時,可用于撐開剩余寬度的列數(shù) */
let _remainder_col = 0;
/** 固定寬度(包含自定義的寬和最小寬的總和) */
let _fixed_width = 0;
/** 各列最小寬度數(shù)組 */
let _min_width_list = [];
/** 表格各列寬度數(shù)組 */
let _col_width_list = [];
/** 單列最小寬度 */
const _min_column_width = 80;初始化表頭列表 initColumns
在表格整體渲染結(jié)束,能獲取 table 實(shí)際寬度后,需要執(zhí)行表頭列表初始化,對傳入的props中的cols進(jìn)行處理,計(jì)算實(shí)際每一列需要width值。
/**
* 初始化表頭列表
* @returns Array
*/
const initColumns = () => {
const el = bpTable.value;
const { cols } = props;
/** 每次需要初始化的一些值 */
_fixed_width = 0;
_remainder_col = cols.length;
_min_width_list = [];
// 1. 處理含有固定寬度和最小寬的列
// 2. 獲取各列寬度,并組成一個數(shù)組
// 計(jì)算需要自適應(yīng)的列寬度
// 3. 輸出 columns
}處理含有固定寬度和最小寬的列
如果含有自定義的寬和最小寬,則需要單獨(dú)處理這些列,使其不參與剩余寬度自適應(yīng)當(dāng)中,同時對應(yīng)的自適應(yīng)列的數(shù)量也要相應(yīng)的減去,處理邏輯如下:
for (let i = 0; i < cols.length; i++) {
const { width, minWidth } = cols[i];
if (width) {
_fixed_width += Number(width);
_remainder_col--;
}
minWidth && _min_width_list.push(minWidth)
}獲取各列寬度,并組成一個數(shù)組 getWidthList
這個方法目的返回一個數(shù)組,包含各列的寬度值,最后匹配到columns中。 為了不出現(xiàn)列寬過于太小而把內(nèi)容擠掉的情況,需要判斷最小值不能小于設(shè)定的80px。
/**
* 獲取各列寬度,并組成一個數(shù)組
* @returns Array width_list
*/
function getWidthList() {
const { cols } = props;
/** 各列寬度數(shù)組 */
let width_list = [];
/** 自適應(yīng)列寬 */
let adapt_width = getAdaptWidth();
/**
* 當(dāng)表格中含有設(shè)置最小寬度的列時,需要挨個比較自適應(yīng)寬是否小于最小寬度
* 如果小于,則重新設(shè)置各個值并重新計(jì)算自適應(yīng)寬度
*/
if (_min_width_list.length) {
_min_width_list.map((item, index) => {
if (adapt_width > item) {
_fixed_width += item;
_remainder_col--;
_min_width_list.splice(index, 1);
adapt_width = getAdaptWidth();
}
});
}
for (let i = 0; i < cols.length; i++) {
const { width, minWidth } = cols[i];
// 設(shè)置成固定寬度
if (width) { width_list.push(width); continue; }
// 是否設(shè)置成最小寬度:當(dāng)含有最小寬度屬性并且最小寬度大于計(jì)算得出的最大列寬
const hasMinWidth = minWidth && minWidth > adapt_width;
if (hasMinWidth) { width_list.push(minWidth); continue; }
// 如果沒有定義寬度和最小寬,則設(shè)置成自適應(yīng)寬度或者最小預(yù)設(shè)寬度
width_list.push(adapt_width < _min_column_width ? _min_column_width : adapt_width);
}
return width_list;
}計(jì)算需要自適應(yīng)的列寬度 getAdaptWidth
在表格整體渲染結(jié)束,能獲取 table 實(shí)際寬度后,需要計(jì)算允許列自適應(yīng)的寬度有多少,如果所有列都沒有設(shè)置寬度值,這時候自適應(yīng)的列寬即為 table 的實(shí)際寬度,列寬平均分布就行了。
/**
* 根據(jù)表格實(shí)際寬度、已固定的列寬、以及剩余自適應(yīng)列數(shù),計(jì)算得出自適應(yīng)列寬
* @returns Number width
*/
function getAdaptWidth() {
let width = (_table_width.value - _fixed_width) / _remainder_col;
return Number(width).toFixed(2);
}
```
#### 完整代碼
```javascript
/**
* 獲取各列寬度,并組成一個數(shù)組
* @returns Array width_list
*/
function getWidthList() {
const { cols } = props;
/** 各列寬度數(shù)組 */
let width_list = [];
/** 自適應(yīng)列寬 */
let adapt_width = getAdaptWidth();
/**
* 當(dāng)表格中含有設(shè)置最小寬度的列時,需要挨個比較自適應(yīng)寬是否小于最小寬度
* 如果小于,則重新設(shè)置各個值并重新計(jì)算自適應(yīng)寬度
*/
if (_min_width_list.length) {
_min_width_list.map((item, index) => {
if (adapt_width > item) {
_fixed_width += item;
_remainder_col--;
_min_width_list.splice(index, 1);
adapt_width = getAdaptWidth();
}
});
}
for (let i = 0; i < cols.length; i++) {
const { width, minWidth } = cols[i];
// 設(shè)置成固定寬度
if (width) { width_list.push(width); continue; }
// 是否設(shè)置成最小寬度:當(dāng)含有最小寬度屬性并且最小寬度大于計(jì)算得出的最大列寬
const hasMinWidth = minWidth && minWidth > adapt_width;
if (hasMinWidth) { width_list.push(minWidth); continue; }
// 如果沒有定義寬度和最小寬,則設(shè)置成自適應(yīng)寬度或者最小預(yù)設(shè)寬度
width_list.push(adapt_width < _min_column_width ? _min_column_width : adapt_width);
}
return width_list;
}監(jiān)聽屏幕變化和屬性更新
觸發(fā)initColumns的時機(jī)有三個
- 初次加載表格組件
- 列屬性有更新時
- 屏幕寬度變化時
watch(() => props.cols, () => { initColumns() });
onMounted(() => {
nextTick(() => {
initColumns();
on(window, 'resize', throttle(() => initColumns(), 400));
});
});
onBeforeUnmount(() => off(window, 'resize', () => initColumns()));到此這篇關(guān)于vue.js Table 組件自定義列寬實(shí)現(xiàn)核心方法的文章就介紹到這了,更多相關(guān)vue.js Table 組件自定義內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解vuex中的this.$store.dispatch方法
這篇文章主要介紹了vuex中的this.$store.dispatch方法,必須要用commit(‘SET_TOKEN’,?tokenV)調(diào)用mutations里的方法,才能在store存儲成功,需要的朋友可以參考下2022-11-11
vue中radio根據(jù)動態(tài)值綁定checked無效的解決
這篇文章主要介紹了vue中radio根據(jù)動態(tài)值綁定checked無效的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
Vue網(wǎng)絡(luò)請求的三種實(shí)現(xiàn)方式介紹
這篇文章主要介紹了Vue網(wǎng)絡(luò)請求的三種實(shí)現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09
Vue?3.0?v-for中的Ref數(shù)組用法小結(jié)
在?Vue?2?中,在?v-for?里使用的?ref?attribute會用ref?數(shù)組填充相應(yīng)的?$refs?property,本文給大家介紹Vue?3.0?v-for中的Ref數(shù)組的相關(guān)知識,感興趣的朋友一起看看吧2023-12-12
Vue3中Vite和Vue-cli的特點(diǎn)與區(qū)別詳解
vue-cli是Vue早期推出的一款腳手架,使用webpack創(chuàng)建Vue項(xiàng)目,可以選擇安裝需要的各種插件,比如Vuex、VueRouter,下面這篇文章主要給大家介紹了關(guān)于Vue3中Vite和Vue-cli的特點(diǎn)與區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-12-12

