vue.js?Table?組件自定義列寬實(shí)現(xiàn)核心方法
前言
如果你使用過(guò)類似于 ElementUI 的組件庫(kù),一定對(duì)如下的 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)填充剩余寬度。
如果你打算自己手動(dòng)實(shí)現(xiàn)一個(gè) Table 組件,并且對(duì)支持定義列寬屬性的實(shí)現(xiàn)毫無(wú)頭緒,那這篇文章大概率可以幫你梳理一些邏輯和核心方法的實(shí)現(xiàn)(Vue3)
注:這也許不是最佳的實(shí)現(xiàn)方案。
準(zhǔn)備工作:
這里假定使用的是類似于and-design for vue
的屬性傳值方式,即列的屬性配置是通過(guò)額外的數(shù)組對(duì)象傳入的。
除了title
-列表頭名,key
-列值對(duì)應(yīng)的鍵外,還有這篇文章涉及到的最小寬度minWidth
和固定寬度width
,并通過(guò)組件屬性cols
傳入。
colgroup 和 col
這里需要用到<colgroup>
和<col>
標(biāo)簽,以便更好的去控制每列的屬性信息,兩個(gè)標(biāo)簽均支持傳入width
屬性控制列寬度,不同的是,<col>
控制的是單列的寬度,而<colgroup>
可以控制所包含在內(nèi)的。
除此之外,這兩個(gè)標(biāo)簽還有如下注意事項(xiàng):
colgroup
需在 table 標(biāo)簽中col
需在 colgroup 標(biāo)簽中,且只能包含 標(biāo)簽- 兩者均無(wú)法為表格創(chuàng)建列,僅控制列的展現(xiàn)形式
- 在 xhtml 中,
col
必須含有結(jié)束標(biāo)簽
根據(jù)我們的需求,我們需要單獨(dú)控制每一列的寬度展示,并在瀏覽器寬度變化時(shí)實(shí)時(shí)的重新計(jì)算并且重新渲染列。
大致的功能如下:
- 含有
width
的列,寬度固定,不隨瀏覽器寬度變化而變化 - 含有
minWidth
的列,在大于設(shè)定值時(shí),自動(dòng)填充 table 剩余寬度,小于設(shè)定值時(shí),固定該寬度 - 不包含
width
和minWidth
的列,自動(dòng)填充 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 組件初始化的時(shí)候,需要定義一些變量以供后續(xù)方法中使用,具體如下:
/** Table 實(shí)例 */ const bpTable = ref(null); /** 最終用于渲染的 columns 表頭列表 */ const columns = ref([]); /** 表格所占的實(shí)際寬度 px */ const _table_width = ref(""); /** 在沒(méi)有設(shè)定寬度時(shí),可用于撐開(kāi)剩余寬度的列數(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í)行表頭列表初始化,對(duì)傳入的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. 獲取各列寬度,并組成一個(gè)數(shù)組 // 計(jì)算需要自適應(yīng)的列寬度 // 3. 輸出 columns }
處理含有固定寬度和最小寬的列
如果含有自定義的寬和最小寬,則需要單獨(dú)處理這些列,使其不參與剩余寬度自適應(yīng)當(dāng)中,同時(shí)對(duì)應(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) }
獲取各列寬度,并組成一個(gè)數(shù)組 getWidthList
這個(gè)方法目的返回一個(gè)數(shù)組,包含各列的寬度值,最后匹配到columns
中。 為了不出現(xiàn)列寬過(guò)于太小而把內(nèi)容擠掉的情況,需要判斷最小值不能小于設(shè)定的80px
。
/** * 獲取各列寬度,并組成一個(gè)數(shù)組 * @returns Array width_list */ function getWidthList() { const { cols } = props; /** 各列寬度數(shù)組 */ let width_list = []; /** 自適應(yīng)列寬 */ let adapt_width = getAdaptWidth(); /** * 當(dāng)表格中含有設(shè)置最小寬度的列時(shí),需要挨個(gè)比較自適應(yīng)寬是否小于最小寬度 * 如果小于,則重新設(shè)置各個(gè)值并重新計(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; } // 如果沒(méi)有定義寬度和最小寬,則設(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)的寬度有多少,如果所有列都沒(méi)有設(shè)置寬度值,這時(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 /** * 獲取各列寬度,并組成一個(gè)數(shù)組 * @returns Array width_list */ function getWidthList() { const { cols } = props; /** 各列寬度數(shù)組 */ let width_list = []; /** 自適應(yīng)列寬 */ let adapt_width = getAdaptWidth(); /** * 當(dāng)表格中含有設(shè)置最小寬度的列時(shí),需要挨個(gè)比較自適應(yīng)寬是否小于最小寬度 * 如果小于,則重新設(shè)置各個(gè)值并重新計(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; } // 如果沒(méi)有定義寬度和最小寬,則設(shè)置成自適應(yīng)寬度或者最小預(yù)設(shè)寬度 width_list.push(adapt_width < _min_column_width ? _min_column_width : adapt_width); } return width_list; }
監(jiān)聽(tīng)屏幕變化和屬性更新
觸發(fā)initColumns
的時(shí)機(jī)有三個(gè)
- 初次加載表格組件
- 列屬性有更新時(shí)
- 屏幕寬度變化時(shí)
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
初識(shí)簡(jiǎn)單卻不失優(yōu)雅的Vue.js
這篇文章主要為大家介紹了簡(jiǎn)單卻不失優(yōu)雅、小巧而不乏大匠的Vue.js,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09vue全局過(guò)濾器概念及注意事項(xiàng)和基本使用方法
這篇文章主要給大家分享了vue全局過(guò)濾器概念及注意事項(xiàng)和基本使用方法,下面文字圍繞vue全局過(guò)濾器的相關(guān)資料展開(kāi)具體的詳細(xì)內(nèi)容,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-11-11如何解決ECharts圖表切換后縮成一團(tuán)的問(wèn)題
這篇文章主要介紹了如何解決ECharts圖表切換后縮成一團(tuán)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Vue中的v-for循環(huán)key屬性注意事項(xiàng)小結(jié)
這篇文章主要介紹了Vue中的v-for循環(huán)key屬性注意事項(xiàng)小結(jié),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08vue循環(huán)中點(diǎn)擊選中再點(diǎn)擊取消(單選)的實(shí)現(xiàn)
這篇文章主要介紹了vue循環(huán)中點(diǎn)擊選中再點(diǎn)擊取消(單選)的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09vue最強(qiáng)table vxe-table 虛擬滾動(dòng)列表 前端導(dǎo)出問(wèn)題分析
最近遇到個(gè)問(wèn)題,后臺(tái)一次性返回2萬(wàn)條列表數(shù)據(jù)并且需求要求所有數(shù)據(jù)必須全部展示,不能做假分頁(yè),怎么操作呢,下面通過(guò)本文介紹下vue最強(qiáng)table vxe-table 虛擬滾動(dòng)列表 前端導(dǎo)出問(wèn)題,感興趣的朋友一起看看吧2023-10-10淺談關(guān)于.vue文件中style的scoped屬性
本篇文章主要主要介紹了淺談關(guān)于.vue文件中style的scoped屬性,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08daisyUI解決TailwindCSS堆砌class問(wèn)題詳解
這篇文章主要為大家介紹了daisyUI解決TailwindCSS堆砌class問(wèn)題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07