原生JS自制的scrollbar,如何消除滑块拖动时的卡顿?

作者站长头像
站长
· 阅读数 12

这是 事件监听,也是用docment对全局进行鼠标的移动及抬起监听了。

        const scrollStart =  (e: MouseEvent) => {
            e = e || window.Event;
            if (e.button == 0) { // 鼠标左键点击
                xPostion = e.clientX;
                originLeft = parseInt(this.scrollThumb.style.left) ? parseInt(this.scrollThumb.style.left) : 0;
                document.addEventListener('mousemove', scrollMove);
                document.addEventListener('mouseup', scrollEnd, {once: true});
            }
        }
        this.scrollThumb.addEventListener('mousedown', scrollStart);

        // let timeOutId = null;
        const scrollMove =  (e: MouseEvent) => {
            e = e || window.Event;
            e.preventDefault();
            e.stopPropagation();
            // document.removeEventListener('mousemove', scrollMove);
            // timeOutId = setTimeout(function() {
            //     document.addEventListener('mousemove', scrollMove);
            // }, 16);
            let move = e.clientX - xPostion;
            // window.requestAnimationFrame(() => {
                this.setPosition(originLeft + move); 
            // })                       
        }

        const scrollEnd = (e: MouseEvent) => {
            e = e || window.Event;
            // timeOutId = null;
            xPostion = 0;
            document.removeEventListener('mousemove', scrollMove);
        }

这是CSS,使用absolute对滑块进行定位

.scroll-track {
        position: absolute;
        left: 16px;
        top: 0;
        width: calc(100% - 52px);
        height: 20px;

        .scroll-thumb {
            position: absolute;
            left: 0;
            top: 0;
            margin: 4px 0 4px 0;
            height: 12px;
            background-color: lightgray;
        }
        .scroll-thumb:hover {
            background-color: gray;
        }
        .scroll-thumb:active {
            background-color: dimgrey;
        }
    }
回复
1个回答
avatar
test
2024-08-11

上面的问题我没有描述清楚,关键是这个 this.setPosition(originLeft + move); 函数我写得有问题。

原来我是这样写的

setPosition(top: number) {
    if (top >= 0 && top <= this.scrollTrack.getBoundingClientRect().height * (1 - this.ratio)) {
        this.scrollThumb.style.top = `${top}px`;
    }
    
}

由于需要判断边界,不能让滑块滑出边界,我做了鼠标滚动距离的判断,这样就导致出了边界之后,滑块不再动了,具体表现就是卡顿。所以我改了一下这个函数,完美解决。

setPosition(top: number) {
        if (top < 0) top = 0;
        if (top > this.scrollTrack.getBoundingClientRect().height * (1 - this.ratio)) {
            top = this.scrollTrack.getBoundingClientRect().height * (1 - this.ratio);
        }
        this.scrollThumb.style.top = `${top}px`;
        
    }

不再用条件判断来执行下一步操作,说白了就是把鼠标滑动的距离做个判断,超过了边界,直接把参数值固定在边界。move事件每次循环都会执行了。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容