Vue3 怎樣定製複雜組件的滾動條?仿生獅子
原生滾動條樣式一言難盡
公司項目需要用到多表頭等複雜的表格功能,一直使用 vxe-table 並在其基礎上定製開發。但相比 Element Plus 的表格,它有一個對界面來說很不友好的缺陷:不能自定義滾動條。使用原生滾動條會使表格右側多出一塊空白的區域,令人難受。
年前,我們要在一個新系統中畫甘特圖,用到了在 Github 極其流行的 vue-gantt-elastic。並不出乎意料,這玩意兒也不支持自定義滾動條。
也許大家沒見過 Windows 的滾動條樣式是到底有多麼齣戲。這裏截張圖給大家感受一下。
CSS 滾動條相關的規範如 CSS Scrollbars Styling Module 所規範的功能不多,甚至可以說太弱了。它只描述了一些用來簡單處理滾動條樣式的屬性,如寬度和顏色。考慮到 PC 端用戶使用鼠標,給滾動條加上動畫或鼠標交互也是完全合情合理的需求,所以依賴 CSS 滾動條規範完全不夠用。
但大佬對原生滾動條樣式不滿意,前端怎麼能說不行呢,改!(不是手癢癢了)
尋找簡單的解決方案
要把基礎庫依賴的 vxe-table 直接替換爲 Element Plus 表格很不現實。在沒做過表格調研的情況下就遷移基礎組件是不可接受的,何況我們只想改個滾動條樣式。
這是 ElTable 的示例。看着這漂亮的滾動條當時真是心癢癢呀!
講到 Element Plus,能不能用 ElScrollbar 組件做點什麼呢?
答案是否定的,因爲 ElScrollbar 只能處理簡單的滾動系統。
如圖所示,假設 ElScrollbar 組件 S 本身高 400px,其直接子元素 Children 高 1000px。這個場景足夠簡單,所以能輕易獲取 S 的滾動餘量有 600px。
當組件有複雜的層級嵌套時,ElScrollbar 組件就不知道你要使用哪一個元素去計算滾動餘量了。如圖所示,在複雜情況下,ElScrollbar 的虛擬滾動條甚至會和原生滾動條出現衝突的情況。
Use Scrollbars 的誕生
這段時間想了許多方法,也試了不少開源輪子,它們都不能滿足我 “一鍵替換” vxe-table 及 vue-gantt-elastic 滾動條樣式的需求。所以我找時間把溫習了一下瀏覽器滾動系統相關知識,並把需求精簡後,封裝出順手的工具,use-scrollbars
use-scrollbars 有以下幾個特點:
-
它支持定製複雜組件的滾動條樣式
-
它能提供比原生滾動條更豐富的樣式、動畫和交互效果
-
它使用原生滾動事件而不是 CSS Transform 等低性能滾動方案
-
它的狀態是響應式的且有完整的類型提示
第一點,也就是我的需求,use-scrollbars 能修改 vxe-table 等複雜組件的滾動條,這是 ElScrollbar 等其它開源組件目前無法實現的功能。第二點和第三點意味着更低的代碼複雜度。第四點是說 use-scrollbars 是用 TypeSript 實現的 Vue Hook...
使用示例
對於簡單的滾動系統,use-scrollbars 能做到 API 足夠簡單。
<template>
<div ref="elemRef">
long content long content ...
long content long content ...
long content long content ...
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useSrollbar } from 'use-scrollbars'
const elemRef = ref(null);
const barStates = useScrollbar(elemRef);
</script>
那怎麼使用 use-scrollbars 修改複雜的組件比如 vxe-table 呢?
代碼雖然沒有大家想象的那麼短,但一定是可以理解的。
第一步,使用 devtools 確認滾動系統,並在代碼中將相關元素選取出來。
const $table = tableRef.value.$el;
const $header = $table.querySelector(".vxe-table--header-wrapper");
const $bodyWrapper = $table.querySelector(".vxe-table--body-wrapper");
const $bodyContent = $table.querySelector(".vxe-table--body");
const $bodyXSpace = $table.querySelector(".vxe-body--x-space");
const $bodyYSpace = $table.querySelector(".vxe-body--y-space");
第二步,通過 use-scrollbars 初始化這些滾動系統。
const barStates = useScrollbar();
barStates.init({
mount: tableRef,
content: [$bodyWrapper, $bodyContent, $bodyXSpace, $bodyYSpace],
viewport: [$bodyWrapper]
});
第三步,調整樣式,適配虛擬滾動條。
.vxe-table--body-wrapper::-webkit-scrollbar {
width: 0;
height: 0;
}
// ... and more
最後,這是效果對比。
如果你是 vxe-table 用戶,在這裏可以找到我寫的示例組件,直接拷貝到項目中使用,普通表格和虛擬滾動的表格都支持。如果大家對使用 use-scrollbars 定製其它組件的滾動條有其它疑問,歡迎留言,我會逐一解答。
另,use-scrollbars 歡迎 Start & PR!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/kUP8d8bwgrxgqC0Kv6C0Sw