vue.js?Table?組件自定義列寬實現(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)填充剩余寬度。
如果你打算自己手動實現(xiàn)一個 Table 組件,并且對支持定義列寬屬性的實現(xiàn)毫無頭緒,那這篇文章大概率可以幫你梳理一些邏輯和核心方法的實現(xiàn)(Vue3)
注:這也許不是最佳的實現(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)簽還有如下注意事項:
colgroup
需在 table 標(biāo)簽中col
需在 colgroup 標(biāo)簽中,且只能包含 標(biāo)簽- 兩者均無法為表格創(chuàng)建列,僅控制列的展現(xiàn)形式
- 在 xhtml 中,
col
必須含有結(jié)束標(biāo)簽
根據(jù)我們的需求,我們需要單獨控制每一列的寬度展示,并在瀏覽器寬度變化時實時的重新計算并且重新渲染列。
大致的功能如下:
- 含有
width
的列,寬度固定,不隨瀏覽器寬度變化而變化 - 含有
minWidth
的列,在大于設(shè)定值時,自動填充 table 剩余寬度,小于設(shè)定值時,固定該寬度 - 不包含
width
和minWidth
的列,自動填充 table 剩余寬度
最終實現(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>
核心實現(xiàn)
一些常量/變量定義
在 Table 組件初始化的時候,需要定義一些變量以供后續(xù)方法中使用,具體如下:
/** Table 實例 */ const bpTable = ref(null); /** 最終用于渲染的 columns 表頭列表 */ const columns = ref([]); /** 表格所占的實際寬度 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 實際寬度后,需要執(zhí)行表頭列表初始化,對傳入的props
中的cols
進(jìn)行處理,計算實際每一列需要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ù)組 // 計算需要自適應(yīng)的列寬度 // 3. 輸出 columns }
處理含有固定寬度和最小寬的列
如果含有自定義的寬和最小寬,則需要單獨處理這些列,使其不參與剩余寬度自適應(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è)置各個值并重新計算自適應(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)含有最小寬度屬性并且最小寬度大于計算得出的最大列寬 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; }
計算需要自適應(yīng)的列寬度 getAdaptWidth
在表格整體渲染結(jié)束,能獲取 table 實際寬度后,需要計算允許列自適應(yīng)的寬度有多少,如果所有列都沒有設(shè)置寬度值,這時候自適應(yīng)的列寬即為 table 的實際寬度,列寬平均分布就行了。
/** * 根據(jù)表格實際寬度、已固定的列寬、以及剩余自適應(yīng)列數(shù),計算得出自適應(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è)置各個值并重新計算自適應(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)含有最小寬度屬性并且最小寬度大于計算得出的最大列寬 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 組件自定義列寬實現(xiàn)核心方法的文章就介紹到這了,更多相關(guān)vue.js Table 組件自定義內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue中的v-for循環(huán)key屬性注意事項小結(jié)
這篇文章主要介紹了Vue中的v-for循環(huán)key屬性注意事項小結(jié),非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-08-08vue循環(huán)中點擊選中再點擊取消(單選)的實現(xiàn)
這篇文章主要介紹了vue循環(huán)中點擊選中再點擊取消(單選)的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09vue最強(qiáng)table vxe-table 虛擬滾動列表 前端導(dǎo)出問題分析
最近遇到個問題,后臺一次性返回2萬條列表數(shù)據(jù)并且需求要求所有數(shù)據(jù)必須全部展示,不能做假分頁,怎么操作呢,下面通過本文介紹下vue最強(qiáng)table vxe-table 虛擬滾動列表 前端導(dǎo)出問題,感興趣的朋友一起看看吧2023-10-10淺談關(guān)于.vue文件中style的scoped屬性
本篇文章主要主要介紹了淺談關(guān)于.vue文件中style的scoped屬性,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08daisyUI解決TailwindCSS堆砌class問題詳解
這篇文章主要為大家介紹了daisyUI解決TailwindCSS堆砌class問題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07