序言
在上篇文章中,我們完成了滾動條組件開發的前期準備工作,包括理論推導、布局規劃和基礎設置。現在,我們將把這些準備轉化為實際代碼,開啟滾動條組件的具體開發之旅🌟。我們會詳細闡述如何實現各項功能,解決開發中的技術挑戰,為用戶帶來更好的滾動體驗🌐。
滾動條
在設計滾動條組件時,我們需要考慮橫向和縱向兩個方向的滾動條。這兩個方向的滾動條在功能實現和表現形式上有諸多相似之處,但也存在一些細微的差異。為了提高代碼的可維護性、可復用性和可擴展性,我們決定將滾動條單獨提取出來,作為一個獨立的組件進行開發。基于此,我們在?packages/components/scrollbar/src
?目錄下創建了?bar.ts
?和?bar.vue
?文件,它們將作為實現滾動條功能的核心文件,為后續的開發工作提供強有力的支撐 🏗?。
bar.ts
import { ExtractPropTypes } from 'vue'
import { useDirectionProp } from '@nova-ui/hooks'
import type bar from './bar.vue'export const barProps = {direction: useDirectionProp(),always: Boolean,
} as constexport type BarType = ExtractPropTypes<typeof barProps>export type BarInstance = InstanceType<typeof bar>
在?bar.ts
?文件中,barProps
?包含?direction
?和?always
?兩個屬性。direction
?用于確定滾動條的方向,并且可以在其他組件中復用 🔄。always
?這個屬性用于控制滾動條是否始終顯示,以此來滿足不同的使用場景 🔧。通過?InstanceType<typeof bar>
?導出的?BarInstance
?類型,有助于在操作滾動條組件實例時確保類型的準確性,避免出現類型錯誤,而且會在?scrollbar
?組件中使用 🌟。
bar.vue
<template><divv-show="visible"ref="barRef":class="[n.b(),n.m(direction),n.is('always', always)]"><divref="thumbRef":class="n.e('thumb')"></div></div>
</template><script lang="ts" setup>
const n = useNamespace('bar')
defineOptions({name: 'NBar',
})
const props = defineProps(barProps)
</script>
bar.vue
?的基本 DOM 結構由兩個?div
?元素組成,一個作為軌道,另一個作為滑塊。首先,我們會定義以下幾個重要的變量:
size
:用于存儲滑塊的長或寬,方便后續的樣式調整 📏。ratio
:表示視圖區域與可視區域的比例,這是計算滑塊大小的關鍵數據 🔢。visible
:決定滾動條是否顯示,會根據不同的情況進行調整 👁?。distance
:表示滑塊滾動的距離,它會根據用戶的操作而變化呢 📏。
滑塊大小計算
我們需要獲取視圖區域和可視區域的 DOM 元素。在?scrollbar
?組件中通過?provide
?傳遞,在?bar
?組件中通過?inject
?獲取,以下是以縱向滾動條為例的代碼,完整代碼可查看相應的倉庫 🔍。
const scrollbar = inject(scrollbarInjectionKey)
const visible = ref(false)
const size = ref(0)
const ratio = ref(1)const updateHandler = () => {const wrap = scrollbar?.wrapElementif (!wrap) returnconst { offsetHeight, scrollHeight } = wrapconst _ratio = offsetHeight / scrollHeightconst height = _ratio * offsetHeightsize.value = heightratio.value = _ratiovisible.value = offsetHeight < scrollHeight
}
通過上述計算,我們可以得到所需的數值,進而為滑塊添加合適的樣式 🌟。
const thumbStyle = computed(() => {return {[props.direction === 'vertical' ? 'height' : 'width']: size.value ? addUnit(size.value) : undefined}
})
滑塊滾動距離
在完成滑塊大小的計算和相關屬性的獲取之后,我們要計算滑塊滾動的距離 🔢。
const scrollHandler = () => {const wrap = scrollbar?.wrapElementif (!wrap) returndistance.value = wrap.scrollTop * ratio.value
}
這個計算很簡單,就是將視圖區域滾動的距離與比例相乘。根據這個結果,我們將修改滑塊的樣式:
const thumbStyle = computed(() => {return {[props.direction === 'vertical' ? 'height' : 'width']: size.value ? addUnit(size.value) : undefined,transform: `translate${ props.direction === 'vertical' ? 'Y' : 'X' }(${ distance.value }px)`}
})
至此,基本功能已成型 👏。接下來,我們來看看如何觸發這些方法。
scrollbar
更新 bar
的 滑塊
在 VNode 更新之后,我們需要調用相應的方法,這里使用?onUpdated
?生命周期來完成。為了更好地兼容不同的場景,當視圖區域大小發生變化時,我們會使用?useResizeObserver
?來監聽 DOM 變化并調用?updateHandler
?。
const update = () => {barUpdateHandler()barScrollHandler()
}let stopResizeObserver: (() => void) | undefined = undefined
watch(() => props.noresize, (noresize) => {if (noresize) {stopResizeObserver?.()} else {const { stop } = useResizeObserver(wrapRef as unknown as MaybeComputedElementRef, update)stopResizeObserver = stop}
}, { immediate: true })onUpdated(() => {update()
})
scrollbar
更新 bar
的 滾動距離
在設置好滑塊的大小之后,我們需要處理滾動距離。我們會對滾動區域進行監聽,觸發?bar
?的相關函數。
const barScrollHandler = () => {barVerticalRef.value?.scroll()barHorizontalRef.value?.scroll()
}
const onScroll = () => {barScrollHandler()emits('scroll', {scrollTop: wrapRef.value?.scrollTop || 0,scrollLeft: wrapRef.value?.scrollLeft || 0,})
}
🦀🦀感謝看官看到這里,如果覺得文章不錯的話🙌,點個關注不迷路?。
誠邀您加入我的微信技術交流群🎉,群里都是志同道合的開發者👨?💻,大家能一起交流分享摸魚🐟。期待與您在群里相見🚀,咱們攜手在開發路上共同進步? !
👉點我
感謝各位大俠一路相伴,實在感激! 不瞞您說,在下還有幾個開源項目 📦,它們就像精心培育的幼苗 🌱,急需您的澆灌。要是您瞧著還不錯,麻煩動動手指,給它們點亮幾顆 Star ?,您的支持就是它們成長的最大動力,在此謝過各位大俠啦!
Nova UI
組件庫:https://github.com/gmingchen/nova-ui- 基于 Vue3 + Element-plus 管理后臺基礎功能框架
- 預覽:https://admin.gumingchen.icu
- Github:https://github.com/gmingchen/agile-admin
- Gitee:https://gitee.com/shychen/agile-admin
- 基礎版后端:https://github.com/gmingchen/java-spring-boot-admin
- 文檔:http://admin.gumingchen.icu/doc/
- 基于 Vue3 + Element-plus + websocket 即時聊天系統
- 預覽:https://chatterbox.gumingchen.icu/
- Github:https://github.com/gmingchen/chatterbox
- Gitee:https://gitee.com/shychen/chatterbox
- 基于 node 開發的后端服務:https://github.com/gmingchen/node-server