飞道的博客

可拖拽组件slider.js

423人阅读  评论(0)

基于 mithril.js ,javascript ,scss写一个可拖动的滑块组件


问题描述:

需求需要实现一个可拖动的滑块组件,但是又不能用UI框架,只好自己动手写一个了。 废话不多说,直接上代码。

技术要求

需要有mithril.js,javascript,scss技术基础。
js及页面代码。
var m = require("mithril");
require('./slider.scss');
import slider from './slider';

let obj = {
   
    colorWidth: 0,              // 已拖拽长度
    clickOpen: false,           // 是否开启拖拽
    sliderDom: '',              // 绑定的灰条dom
    colorDom: '',               // 绑定的有色条dom
    radiusDom: '',              // 绑定的圆点dom
    moveEmentRect: null,        // 获取灰条dom参数
    Percentage: 0,              // 百分比

    minWidth: 0,				// 拖动区间下限
    maxWidth: 0,				// 拖动区间上限
    sliderCallback: null,       // 参数回调
    node: [0, 25, 50, 75, 100], // 节点数及占比

    // 初始化数据
    initslider:function(){
   
        obj.sliderDom = document.getElementsByClassName('slider-body')[0];              // 允许进行开始拖拽的元素
        obj.colorDom = document.getElementsByClassName('slider-section')[0];            // 允许进行开始拖拽的元素
        obj.radiusDom = document.getElementsByClassName('slider-radius-body')[0];       // 允许进行开始拖拽的元素
        obj.moveEmentRect = obj.sliderDom.getBoundingClientRect();                      // 获取拖拽父元素的宽度
        obj.maxWidth = obj.moveEmentRect.width;
    },
    // 处理宽度值域
    handleWidth:function(EV){
   
        if (EV <= obj.minWidth) {
   
            return obj.minWidth;
        } else if (EV >= obj.maxWidth) {
   
            return obj.maxWidth;
        } else {
   
            return EV;
        }
    },
    // 鼠标点击 拖动开始
    getMousedown:function(e){
   
        if (e.target === obj.sliderDom || e.target === obj.colorDom || e.target === obj.radiusDom) {
    // 判断是否是可点击拖拽的元素
            obj.clickOpen = true;                                                                    // 打开拖拽状态
            let Width = e.clientX - obj.moveEmentRect.left;                                          // 计算拖拽距离
            obj.colorWidth = this.handleWidth(Width);                                                // 处理拖拽距离转化为长度
            console.log(obj.colorWidth, '拖动开始')
            this.sliderCallback && this.sliderCallback({
   
                colorWidth : this.getPercentage(),                                                   // 将数据回传页面
            })
        }
    },
    // 拖动中
    getMoveWidth:function(e){
   
        if (obj.clickOpen) {
   
            let moveX = e.clientX - obj.moveEmentRect.left;
            obj.colorWidth = this.handleWidth(moveX);
            console.log(obj.colorWidth, '拖动中')
            this.sliderCallback && this.sliderCallback({
   
                colorWidth : this.getPercentage(),                                                   // 将数据回传页面
            })
        }
    },
    // 鼠标松开 拖动结束
    getmouseUp:function(){
   
        obj.clickOpen = false;
        console.log('拖动结束')
    },
    // 绑定到body上,实现在组件外面可以拖拽
    getBodyMouse: function(){
   
        let body = document.querySelector('body');
        body.onmousemove = function(e){
   
            obj.getMoveWidth(e);        // 在body上拖拽组件
        };
        body.onmouseup = function(e){
   
            obj.getmouseUp(e);          // 在body上拖拽结束时关闭可拖拽状态
            obj.onmouseout();           // 在body上结束拖拽时隐藏百分比
        }
    },
    // 计算拖动的百分比
    getPercentage: function () {
   
        let _P = (Number(obj.colorWidth) / Number(obj.maxWidth)).toFixed(2);
        this.Percentage = Math.floor((Number(_P || 0) * 100));
        return Number(_P);
    },
    // 鼠标移入显示百分比
    onmouseover:function(){
   
        let _S = document.getElementsByClassName('slider-percentage')[0];
        _S.style.display = 'block';
    },
    // 鼠标移除隐藏百分比
    onmouseout:function(){
   
        let _S = document.getElementsByClassName('slider-percentage')[0];
        _S.style.display = 'none';
    },
    // 清除数据
    closemode: function () {
   
        obj.colorWidth = 0;              // 已拖拽长度
        obj.clickOpen = false;           // 是否开启拖拽
        obj.sliderDom = '';              // 绑定的灰条dom
        obj.colorDom = '';               // 绑定的有色条dom
        obj.radiusDom = '';              // 绑定的圆点dom
        obj.moveEmentRect = null;        // 获取灰条dom参数
        obj.Percentage = 0;              // 百分比

        obj.minWidth = 0;
        obj.maxWidth = 0;
        obj.sliderCallback = null;       // 参数回调
    },
    // 百分比选择
    getNodePer:function () {
   
        return obj.node.map((item) => {
   
            return m('div',{
   class:'slider-node', style: `left: ${
     item}%`, onclick: function(){
   
                obj.getNodeData(item);
            }},[
            
            ])
        })
    },
    getNodeData:function(item){
   
        obj.colorWidth = Number(obj.maxWidth) * (item / 100);
        this.sliderCallback && this.sliderCallback({
   
            colorWidth : this.getPercentage(),        // 将数据回传页面
        });
    },
}

export default {
   
    oninit: function (vnode) {
   
        
    },
    oncreate: function (vnode) {
   
        obj.sliderCallback = vnode.attrs.cb;
        obj.initslider();
        obj.onmouseout();
        obj.getBodyMouse();
    },
    view: function (vnode) {
   
        return m('div', {
   class: 'slider'}, [
            m('div',{
   class:"slider-body",onmousedown:function(e){
   
                obj.getMousedown(e);
            },onmousemove:function(e){
   
                obj.getMoveWidth(e);
            },onmouseup:function(e){
   
                obj.getmouseUp(e);
            }},[
                m('div',{
   class:"slider-section", style:`width: ${
     obj.colorWidth}px`},[
                    m('div',{
   class:"slider-radius",onmouseover:function(){
   
                        obj.onmouseover();
                    },onmouseout:function(){
   
                        obj.onmouseout();
                    }},[
                        m('div',{
   class:"slider-radius-body"},[])
                    ]),
                    m('div',{
   class:"slider-percentage" , style: `left: ${
     obj.colorWidth - 25}px`},[
                        obj.Percentage + '%'
                    ]),
                ]),
                obj.getNodePer(),
            ]),
        ])
    },
    onremove: function (vnode) {
   
        obj.closemode();
    },
  }

scss样式代码。
// 用的是scss预处理样式
// $arrowsSize scss变量
// var(--primary-lighten)用的是全局颜色,可以直接用颜色值代替
// $dark #ligth 为黑夜白天样式,可以不用。
$arrowsSize: 6px; // 三角形 大小
.slider{
   
    width: 100%;

    .slider-body{
   
        width: 100%;
        height: 6px;
        margin: 16px 0;
        border-radius: 5px;
        position: relative;
        cursor: pointer;

        .slider-section{
   
            height: 6px;
            background-color: var(--primary-lighten); 
            // width: 30%;
            position: absolute;
            left: 0;
            border-radius: 5px;

            .slider-radius{
   
                height: 16px;
                width: 16px;
                position: absolute;
                left: 100%;
                z-index: 999;
                top: -5px;
                transform: translateX(-50%);
                background-color: transparent;
                text-align: center;
                user-select: none;
                line-height: normal;

                .slider-radius-body{
   
                    width: 16px;
                    height: 16px;
                    border: 2px solid var(--primary-lighten);
                    background-color: var(--fontwhite-base);
                    border-radius: 50%;
                    transition: .2s;
                    user-select: none;

                    &::after {
   
                        content: '';
                        height: 100%;
                        display: inline-block;
                        vertical-align: middle;
                    }
                }
            }

            .slider-percentage{
   
                // display: none;
                height: 25px;
                width: 50px;
                line-height: 25px;
                border-radius: 5px;
                background-color: var(--mode-darken);
                text-align: center;
                font-size: 14px;
                color: var(--font-darken);
                position: absolute;
                top: -40px;
                // left: 100%;

                &::after {
   
                    content: '';
                    display: inline-block;
                    vertical-align: middle;
                    width: 0;
                    height: 0;
                    position: absolute;
                    border-top: solid $arrowsSize;
                    border-left: solid $arrowsSize transparent !important;
                    border-right: solid $arrowsSize transparent !important;
                    border-bottom: solid $arrowsSize transparent !important;
                    top: 25px;
                    left: 35%;
                    color: var(--mode-darken);
                }
            }
        }

        .slider-node{
   
            position: absolute;
            height: 8px;
            width: 8px;
            border-radius: 100%;
            background-color: var(--fontwhite-base);
            border: 2px solid var(--primary-lighten);
            transform: translateX(-50%);
            top: -1px;
        }
    }
}

#dark .slider-body{
   
    background-color: var(--line-darken3);
}
#light .slider-body{
   
    background-color: var(--line-lighten3);
}

调用

getSlider: function () {
   
         return m(slider, {
   
             cb : function(arg){
   
                  console.log(arg,22222)
             },
        });
    },

obj.getSlider(),

说明一下

因为公司项目涉及保密条例,电脑都加了安全限制,无法录制视频或者gif图片,所有只能截图展示了。

效果


可以点击圆点拖动,也可以直接点击灰条进行点选然后拖动,也可以点击灰条上的百分比圆点进行拖动,因为单独又把事件绑定到了body上,所以可以在灰条上拖动开始并且在组件外也可以进行拖动,类似Element UI的slider组件效果。


拖动参数的打印


只为分享写代码过程中的一些心得体会,感谢平台!


转载:https://blog.csdn.net/weixin_45126901/article/details/110531312
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场