手指(鼠标)拖动、滑动,金额限制交互 Demo

手机端 Demo

手机端主要使用了 touchstart touchmove touchend 三个事件
html:

<div class="in_box">
                <div class="in_list touch_list">
                    <div class="t">
                        <div class="l">
                            投资限额<span>(最大1000万)</span>
                        </div>
                        <div class="r">
                            <span class="count" id="limit1">10</span>万
                        </div>
                    </div>
                    <div class="b">
                        <div class="ball">
                            <div class="touch"></div>
                        </div>
                    </div>
                </div>
                <div class="in_list touch_list">
                    <div class="t">
                        <div class="l">
                            扣款额度<span>(最大10万)</span>
                        </div>
                        <div class="r">
                            <span class="count" id="limit2">5</span>万
                        </div>
                    </div>
                    <div class="b">
                        <div class="ball">
                            <div class="touch"></div>
                        </div>
                    </div>
                </div>
                <div class="in_list">
                    <div class="t">
                        <div class="l">
                            授权期限
                        </div>
                        <div class="r">
                            <span id="limit3">3</span>年
                        </div>
                    </div>
                    <div class="b">
                       <ul class="selyears">
                           <li>1年</li>
                           <li>2年</li>
                           <li class="cur">3年</li>
                       </ul>
                    </div>
                </div>
            </div>

css:

.bswmaim>.m2>.in_box>.in_list{margin-bottom:.05rem;padding:.2rem 0;}
.bswmaim>.m2>.in_box>.in_list>.t{line-height:.25rem;}
.bswmaim>.m2>.in_box>.in_list>.t>.l{float:left;color:#333;font-size:.15rem;}
.bswmaim>.m2>.in_box>.in_list>.t>.l>span{color:#666;font-size:.12rem;}
.bswmaim>.m2>.in_box>.in_list>.t>.r{float:right;width:.5rem;text-align:center;font-size:.15rem;color:#009fe8;position:relative;}
.bswmaim>.m2>.in_box>.in_list>.t>.r:before{content:" ";display:block;position:absolute;bottom:0;top:0;left:0;right:0;margin:auto auto 0 auto;height:1px;background-color:#ccc;}
.bswmaim>.m2>.in_box>.in_list>.b{position:relative;min-height:.25rem;padding:.05rem 0;}
.bswmaim>.m2>.in_box>.touch_list>.b{margin-right:.25rem;overflow:visible;}
.bswmaim>.m2>.in_box>.touch_list>.b:after{content:" ";display:block;position:absolute;left:0;top:0;right:0;bottom:0;height:.05rem;background-color:#cddae0;margin:auto;border-radius:.025rem;box-shadow:0 0 7px 1px #bdcdd5 inset;width:3.4rem;}
.bswmaim>.m2>.in_box>.touch_list>.b>.ball{position:absolute;left:0;top:.05rem;width:.25rem;height:.25rem;overflow:visible;}
.bswmaim>.m2>.in_box>.touch_list>.b>.ball>.touch{content:" ";display:block;position:absolute;width:.25rem;height:.25rem;border-radius:50%;background:url(/Images/Area/AccountMan/BSWarrant/icon1.png) center center no-repeat #009fe8;background-size:.115rem .115rem;left:0;top:0;z-index:10;}
.bswmaim>.m2>.in_box>.touch_list>.b>.ball:before{content:"";display:block;position:absolute;width:3.15rem;height:.05rem;background-color:#009fe8;border-radius:.025rem 0 0 .025rem;left:0;top:.1rem;z-index:9;left:-3.15rem;}

js:

//手指触摸交互
$(function () {
    var startXs = [], x = 0, endX = 0, startX = 0;
    //数据初始化
    initData();
    //触摸事件
    $('.touch_list').each(function (index, element) {
        $(element).find('.touch').on('touchstart', function (event) {
            x = startXs[index];
            //console.log(1);
            event.preventDefault();
            //console.log(event);
            var touch = event.originalEvent.targetTouches[0];
            startX = touch.pageX - x;
        });

        $(element).find('.touch').on('touchmove', function (event) {
            event.preventDefault();
            //console.log(event);
            var touch = event.originalEvent.targetTouches[0];
            endX = touch.pageX;
            x = endX - startX;
            var all = $(this).parent('.ball').parent('.b').css('width');
            all = all.substr(0, all.length - 2) * 1;
            x = x > all ? all : (x < 0 ? 0 : x);
            var num = x / all * 100;
            $(this).parent('.ball').css({ "left": num + '%' });
            var money = parseInt(num / 100 * (index == 0 ? 1000 : 10));
            $('#limit' + (index + 1)).html(money);
        });

        $(element).find('.touch').on('touchend', function (event) {
            startXs[index] = x;
        });
    });
    //期限 点击交互
    $('.selyears').find('li').click(function () {
        $(this).addClass('cur').siblings('li').removeClass('cur');
        $('#limit3').html($(this).index() + 1);
    });
    //投资人初始化数据函数
    function initData() {
        if ($('.touch_list').length) {
            var money1 = $('#limit1').html() * 1;
            var money2 = $('#limit2').html() * 1;
            $('.touch_list').each(function (index, element) {
                if (index == 0) {
                    var num = money1 / 1000 * 100;
                } else if (index == 1) {
                    var num = money2 / 10 * 100;
                }
                var all = $(element).find('.b').css('width');
                all = all.substr(0, all.length - 2) * 1;
                var length = num / 100 * all;
                startXs.push(length);
                num = num > 100 ? 100 : (num < 0 ? 0 : num);
                $(element).find('.ball').animate({ "left": num + '%' }, 500);
            });
        };
    };
});

效果 GIF

GIF.gif

扩展上面的 Demo

  • 参考网易云音乐进度条的设计、交互来实现
1.gif
  • 主要修改的地方:使按钮可以在进度条的左右两侧各多出自身一半的宽度

源码

  • HTML 与上面之前的不变,修改的只是 JS && CSS
  • CSS
.bswmaim>.m2>.in_box>.in_list{margin-bottom:.05rem;padding:.2rem 0;}
.bswmaim>.m2>.in_box>.in_list>.t{line-height:.25rem;}
.bswmaim>.m2>.in_box>.in_list>.t>.l{float:left;color:#333;font-size:.15rem;}
.bswmaim>.m2>.in_box>.in_list>.t>.l>span{color:#666;font-size:.12rem;}
.bswmaim>.m2>.in_box>.in_list>.t>.r{float:right;width:.5rem;text-align:center;font-size:.15rem;color:#009fe8;position:relative;}
.bswmaim>.m2>.in_box>.in_list>.t>.r:before{content:" ";display:block;position:absolute;bottom:0;top:0;left:0;right:0;margin:auto auto 0 auto;height:1px;background-color:#ccc;}
.bswmaim>.m2>.in_box>.in_list>.b{position:relative;min-height:.25rem;padding:.05rem 0;}
.bswmaim>.m2>.in_box>.touch_list>.b{overflow:visible;}
.bswmaim>.m2>.in_box>.touch_list>.b:after{content:" ";display:block;position:absolute;left:.125rem;top:0;right:.125rem;bottom:0;height:.05rem;background-color:#cddae0;margin:auto;border-radius:.025rem;box-shadow:0 0 7px 1px #bdcdd5 inset;}
.bswmaim>.m2>.in_box>.touch_list>.b>.ball{position:absolute;left:0;right:.25rem;top:.05rem;height:.25rem;overflow:visible;}
.bswmaim>.m2>.in_box>.touch_list>.b>.show:before{content:"";display:block;position:absolute;width:.125rem;background-color:#fff;border-radius:.025rem 0 0 .025rem;top:0;bottom:0;left:0;z-index:10;}
.bswmaim>.m2>.in_box>.touch_list>.b>.ball>.touch{position:absolute;width:.25rem;height:.25rem;border-radius:50%;background:url(/Images/Area/AccountMan/BSWarrant/icon1.png) center center no-repeat #009fe8;background-size:.115rem .115rem;left:0;top:0;z-index:1;overflow:visible;}
.bswmaim>.m2>.in_box>.touch_list>.b>.show>.touch:before{content:"";display:block;position:absolute;width:3.025rem;height:.05rem;background-color:#009fe8;border-radius:.025rem 0 0 .025rem;top:.1rem;z-index:0;left:-3.025rem;}
  • JS (这里写了较为详细的注释)
$(function () {
    var startXs = [],//接收每个按钮移动距离的数组
        x = 0,//移动距离计算时所用的初始值
        endX = 0,//接收手指移动后位置的数值
        startX = 0;//接收手机触摸开始时位置的数值 其实算的是元素的相对的起始位置的 0 0 点的坐标
    //数据初始化
    initData();
    //触摸事件
    $('.touch_list').each(function (index, element) {
        //开始触摸事件
        $(element).find('.touch').on('touchstart', function (event) {
            x = startXs[index];//拿出移动数值中当前元素移动的距离数值
            //console.log(x);
            event.preventDefault();//禁止浏览器的默认事件
            //console.log(event);
            var touch = event.originalEvent.targetTouches[0];//获取触摸对象
            startX = touch.pageX - x;//用当前的触摸位置减去之前移动的距离 获得的是 按钮最初 `left = 0` 在页面中的 pageX 的值
            //console.log(startX);
        });
        //触摸时移动事件
        $(element).find('.touch').on('touchmove', function (event) {
            event.preventDefault();//禁止浏览器的默认事件
            //console.log(event);
            var touch = event.originalEvent.targetTouches[0];//获取触摸对象
            endX = touch.pageX;//获取此时手指移动时的位置
            x = endX - startX;//用移动时的数值减去手指从 `left = 0`的 pageX 的值得到按钮需要移动的距离
            var all = all || parseInt($(this).parent('.ball').parent('.b').css('width')) - 2 * (parseInt($(this).css('width')));//按钮 `left` 从 0 到 100 总需移动的距离数值
            //console.log(all);
            x = x > all ? all : (x < 0 ? 0 : x);//容错
            var num = x / all * 100;//获取移动距离所占的百分比
            //判断移动距离的百分比距离是否超过 .touch 一半的宽度所占的百分比
            //1.25 为 .touch 一半的宽度   3.025 为 移动 100% 的宽度 
            if (num > (.125 / 3.025 * 100)) {
                $(this).parent('.ball').addClass('show');//在 css 中做相应的转换
            } else {
                $(this).parent('.ball').removeClass('show');//在 css 中做相应的转换
            }
            $(this).css({ "left": num + '%' });//移动样式
            var money = parseInt(num / 100 * (index == 0 ? 1000 : 10));
            $('#limit' + (index + 1)).html(money);//改变 相应的元素的 html 数值
        });
        //触摸事件结束后
        $(element).find('.touch').on('touchend', function (event) {
            event.preventDefault();//禁止浏览器的默认事件
            startXs[index] = x;//结束时更新数组中相应的 手指从触摸到移动的距离
        });
    });
    //期限 点击交互
    $('.selyears').find('li').click(function () {
        $(this).addClass('cur').siblings('li').removeClass('cur');
        $('#limit3').html($(this).index() + 1);
    });
    //投资人初始化数据函数
    function initData() {
        //判断当前用户是否为 投资人
        if ($('.touch_list').length) {
            //获取 html 中相应的数值
            var money1 = $('#limit1').html() * 1;
            var money2 = $('#limit2').html() * 1;
            $('.touch_list').each(function (index, element) {
                //num 为 html 中的数值转换为所占的相应的宽度百分比数值
                if (index == 0) {
                    var num = money1 / 1000 * 100;
                } else if (index == 1) {
                    var num = money2 / 10 * 100;
                }
                var all = all || parseInt($(element).find('.b').css('width')) - 2 * (parseInt($(element).find('.touch').css('width')));//按钮 `left` 从 0 到 100 总需移动的距离数值
                //console.log(all);
                var length = num / 100 * all;//按钮移动的距离
                startXs.push(length);//传入移动的距离至数组中
                num = num > 100 ? 100 : (num < 0 ? 0 : num);//容错
                //判断移动距离的百分比距离是否超过 .touch 一半的宽度所占的百分比
                //1.25 为 .touch 一半的宽度   3.025 为 移动 100% 的宽度 
                if (num > (.125 / 3.025 * 100)) {
                    $(element).find('.ball').addClass('show');//在 css 中做相应的转换
                }
                $(element).find('.touch').animate({ "left": num + '%' }, 500);//移动动画
            });
        };
    };
});
  • 效果图
2.gif

总结

主要需要知道的是按钮从 left 从 0 ~ 100 所需要移动的总距离是多少,然后算出手指在移动时的距离占前面总距离的百分比
主要的难点是:我将按钮和她左侧的蓝色的线条放在了一个元素上,在刚开始移动的时候会出现多出来的.125rem 的长度的蓝色线条,正常来说他是不应该显示出来的

image.png

就是上图这个地方会有问题,后来我使用了一个遮罩的方法具体思路如下 :
在 css 中给 .ball 增加一个 .show 类名,在 JS 中判断移动的距离或者说是移动距离所占的百分比是否大于了这段小距离所占的百分比,大于的话增加这个类名 show 否则去掉,这个类名控制了 左侧的白色遮罩以及按钮左侧的蓝色的线条的显示与隐藏

PC 端 Demo

PC 端主要使用了 mousedown -- 当按下鼠标按钮时, mousemove -- 获得鼠标指针在页面中的位置 ,mouseup -- 当松开鼠标按钮时 三个事件

  • HTML
<!-- 投资人模块 -->
        <div class="in_box">
            <div class="in_list touch_list">
                <div class="l">
                    投资限额
                </div>
                <div class="r">
                    <div class="line">
                        <div class="ball">
                            <div class="touch" title="鼠标拖动改变金额"></div>
                        </div>
                    </div>
                    <div class="txt">
                        <!-- 程序调取投资人投资限额数据  无数据默认为 10 -->
                        <span class="count" id="limit1">10</span>万
                    </div>
                </div>
            </div>
            <div class="in_list touch_list">
                <div class="l">
                    扣款额度
                </div>
                <div class="r">
                    <div class="line">
                        <div class="ball">
                            <div class="touch" title="鼠标拖动改变金额"></div>
                        </div>
                    </div>
                    <div class="txt">
                        <!-- 程序调取投资人扣款限额数据  无数据默认为 5 -->
                        <span class="count" id="limit2">5</span>万
                    </div>
                </div>
            </div>
            <div class="in_list">
                <div class="l">
                    授权期限
                </div>
                <div class="r">
                    <ul class="selyears clearfix">
                        <!-- 程序判断投资人授权期限数据为相应 li 加类名 cur  无数据默认给第三个加 -->
                        <li>1年</li>
                        <li>2年</li>
                        <li class="cur">3年</li>
                    </ul>
                    <!-- 程序调取投资人授权期限数据  无数据默认为 3 -->
                    <input id="limit3" type="hidden" value="3">
                </div>
            </div>
        </div>
  • CSS
.in_box {
    margin: 0 auto;
    width: 600px;
}

   .in_box .in_list {
        line-height: 32px;
        margin-bottom: 22px;
        overflow: hidden;
    }
        .in_box .in_list .l {
            float: left;
            width: 140px;
            color: #333;
            font-size: 16px;
            margin-right: 20px;
            text-align: right;
        }

        .in_box .in_list .r {
            float: left;
            width: 440px;
            overflow: hidden;
        }

            .in_box .in_list .r .line {
                float: left;
                width: 230px;
                position: relative;
                height: 32px;
                margin-right: 30px;
            }

                .in_box .in_list .r .line:after {
                    content: " ";
                    display: block;
                    position: absolute;
                    top: 0;
                    bottom: 0;
                    left: 0;
                    margin: auto;
                    height: 6px;
                    width: 260px;
                    box-shadow: 0 1px 4px rgba(0,0,0,.4) inset;
                    border-radius: 4px;
                }

                .in_box .in_list .r .line .ball {
                    position: absolute;
                    width: 30px;
                    height: 20px;
                    top: 0;
                    bottom: 0;
                    margin: auto;
                    z-index: 10;
                }

                    .in_box .in_list .r .line .ball:before {
                        content: " ";
                        display: block;
                        position: absolute;
                        width: 230px;
                        height: 6px;
                        background-color: #009ce4;
                        box-shadow: 0 1px 4px rgba(0,0,0,.3) inset;
                        border-radius: 4px 0 0 4px;
                        left: -230px;
                        top: 0;
                        bottom: 0;
                        margin: auto;
                    }

                    .in_box .in_list .r .line .ball .touch {
                        width: 100%;
                        height: 100%;
                        background: url(/Images/Areas/AccountMan/BSWarrant/spriteImg.png) no-repeat;
                        background-position: 0 0;
                        border-radius: 4px;
                        box-shadow: 0 0 3px rgba(0,0,0,.3) inset,1px 1px 5px rgba(0,0,0,.4);
                        cursor: pointer;
                    }

            .in_box .in_list .r .txt {
                float: left;
                margin-left: 20px;
                color: #00a0e9;
                font-size: 18px;
                font-weight: 600;
            }

                .in_box .in_list .r .txt span {
                    color: #00a0e9;
                }

            .in_box .in_list .r .selyears li {
                float: left;
                width: 80px;
                height: 32px;
                box-shadow: 0 0 0 1px #ccc inset;
                text-align: center;
                font-size: 16px;
                color: #666;
                line-height: 32px;
                cursor: pointer;
                margin-right: 10px;
            }

                .in_box .in_list .r .selyears li.cur {
                    box-shadow: none;
                    background: url(/Images/Areas/AccountMan/BSWarrant/spriteImg.png) no-repeat;
                    background-position: 0 -20px;
                }

.bd_rule {
    border-top: 1px solid #e6e6e6;
    padding: 38px 0 64px;
}

    .bd_rule .txt {
        line-height: 36px;
        color: #999;
        font-size: 14px;
        padding-left: 90px;
        position: relative;
        width: 470px;
        margin: 0 auto;
    }

        .bd_rule .txt:before {
            content: "授权须知";
            position: absolute;
            line-height: 36px;
            height: 36px;
            left: 0;
            top: 0;
        }

/*雪碧图*/
.spriteImg {
    background: url(/Images/Areas/AccountMan/BSWarrant/spriteImg.png) no-repeat;
}

.touchicon {
    height: 20px;
    width: 30px;
    background-position: 0 0;
}

.selectact {
    height: 32px;
    width: 80px;
    background-position: 0 -20px;
}
  • JS
//鼠标拖动交互
$(function () {
    var startXs = [],//接收每个按钮移动距离的数组
        x = 0,//移动距离计算时所用的初始值
        endX = 0,//接收鼠标移动后位置的数值
        startX = 0;//接收鼠标开始时位置的数值 其实算的是元素的相对的起始位置的 0 0 点的坐标
    var down = false;//判断鼠标是否按下
    //数据初始化
    initData();
    //鼠标拖拽事件
    $('.touch_list').each(function (index, element) {
        //mousedown   当按下鼠标按钮时
        $(element).find('.touch').on('mousedown', function (event) {
            down = true;
            x = startXs[index];
            //console.log(event);
            event.preventDefault();
            startX = event.pageX - x;
            console.log(1);
        });
        //mousemove 获得鼠标指针在页面中的位置
        $(element).on('mousemove', function (event) {
            //判断鼠标是否按下
            if (down) {
                event.preventDefault();
                //console.log(event);
                endX = event.pageX;
                x = endX - startX;
                var all = 230;//230 为 .line 的长度
                x = x > all ? all : (x < 0 ? 0 : x);
                var num = x / all * 100;
                $(this).find('.ball').css({ "left": x + 'px' });
                var money = parseInt(num / 100 * (index == 0 ? 1000 : 10));
                $('#limit' + (index + 1)).html(money);
                console.log(2);
            }
        });
        //mouseup 当松开鼠标按钮时
        $(element).on('mouseup', function (event) {
            event.preventDefault();
            down = false;
            startXs[index] = x;
            console.log(down);
        });
    });
    //期限 点击交互
    $('.selyears').find('li').click(function () {
        $(this).addClass('cur').siblings('li').removeClass('cur');
        $('#limit3').val($(this).index() + 1);
    });
    //投资人初始化数据函数
    function initData() {
        if ($('.touch_list').length) {
            var money1 = $('#limit1').html() * 1;
            var money2 = $('#limit2').html() * 1;
            $('.touch_list').each(function (index, element) {
                if (index == 0) {
                    var num = money1 / 1000;
                } else if (index == 1) {
                    var num = money2 / 10;
                }
                var length = num * 230;//230 为 .line 的长度
                length = length > 230 ? 230 : (length < 0 ? 0 : length);
                startXs.push(length);
                $(element).find('.ball').animate({ "left": length + 'px' }, 1000);
            });
        };
    };
});
  • 浏览器效果图
3.gif
  • 总结:

PC 和 手机端最主要的区别除了使用的事件之外还有就是元素移动范围的不同,PC 端范围是按钮的相对父级 .touch_list,这样使得拖拽的范围扩大了些,不会显得有些"笨重"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • •前端面试题汇总 一、HTML和CSS 21 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? ...
    Simon_s阅读 6,598评论 0 8
  • 第一部分HTML&CSS整理答案1.什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HTML5...
    Programmer客栈阅读 6,128评论 0 12
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 14,687评论 1 92
  • 前几天看到一个段子: 如果你问我 想做你的什么 那我会告诉你 我要做你的手机 因为你每天甚至无时不刻都会 把我拿在...
    李晓茹阅读 4,811评论 6 11
  • 释清风阅读 1,193评论 2 2

友情链接更多精彩内容