序言
在之前的内容中,我们已经深入探讨了滚动条组件开发的多个关键方面啦,包括前期准备工作的完成、核心功能的实现以及滑块大小和滚动距离的计算呢 🌟。通过这些步骤,我们已经成功搭建了一个具有基本功能的滚动条组件,为用户带来了初步的滚动体验。然而,滚动条组件的开发之旅尚未结束哦,我们将在本篇文章中继续深入完善这个组件,探索更高级的交互功能 🏗️。
拖动滑块与滚动区域
在一个完整的滚动条组件里,除了滑块的计算和基础滚动功能之外,用户期望获得更加流畅和直观的操作体验呢 👍。其中一个重要的部分就是能够通过拖动滑块来实现滚动区域的滚动 🔄。这不仅涉及到更加复杂的交互逻辑,还需要我们对用户的操作行为进行细致的监听和处理,同时还要考虑各种边界情况和性能优化 🔧。在本篇文章中,我们将详细阐述如何实现拖动滑块时与滚动区域的交互,让滚动条组件的功能更加完善,为用户带来更加出色的用户体验 🌐。
点击轨道滚动
当点击轨道时,我们需要计算出滚动区域需要滚动的距离,并设置相应的值。
const onBarMouseDown = (event: MouseEvent) => {
const wrap = scrollbar?.wrapElement
if (!wrap) return
if (props.direction === 'vertical') {
const scrollTop = (event.offsetY - size.value / 2) / ratio.value
wrap.scrollTop = scrollTop
} else if (props.direction === 'horizontal') {
const scrollLeft = (event.offsetX - size.value / 2) / ratio.value
wrap.scrollLeft = scrollLeft
}
}
设置了 scrollTop 之后,会触发 scrollbar 的滚动事件,该事件会调用 bar 组件的 scrollHandler 来计算滚动的距离。
这个函数 onBarMouseDown 主要是处理用户点击滚动条轨道时的操作哦 👆。当用户点击轨道时,我们会根据点击位置和滑块的尺寸大小,计算出滚动区域应该滚动的距离。对于垂直滚动条,会根据 event.offsetY(点击位置的 Y 坐标)和滑块尺寸的一半进行计算;对于水平滚动条,则依据 event.offsetX(点击位置的 X 坐标)和滑块尺寸的一半来计算呢 🔍。计算得到的结果会被设置到 wrap 的 scrollTop 或 scrollLeft 属性上,进而触发滚动,随后触发相关滚动事件,调用 scrollHandler 进行后续滚动距离的计算 🔄。
拖动滑块滚动
接下来处理滑块的拖动操作啦,它和点击轨道滚动有些类似哦,我们要计算拖动的距离,通过比例计算出视图区域滚动的记录并设置上 🔢。
const startMove = (event: MouseEvent) => {
const wrap = scrollbar?.wrapElement
if (!wrap) return
moveClient.value = props.direction === 'vertical' ? event.clientY : event.clientX
wrapScroll.value = props.direction === 'vertical' ? wrap.scrollTop : wrap.scrollLeft
event.stopImmediatePropagation()
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
document.onselectstart = () => false
}
const mouseMoveHandler = (event: MouseEvent) => {
const wrap = scrollbar?.wrapElement
if (!wrap || !barRef.value || !thumbRef.value) return
if (props.direction === 'vertical') {
const moveDistance = event.clientY - moveClient.value
const scrollTop = moveDistance / ratio.value + wrapScroll.value
wrap.scrollTop = scrollTop
} else if (props.direction === 'horizontal') {
const moveDistance = event.clientX - moveClient.value
const scrollLeft = moveDistance / ratio.value + wrapScroll.value
wrap.scrollLeft = scrollLeft
}
}
const mouseUpHandler = () => {
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
document.onselectstart = () => true
}
const onThumbMouseDown = (event: MouseEvent) => {
startMove(event)
}
在这部分代码里呢,我们主要关注的是用户拖动滑块的交互逻辑 👐。startMove 函数会在用户按下鼠标时触发,它会记录初始的鼠标位置和当前滚动位置,同时添加鼠标移动和鼠标松开的事件监听 🔔。mouseMoveHandler 函数负责在鼠标移动时更新滚动位置,它会根据鼠标的移动距离、比例和初始滚动位置计算新的滚动位置,然后将其应用到滚动区域 🔄。最后,mouseUpHandler 函数在用户松开鼠标时移除事件监听,恢复默认的文本选择行为 🔚。而 onThumbMouseDown 函数作为滑块按下事件的处理函数,会调用 startMove 开始拖动操作 🔛。
样式
@use 'mixins' as *;
$bar: #{$namespace}-bar;
$wrap: #{$namespace}-scrollbar__wrap;
@include b(scrollbar) {
@include set-variable(('scrollbar-thumb-size'), '6px');
@include set-variable(('scrollbar-thumb-border-radius'), getVariableValue('border-radius', 'small'));
@include set-variable(('scrollbar-thumb-background-color'), getVariableValue('border-color', 'light'));
@include set-variable(('scrollbar-thumb-hover-background-color'), getVariableValue('border-color'));
}
@include b(scrollbar) {
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
@include e(wrap) {
width: 100%;
height: 100%;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
}
&:hover {
& > .#{$bar} {
opacity: 1;
}
}
@include when(native) {
& > .#{$wrap} {
&::-webkit-scrollbar {
width: getVariableValue('scrollbar-thumb-size');
height: getVariableValue('scrollbar-thumb-size');
}
&::-webkit-scrollbar-track {
background: transparent;
cursor: pointer;
border-radius: getVariableValue('scrollbar-thumb-border-radius');
opacity: 0;
}
&::-webkit-scrollbar-thumb {
background: getVariableValue('scrollbar-thumb-background-color');
cursor: pointer;
border-radius: getVariableValue('scrollbar-thumb-border-radius');
&:hover {
background: getVariableValue('scrollbar-thumb-hover-background-color');
}
}
&:hover {
&::-webkit-scrollbar {
display: block;
}
}
}
@include when(always) {
& > .#{$wrap} {
&::-webkit-scrollbar {
display: block;
}
}
}
}
@include m(vertical) {
& > .#{$wrap} {
overflow-x: hidden;
}
}
@include m(horizontal) {
& > .#{$wrap} {
overflow-y: hidden;
}
}
}
@include b(bar) {
position: absolute;
right: 0;
bottom: 0;
border-radius: getVariableValue('scrollbar-thumb-border-radius');
opacity: 0;
transition: opacity 0.1s ease-out;
cursor: pointer;
&:hover {
z-index: 2;
opacity: 1;
}
&:has(:active) {
opacity: 1;
}
@include e(thumb) {
border-radius: inherit;
background-color: getVariableValue('scrollbar-thumb-background-color');
&:hover {
background-color: getVariableValue('scrollbar-thumb-hover-background-color');
}
}
@include m(vertical) {
top: 0;
& > div {
width: getVariableValue('scrollbar-thumb-size');
}
}
@include m(horizontal) {
left: 0;
& > div {
height: getVariableValue('scrollbar-thumb-size');
}
}
@include when(always) {
& > div {
opacity: 1;
}
}
}
这里提供了完整的样式代码,使用了 SASS 预处理器 🌈。@include b(scrollbar) 部分是用来设置滚动条的基本样式啦,包括滚动条的尺寸、边框半径、背景颜色等,同时处理了不同状态下(比如鼠标悬停)的显示效果和滚动条的显示与隐藏逻辑呢 🔍。对于 @include b(bar) 部分,设置了滚动条的位置、透明度、过渡效果和指针样式,以及滑块的样式,包括不同方向(垂直和水平)下的尺寸设置 🔧。
最终效果
这段代码展示了滚动条组件最终的视觉效果,通过一张 GIF 图片直观地呈现了滚动条的外观和操作时的动态效果,帮助大家更好地理解组件在实际使用中的表现 👀。
🦀🦀感谢看官看到这里,如果觉得文章不错的话🙌,点个关注不迷路⭐。
诚邀您加入我的微信技术交流群🎉,群里都是志同道合的开发者👨💻,大家能一起交流分享摸鱼🐟。期待与您在群里相见🚀,咱们携手在开发路上共同进步✨ !👉点我
感谢各位大侠一路相伴,实在感激! 不瞒您说,在下还有几个开源项目 📦,它们就像精心培育的幼苗 🌱,急需您的浇灌。要是您瞧着还不错,麻烦动动手指,给它们点亮几颗 Star ⭐,您的支持就是它们成长的最大动力,在此谢过各位大侠啦!
Nova UI组件库:github.com/gmingchen/n…- 基于 Vue3 + Element-plus 管理后台基础功能框架
- 预览:admin.gumingchen.icu
- Github:github.com/gmingchen/a…
- Gitee:gitee.com/shychen/agi…
- 基础版后端:github.com/gmingchen/j…
- 文档:admin.gumingchen.icu/doc/
- 基于 Vue3 + Element-plus + websocket 即时聊天系统
- 预览:chatterbox.gumingchen.icu/
- Github:github.com/gmingchen/c…
- Gitee:gitee.com/shychen/cha…
- 基于 node 开发的后端服务:github.com/gmingchen/n…