原生js自定义slider滑块组件

本文详细介绍了如何使用JavaScript实现一个滑块组件的模拟滑动功能,包括无间隔的平滑效果和有间隔的步进效果。通过监听鼠标事件,计算滑块位置,实现了滑动交互,并提供了相应的CSS样式。最后,封装了一个Slider类,支持自定义最小值、最大值、步进和回调函数,以实现更灵活的间隔滑动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过鼠标点击,移动事件来模拟一个滑块组件

实现的效果

无step平滑效果

平滑效果

有step间隔效果

间隔效果

实现逻辑

实现结构及样式

直接实现DOM和style就好了

<div id="sliderBox" class="slider-box">
    <span class="slider" id="slider"></span>
</div>
.slider-box{
    margin: 50px;
    width: 500px;
    height: 4px;
    background-color: #eee;
    border-radius: 4px;
    position: relative;
}
.slider{
    position: absolute;
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: blue;
    top: -4px;
    left: 0;
}
模拟滑动

思路

  • 通过对slider监听mousedown,来设置一个标识,表明开始滑动滑块
  • 通过对document监听mousemove,来获取鼠标的位置,计算并设置滑块的坐标left
  • 通过对document监听mouseup,来改变标识,表明鼠标松开-停止滑动

此处通过mousedown, mousemove, mouseup事件来模拟滑动的过程。下面就是最初的实现逻辑,可以实现平滑的效果

(function () {
    const sliderBox = document.getElementById('sliderBox');
    const span = document.getElementById('slider');

    const boxWidth = sliderBox.offsetWidth;
    // set a boolean that true is drag slider and false is other event;
    let flag = false;

    // mousedown event of slider
    function onMouseDown(event) {
        flag = true;
    }

    // mousemove event of document
    function onMouseMove(event) {
        if (flag) {
            // get mouse offsetX for box
            const offsetX = event.x - sliderBox.offsetLeft;

            // get left offset
            let left = 0;
            if (offsetX > boxWidth) {
                left = boxWidth;
            } else if (offsetX >= 0) {
                left = offsetX;
            } else {
                left = 0;
            }

            // set left position of slider
            span.style.left = left + 'px';
        }
    }

    // mouseup event of document
    function onMouseUp(event) {
        flag = false;
    }

    // add listener when page or component loaded
    function addListener() {
        span.addEventListener('mousedown', onMouseDown);
        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
    }

    // remove listener when page or component destroy
    function removeListener() {
        span.removeEventListener('mousedown', onMouseDown);
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
    }

    addListener();
})()
模拟step

思路

  • 根据sliderBox的宽度和步骤的配置计算出每一个step的大小
  • 根据四舍五入的原则计算出每次滑动的当前step值
  • 根据计算出的当前值设置滑块的位置

通过设置min,max,以及step来模拟有间隔的滑动,下面是最终逻辑,相比较第一步有所调整,进行了简单封装

使用DOM

<div id="sliderBox" class="slider-box"></div>

css

.slider-box{
    margin: 50px;
    width: 500px;
    height: 4px;
    background-color: #eee;
    border-radius: 4px;
    position: relative;
}
.slider {
    position: absolute;
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 6px;
    background-color: blue;
    top: -4px;
    left: -6px;
}

调用js-实现有间隔的滑动

(function () {
    new Slider({
        boxId: 'sliderBox',// slider box id
        stepEnable: true,// enable step
        min: 0,
        max: 30,
        step: 1,
        leftOff: 6,// slider left offset
        value: 10,// default value
        onValueChange: function(current){
            // do something when value is changed
            console.log('current', current);
        }
    });
})()

slider类

class Slider {
    constructor(option) {
        if (!option || !option.boxId) {
            throw new Error('Slider needed boxId');
        }
        this.boxId = option.boxId;
        this.onValueChange = option.onValueChange;
        this.stepEnable = !option.stepEnable ? false : true;
        this.flag = false;
        this.min = option.min || 0;
        this.max = option.max || 10;
        this.step = option.step || 1;
        this.leftOff = option.leftOff || 0;
        this.value = option.value || 0;
        this.init();
    }

    init() {
        this.render();
        this.addListener();
    }

    render() {
        // get sliderBox
        this.sliderBox = document.getElementById(this.boxId);

        // create slider
        const slider = document.createElement('span');
        slider.classList.add('slider');

        this.slider = slider;
        this.sliderBox.appendChild(this.slider);

        // get slider-box width
        this.boxWidth = this.sliderBox.offsetWidth;
        // get slider-box left
        this.boxLeft = this.sliderBox.getBoundingClientRect().left;
        this.setLeftByValue();
    }

    // set slider default position with default value when init render
    setLeftByValue(){
        const left = ((this.value / this.max)*this.boxWidth).toFixed(2);
        this.slider.style.left = (left - this.leftOff) + 'px';
    }

    // get current value and slider left position
    getCurrentValue(left){
        let current = (left/this.boxWidth) * this.max;
        current = Math.round(current/this.step);
        current = current * this.step;
        return {
            current,
            left: this.stepEnable ? (current/this.max)*this.boxWidth.toFixed(2) : left,
        }
    }

    // add listener when page or component loaded
    addListener() {
        this.slider.addEventListener('mousedown', this.onMouseDown);
        document.addEventListener('mousemove', this.onMouseMove);
        document.addEventListener('mouseup', this.onMouseUp);
    }

    // remove listener when page or component destroy
    removeListener() {
        this.slider.removeEventListener('mousedown', this.onMouseDown);
        document.removeEventListener('mousemove', this.onMouseMove);
        document.removeEventListener('mouseup', this.onMouseUp);
    }

    // mousedown event of slider
    onMouseDown = () => {
        this.flag = true;
    }

    // mousemove event of document
    onMouseMove = (event) => {
        if (this.flag) {
            // get mouse offsetX for box
            const offsetX = event.clientX - this.boxLeft;

            // get left offset
            let left = 0;
            if (offsetX > this.boxWidth) {
                left = this.boxWidth;
            } else if (offsetX >= 0) {
                left = offsetX;
            } else {
                left = 0;
            }

            const result = this.getCurrentValue(left);
            if(this.onValueChange){
                // send to onValueChange function when it exist
                if(result.current !== this.value){
                    // emit change event when value is different
                    this.value = result.current;
                    this.onValueChange(result.current);
                }
            }

            // set left position of slider
            this.slider.style.left = (result.left - this.leftOff) + 'px';
        }
    }

    // mouseup event of document
    onMouseUp = () => {
        this.flag = false;
    }

    destroy() {
        this.removeListener();
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值