手机端 Demo

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

  1. <div class="in_box">
  2. <div class="in_list touch_list">
  3. <div class="t">
  4. <div class="l">
  5. 投资限额<span>(最大1000万)</span>
  6. </div>
  7. <div class="r">
  8. <span class="count" id="limit1">10</span>
  9. </div>
  10. </div>
  11. <div class="b">
  12. <div class="ball">
  13. <div class="touch"></div>
  14. </div>
  15. </div>
  16. </div>
  17. <div class="in_list touch_list">
  18. <div class="t">
  19. <div class="l">
  20. 扣款额度<span>(最大10万)</span>
  21. </div>
  22. <div class="r">
  23. <span class="count" id="limit2">5</span>
  24. </div>
  25. </div>
  26. <div class="b">
  27. <div class="ball">
  28. <div class="touch"></div>
  29. </div>
  30. </div>
  31. </div>
  32. <div class="in_list">
  33. <div class="t">
  34. <div class="l">
  35. 授权期限
  36. </div>
  37. <div class="r">
  38. <span id="limit3">3</span>
  39. </div>
  40. </div>
  41. <div class="b">
  42. <ul class="selyears">
  43. <li>1年</li>
  44. <li>2年</li>
  45. <li class="cur">3年</li>
  46. </ul>
  47. </div>
  48. </div>
  49. </div>

css:

  1. .bswmaim>.m2>.in_box>.in_list{margin-bottom:.05rem;padding:.2rem 0;}
  2. .bswmaim>.m2>.in_box>.in_list>.t{line-height:.25rem;}
  3. .bswmaim>.m2>.in_box>.in_list>.t>.l{float:left;color:#333;font-size:.15rem;}
  4. .bswmaim>.m2>.in_box>.in_list>.t>.l>span{color:#666;font-size:.12rem;}
  5. .bswmaim>.m2>.in_box>.in_list>.t>.r{float:right;width:.5rem;text-align:center;font-size:.15rem;color:#009fe8;position:relative;}
  6. .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;}
  7. .bswmaim>.m2>.in_box>.in_list>.b{position:relative;min-height:.25rem;padding:.05rem 0;}
  8. .bswmaim>.m2>.in_box>.touch_list>.b{margin-right:.25rem;overflow:visible;}
  9. .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;}
  10. .bswmaim>.m2>.in_box>.touch_list>.b>.ball{position:absolute;left:0;top:.05rem;width:.25rem;height:.25rem;overflow:visible;}
  11. .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;}
  12. .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:

  1. //手指触摸交互
  2. $(function () {
  3. var startXs = [], x = 0, endX = 0, startX = 0;
  4. //数据初始化
  5. initData();
  6. //触摸事件
  7. $('.touch_list').each(function (index, element) {
  8. $(element).find('.touch').on('touchstart', function (event) {
  9. x = startXs[index];
  10. //console.log(1);
  11. event.preventDefault();
  12. //console.log(event);
  13. var touch = event.originalEvent.targetTouches[0];
  14. startX = touch.pageX - x;
  15. });
  16. $(element).find('.touch').on('touchmove', function (event) {
  17. event.preventDefault();
  18. //console.log(event);
  19. var touch = event.originalEvent.targetTouches[0];
  20. endX = touch.pageX;
  21. x = endX - startX;
  22. var all = $(this).parent('.ball').parent('.b').css('width');
  23. all = all.substr(0, all.length - 2) * 1;
  24. x = x > all ? all : (x < 0 ? 0 : x);
  25. var num = x / all * 100;
  26. $(this).parent('.ball').css({ "left": num + '%' });
  27. var money = parseInt(num / 100 * (index == 0 ? 1000 : 10));
  28. $('#limit' + (index + 1)).html(money);
  29. });
  30. $(element).find('.touch').on('touchend', function (event) {
  31. startXs[index] = x;
  32. });
  33. });
  34. //期限 点击交互
  35. $('.selyears').find('li').click(function () {
  36. $(this).addClass('cur').siblings('li').removeClass('cur');
  37. $('#limit3').html($(this).index() + 1);
  38. });
  39. //投资人初始化数据函数
  40. function initData() {
  41. if ($('.touch_list').length) {
  42. var money1 = $('#limit1').html() * 1;
  43. var money2 = $('#limit2').html() * 1;
  44. $('.touch_list').each(function (index, element) {
  45. if (index == 0) {
  46. var num = money1 / 1000 * 100;
  47. } else if (index == 1) {
  48. var num = money2 / 10 * 100;
  49. }
  50. var all = $(element).find('.b').css('width');
  51. all = all.substr(0, all.length - 2) * 1;
  52. var length = num / 100 * all;
  53. startXs.push(length);
  54. num = num > 100 ? 100 : (num < 0 ? 0 : num);
  55. $(element).find('.ball').animate({ "left": num + '%' }, 500);
  56. });
  57. };
  58. };
  59. });

效果 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;}
  1. - 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);//移动动画 }); }; }; });

  1. - 效果图
  2. > ![2.gif](http://upload-images.jianshu.io/upload_images/9064013-5968702451d15f0a.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  3. ####总结<br />
  4. 主要需要知道的是按钮从 `left` 0 ~ 100 所需要移动的总距离是多少,然后算出手指在移动时的距离占前面总距离的百分比<br />
  5. 主要的难点是:我将按钮和她左侧的蓝色的线条放在了一个元素上,在刚开始移动的时候会出现多出来的.125rem 的长度的蓝色线条,正常来说他是不应该显示出来的<br />
  6. ![image.png](http://upload-images.jianshu.io/upload_images/9064013-3815ea15a2d29803.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<br />
  7. 就是上图这个地方会有问题,后来我使用了一个遮罩的方法具体思路如下 :<br />
  8. css 中给 .ball 增加一个 .show 类名,在 JS 中判断移动的距离或者说是移动距离所占的百分比是否大于了这段小距离所占的百分比,大于的话增加这个类名 show 否则去掉,这个类名控制了 左侧的白色遮罩以及按钮左侧的蓝色的线条的显示与隐藏<br />
  9. #PC 端 Demo<br />
  10. PC 端主要使用了 `mousedown` -- 当按下鼠标按钮时, `mousemove` -- 获得鼠标指针在页面中的位置 `mouseup` -- 当松开鼠标按钮时 三个事件
  11. - HTML
  1. <div class="in_box">
  2. <div class="in_list touch_list">
  3. <div class="l">
  4. 投资限额
  5. </div>
  6. <div class="r">
  7. <div class="line">
  8. <div class="ball">
  9. <div class="touch" title="鼠标拖动改变金额"></div>
  10. </div>
  11. </div>
  12. <div class="txt">
  13. <!-- 程序调取投资人投资限额数据 无数据默认为 10 -->
  14. <span class="count" id="limit1">10</span>
  15. </div>
  16. </div>
  17. </div>
  18. <div class="in_list touch_list">
  19. <div class="l">
  20. 扣款额度
  21. </div>
  22. <div class="r">
  23. <div class="line">
  24. <div class="ball">
  25. <div class="touch" title="鼠标拖动改变金额"></div>
  26. </div>
  27. </div>
  28. <div class="txt">
  29. <!-- 程序调取投资人扣款限额数据 无数据默认为 5 -->
  30. <span class="count" id="limit2">5</span>
  31. </div>
  32. </div>
  33. </div>
  34. <div class="in_list">
  35. <div class="l">
  36. 授权期限
  37. </div>
  38. <div class="r">
  39. <ul class="selyears clearfix">
  40. <!-- 程序判断投资人授权期限数据为相应 li 加类名 cur 无数据默认给第三个加 -->
  41. <li>1年</li>
  42. <li>2年</li>
  43. <li class="cur">3年</li>
  44. </ul>
  45. <!-- 程序调取投资人授权期限数据 无数据默认为 3 -->
  46. <input id="limit3" type="hidden" value="3">
  47. </div>
  48. </div>
  49. </div>
  1. - 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; }

  1. .in_box .in_list .r {
  2. float: left;
  3. width: 440px;
  4. overflow: hidden;
  5. }
  6. .in_box .in_list .r .line {
  7. float: left;
  8. width: 230px;
  9. position: relative;
  10. height: 32px;
  11. margin-right: 30px;
  12. }
  13. .in_box .in_list .r .line:after {
  14. content: " ";
  15. display: block;
  16. position: absolute;
  17. top: 0;
  18. bottom: 0;
  19. left: 0;
  20. margin: auto;
  21. height: 6px;
  22. width: 260px;
  23. box-shadow: 0 1px 4px rgba(0,0,0,.4) inset;
  24. border-radius: 4px;
  25. }
  26. .in_box .in_list .r .line .ball {
  27. position: absolute;
  28. width: 30px;
  29. height: 20px;
  30. top: 0;
  31. bottom: 0;
  32. margin: auto;
  33. z-index: 10;
  34. }
  35. .in_box .in_list .r .line .ball:before {
  36. content: " ";
  37. display: block;
  38. position: absolute;
  39. width: 230px;
  40. height: 6px;
  41. background-color: #009ce4;
  42. box-shadow: 0 1px 4px rgba(0,0,0,.3) inset;
  43. border-radius: 4px 0 0 4px;
  44. left: -230px;
  45. top: 0;
  46. bottom: 0;
  47. margin: auto;
  48. }
  49. .in_box .in_list .r .line .ball .touch {
  50. width: 100%;
  51. height: 100%;
  52. background: url(/Images/Areas/AccountMan/BSWarrant/spriteImg.png) no-repeat;
  53. background-position: 0 0;
  54. border-radius: 4px;
  55. box-shadow: 0 0 3px rgba(0,0,0,.3) inset,1px 1px 5px rgba(0,0,0,.4);
  56. cursor: pointer;
  57. }
  58. .in_box .in_list .r .txt {
  59. float: left;
  60. margin-left: 20px;
  61. color: #00a0e9;
  62. font-size: 18px;
  63. font-weight: 600;
  64. }
  65. .in_box .in_list .r .txt span {
  66. color: #00a0e9;
  67. }
  68. .in_box .in_list .r .selyears li {
  69. float: left;
  70. width: 80px;
  71. height: 32px;
  72. box-shadow: 0 0 0 1px #ccc inset;
  73. text-align: center;
  74. font-size: 16px;
  75. color: #666;
  76. line-height: 32px;
  77. cursor: pointer;
  78. margin-right: 10px;
  79. }
  80. .in_box .in_list .r .selyears li.cur {
  81. box-shadow: none;
  82. background: url(/Images/Areas/AccountMan/BSWarrant/spriteImg.png) no-repeat;
  83. background-position: 0 -20px;
  84. }

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

  1. .bd_rule .txt {
  2. line-height: 36px;
  3. color: #999;
  4. font-size: 14px;
  5. padding-left: 90px;
  6. position: relative;
  7. width: 470px;
  8. margin: 0 auto;
  9. }
  10. .bd_rule .txt:before {
  11. content: "授权须知";
  12. position: absolute;
  13. line-height: 36px;
  14. height: 36px;
  15. left: 0;
  16. top: 0;
  17. }

/雪碧图/ .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; }

  1. - 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,这样使得拖拽的范围扩大了些,不会显得有些”笨重”