
Element Plus Scrollbar 組件完全指南替換原生滾動條、手動控制與無限滾動【免費下載鏈接】element-plus A Vue.js 3 UI Library made by Element team項目地址: https://gitcode.com/GitHub_Trending/el/element-plusElement Plus 的Scrollbar滾動條組件用于替換瀏覽器原生滾動條提供跨平臺一致的外觀與交互同時保留原生滾動行為。它廣泛服務于 el-table、el-select、el-cascader、el-tree 等組件內部也是業務中實現隱藏原生滾動條 自定義美觀滾動條的通用方案。讀完本文你將掌握其全部配置屬性、事件與方法能實現固定高度滾動、橫向滾動、按內容自適應高度、手動/編程式滾動控制以及基于end-reached事件的無限滾動加載。本文以倉庫內文檔 docs/en-US/component/scrollbar.md 為主體并結合組件源碼與測試用例補充底層實現細節。基本用法用 height 固定滾動區域Scrollbar通過height屬性設定滾動區域高度未設置時則按父容器高度自適應。文檔示例basic-usage.vue如下template el-scrollbar height400px p v-foritem in 20 :keyitem classscrollbar-demo-item{{ item }}/p /el-scrollbar /template style scoped .scrollbar-demo-item { display: flex; align-items: center; justify-content: center; height: 50px; margin: 10px; text-align: center; border-radius: 4px; background: var(--el-color-primary-light-9); color: var(--el-color-primary); } /styleheight同時支持string與number兩種類型如400px或400。從源碼看該屬性最終通過addUnit統一補全單位后應用到內部 wrap 容器上見 scrollbar.vue 中的wrapStyle計算邏輯const wrapStyle computedStyleValue(() { const style: CSSProperties {} const height addUnit(props.height) const maxHeight addUnit(props.maxHeight) if (height) style.height height if (maxHeight) style.maxHeight maxHeight return [props.wrapStyle, style] })值得注意即使未顯式傳入height只要父容器給出了確定高度并允許子元素滾動Scrollbar同樣可以工作——它內部沒有對高度做強制斷言而是完全由實際渲染的 wrap 容器尺寸驅動滾動條計算。橫向滾動當內容寬度超過滾動條寬度時會自動出現橫向滾動條。文檔示例horizontal-scroll.vue通過flex布局撐寬內容并配合flex-shrink: 0防止子項被壓縮template el-scrollbar div classscrollbar-flex-content p v-foritem in 50 :keyitem classscrollbar-demo-item{{ item }}/p /div /el-scrollbar /template style scoped .scrollbar-flex-content { display: flex; width: fit-content; } .scrollbar-demo-item { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 100px; height: 50px; margin: 10px; border-radius: 4px; background: var(--el-color-danger-light-9); color: var(--el-color-danger); } /stylewidth: fit-content讓內容容器寬度隨子元素自適應從而產生超出可視區的橫向溢出。組件內部把橫向與縱向滾動條分開渲染bar.vue同時渲染一個水平Thumb和一個垂直Thumb見 bar.vue各自獨立計算位移與尺寸因此兩個方向的滾動可以共存。最大高度與自適應收起max-height允許滾動條按需出現內容未超出最大高度時不顯示滾動條超出后才出現。文檔示例max-height.vue配合動態增刪列表演示了這一行為template el-button clickaddAdd Item/el-button el-button clickonDeleteDelete Item/el-button el-scrollbar max-height400px p v-foritem in count :keyitem classscrollbar-demo-item{{ item }}/p /el-scrollbar /template script langts setup import { ref } from vue const count ref(3) const add () { count.value } const onDelete () { if (count.value 0) { count.value-- } } /script實現層面height/max-height的變化會觸發專門的監聽組件watch這兩個屬性在非native模式下于nextTick后調用update()重新測量內容并刷新滾動條見 scrollbar.vue。這是max-height模式下內容增減后滾動條尺寸/顯示狀態正確刷新的關鍵機制。手動控制滾動setScrollTop / setScrollLeft / scrollToScrollbar將滾動方法通過defineExpose暴露給父組件見 scrollbar.vue從而可以在任意時機編程式控制滾動位置。文檔示例manual-scroll.vue用滑塊驅動滾動template el-scrollbar refscrollbarRef height400px always scrollscroll div refinnerRef p v-foritem in 20 :keyitem classscrollbar-demo-item{{ item }}/p /div /el-scrollbar el-slider v-modelvalue :maxmax :format-tooltipformatTooltip inputinputSlider / /template script langts setup import { onMounted, ref } from vue import type { ScrollbarInstance } from element-plus const max ref(0) const value ref(0) const innerRef refHTMLDivElement() const scrollbarRef refScrollbarInstance() onMounted(() { max.value innerRef.value!.clientHeight - 380 }) const inputSlider (value: number) { scrollbarRef.value!.setScrollTop(value) } const scroll ({ scrollTop }: { scrollTop: number }) { value.value scrollTop } /script組件對外暴露的方法匯總如下方法說明簽名setScrollTop設置滾動到頂部的距離垂直方向(scrollTop: number) voidsetScrollLeft設置滾動到左側的距離水平方向(scrollLeft: number) voidscrollTo滾動到指定坐標支持兩種重載(options: ScrollToOptions) void或(x: number, y: number) voidupdate手動更新滾動條狀態如內容動態變化后重新測量() voidhandleScroll處理滾動事件內部方法也可手動觸發以同步滾動條() voidwrapRef內部滾動 wrap 容器的 DOM 引用RefHTMLDivElementsetScrollTop/setScrollLeft對入參做了嚴格校驗非數字時會通過debugWarn發出value must be a number的警告并直接返回避免產生無效賦值見 scrollbar.vue。scrollTo則直接透傳給 wrap 容器的原生scrollTo支持ScrollToOptions與(x, y)兩種調用形式scrollbar.vue。無限滾動end-reached 事件從 2.10.0 版本開始Scrollbar新增了end-reached事件當滾動到達末尾時觸發可用于實現無限滾動觸底加載更多。文檔示例infinite-scroll.vue如下template el-scrollbar height400px end-reachedloadMore p v-foritem in num :keyitem classscrollbar-demo-item{{ item }}/p /el-scrollbar /template script langts setup import { ref } from vue import type { ScrollbarDirection } from element-plus const num ref(30) const loadMore (direction: ScrollbarDirection) { if (direction bottom) { num.value 5 } } /scriptend-reached的回調參數direction為top | bottom | left | right即到達的是哪個方向可按需決定加載策略如僅bottom時加載下一頁。事件類型定義見 scrollbar.ts。distance觸發距離閾值從 2.10.5 版本開始distance屬性默認0用于設置距離邊緣多少像素時提前觸發end-reached。這在即將觸底時預加載下一批數據的場景非常實用可以讓加載過程對用戶無感。distance大于0時handleScroll會基于scrollHeight - distance clientHeight scrollTop之類的判定提前報告到達見 scrollbar.vueconst arrivedStates { bottom: !isGreaterThan( wrapRef.value.scrollHeight - props.distance, wrapRef.value.clientHeight wrapScrollTop ), top: wrapScrollTop props.distance prevTop ! 0, right: !isGreaterThan( wrapRef.value.scrollWidth - props.distance, wrapRef.value.clientWidth wrapScrollLeft ) prevLeft ! wrapScrollLeft, left: wrapScrollLeft props.distance prevLeft ! 0, }組件內部還維護了distanceScrollState方向狀態機通過DIRECTION_PAIRS在到達某端與離開對端之間做去重只有從非到達狀態切入到達狀態時才會觸發一次end-reached從而避免在末尾反復滾動時重復觸發scrollbar.vue。組件結構與渲染原理Scrollbar的模板結構非常清晰見 scrollbar.vuediv classel-scrollbar div classel-scrollbar__wrap tabindex... component :istag classel-scrollbar__view !-- slot -- /component /div template v-if!native bar :alwaysalways :min-sizeminSize / /template /divwrap真正發生滾動的容器類名el-scrollbar__wrap非native模式下會追加el-scrollbar__wrap--hidden-default類以隱藏原生滾動條scrollbar.vueview內容視圖容器類名el-scrollbar__view其標簽類型由tag屬性決定默認div可改為ul、section等bar僅在非native模式下渲染的自定義滾動條內部再拆分為水平 / 垂直兩個thumb滑塊。組件通過provide(scrollbarContextKey)向bar提供scrollbarElement與wrapElement引用實現父子模塊間通信scrollbar.vue。滾動條尺寸與位移的計算自定義滾動條滑塊的長度和位移由 bar.vue 中的update計算const originalHeight offsetHeight ** 2 / wrap.scrollHeight const originalWidth offsetWidth ** 2 / wrap.scrollWidth const height Math.max(originalHeight, props.minSize) const width Math.max(originalWidth, props.minSize)滑塊長度近似為可視區高度2 / 內容總高度即內容越長滑塊越短并受min-size默認 20px兜底防止內容過長時滑塊過小難以點擊。位移則在滾動時按(scrollTop * 100 / offsetHeight) * ratio換算為百分比 transformbar.vue。容器兩端各留 2px 邊距即 util.ts 中的GAP 4垂直/水平方向的關鍵屬性名統一封裝在BAR_MAPutil.ts中滑塊樣式由renderThumbStyle生成export const renderThumbStyle ({ move, size, bar }): CSSProperties ({ [bar.size]: size, transform: translate${bar.axis}(${move}%), })這些計算均有對應測試佐證。在 scrollbar.test.tsx 的垂直滾動測試中外層 204px、內層 500px 時滾動 100px斷言滑塊樣式包含transform: translateY(50%); height: 80px;精確驗證了上述公式水平方向測試同樣斷言translateX(50%); width: 80px;。響應式更新與 noresize 優化組件默認通過useResizeObserver同時監聽 view 容器與 wrap 容器的尺寸變化并監聽全局window resize事件任一變化都會調用update重算滾動條scrollbar.vue。noresize置為true時則停止所有這些監聽——如果你的容器尺寸確定不變建議開啟它以優化性能此時若內容仍會變化可手動調用暴露的update()刷新。此外組件還會監聽 wrap 的transitionend與animationend事件來更新滾動條以覆蓋 transform 驅動的過渡/動畫場景如幻燈片切換中尺寸觀測不到的問題scrollbar.vue。組件在onMounted、onUpdated時都會刷新滾動條并在onActivated配合KeepAlive時恢復之前記錄的scrollTop/scrollLeftscrollbar.vue。API 參考以下 API 表完全繼承自 docs/en-US/component/scrollbar.md并結合 scrollbar.ts 的源碼補充了類型與默認值細節。Attributes名稱說明類型默認值height滾動條高度string / number—max-height滾動條最大高度string / number—native是否使用原生滾動條樣式booleanfalsewrap-stylewrap 容器的樣式string / objectCSSProperties \| CSSProperties[] \| string[]—wrap-classwrap 容器的類名string—view-styleview 容器的樣式string / object同上—view-classview 容器的類名string—noresize不響應容器尺寸變化若容器尺寸不變建議開啟以優化性能booleanfalsetagview 容器的元素標簽stringdivalways是否始終顯示滾動條booleanfalsemin-size滾動條最小尺寸number20id2.4.0view 容器的 idstring—role2.4.0a11yview 容器的 rolestring—aria-label2.4.0a11yview 容器的 aria-labelstring—aria-orientation2.4.0a11yview 容器的 aria-orientationenumhorizontal \| vertical—tabindex2.8.3wrap 容器的 tabindexnumber / string—distance2.10.5觸發end-reached的距離閾值pxnumber0其中wrap-style/view-style在源碼中通過definePropTypeStyleValue([String, Object, Array, Boolean])定義因此除字符串外也支持 CSSProperties 對象與數組wrap-class/view-class同理支持類名字符串、數組與對象。ariaLabel/ariaOrientation經由useAriaProps注入scrollbar.ts。Events名稱說明類型scroll滾動時觸發返回滾動距離({ scrollLeft: number, scrollTop: number }) voidend-reached2.10.0滾動到末尾時觸發(direction: top \| bottom \| left \| right) voidscroll事件在每次滾動時都會攜帶當前的scrollTop與scrollLeftscrollbar.vue可用于實現滾動監聽 雙向同步如前述手動滾動示例中的滑塊回顯。Slots名稱說明default自定義滾動區域內容Exposes通過 ref 訪問名稱說明類型handleScroll處理滾動事件() voidscrollTo滾動到指定坐標(options: ScrollToOptions \| number, yCoord?: number) voidsetScrollTop設置滾動到頂部距離(scrollTop: number) voidsetScrollLeft設置滾動到左側距離(scrollLeft: number) voidupdate手動更新滾動條狀態() voidwrapRef滾動條 wrap 容器引用RefHTMLDivElement無障礙與鍵盤支持從 2.4.0 起組件補齊了無障礙相關屬性role、aria-label、aria-orientation會透傳到 view 容器上從 2.8.3 起tabindex可作用到 wrap 容器使滾動區域本身可被鍵盤聚焦。這意味著你可以將滾動區域標識為roleregion并給出aria-label描述讓屏幕閱讀器用戶也能理解該區域的語義配合tabindex后用戶可通過方向鍵在可滾動區域內聚焦并滾動符合現代可訪問性實踐。使用建議小結固定高度區域使用height如height400px滾動條出現與否由內容是否溢出自動決定自適應收起使用max-height內容少時無滾動條、內容多時自動出現橫向內容內容寬度超過容器時自動出現水平滾動條配合flex與width: fit-content實現編程控制通過模板 ref 調用setScrollTop/setScrollLeft/scrollTo并在需要時調用update()強制刷新無限滾動監聽end-reached并按需使用distance提前預加載注意事件的方向去重邏輯無需擔心重復觸發性能容器尺寸固定不變時設置noresize避免冗余的 ResizeObserver 與 resize 監聽開銷。如果你只需要純原生的滾動條外觀不追求跨瀏覽器統一的自定義樣式將native設為true即可完全跳過自定義滾動條的渲染分支。【免費下載鏈接】element-plus A Vue.js 3 UI Library made by Element team項目地址: https://gitcode.com/GitHub_Trending/el/element-plus創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考