UDN-企业互联网技术人气社区

板块导航

浏览  : 1212
回复  : 11

[原生js] JS —— 轮播图中的缓动函数的封装

[复制链接]
genie1003的头像 楼主
发表于 2017-2-9 10:53:02 | 显示全部楼层 |阅读模式

  轮播图的根本其实就是缓动函数的封装,如果说轮播图是一辆跑动的汽车,那么缓动函数就是它的发动机,今天本文章就带大家由简入繁,封装属于自己的缓动函数~~

  我们从需求的角度开始,首先给出一个简单需求:

  1、我想让页面中的一个盒子从开始的位置匀速向右运动到200px的地方,该怎么实现?

  分析:1)我们需要知道盒子在哪个地方,这个可以通过offsetLeft属性去获取;

  2)要让盒子匀速运动,对于js肯定需要setInterval了;

  3)要让盒子向右边跑起来?那就是需要不停改变盒子与左边起始点的距离,有margin-left,还有定位的left,这里我选择了改变绝对定位的left;

  4)跑到离开始点200px的距离我们要停下来,使用clearInterval就可以了。

  接下来直接上代码了
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8" />
  5.     <title>Document</title>
  6.     <style type="text/css">
  7.       * {
  8.         margin: 0;
  9.         padding: 0;
  10.       }
  11.       div {
  12.         position: absolute;
  13.         top: 50px;
  14.         width: 100px;
  15.         height: 100px;
  16.         background-color: red;
  17.       }
  18.       input {
  19.         width: 100px;
  20.         height: 30px;
  21.         color: #fff;
  22.         background-color: yellowgreen;
  23.       }

  24.     </style>
  25.   </head>

  26.   <body>
  27.     <div></div>
  28.     <input type="button" value="移动到200" />


  29.     <script type="text/JavaScript">
  30.       // 获取到元素(这里有个小细节,如果给元素设置了id名,即便不使用获取元素的方法,也能通过这个id名获取到元素哦~~大家可以自己尝试一下)
  31.       var btn = document.querySelector('input'),
  32.           dv = document.querySelector('div');
  33.       // 添加点击事件
  34.       btn.addEventListener('click',function() {
  35.         var timer = null,// 保存定时器
  36.             currentDistance = dv.offsetLeft, // 当前离父盒子的距离
  37.             step = 8,// 每次改变的距离
  38.             target = 200;// 目标距离
  39.         timer = setInterval(function() {
  40.           currentDistance += step;// 当前距离 = 上一个当前距离 + 改变的距离
  41.           if((target - currentDistance) < step) {
  42.             currentDistance = target; // 如果目标距离与当前距离的差小于了要改变的距离,这时候我们就直接让当前距离等于目标距离,防止盒子停下来的时候有误差
  43.             clearInterval(timer); // 清楚定时器
  44.             timer = null; // 将timer解绑,释放内存
  45.           }
  46.           dv.style.left = currentDistance + 'px'; // 最核心的一步,改变盒子的left为当前距离
  47.         },17)
  48.       })
  49.     </script>
  50.   </body>
  51. </html>
复制代码

  2、一个初步运动的效果实现了,那么接下来我们改进了需求:

  盒子运动到200px的位置后,我们要让盒子继续运动到400px的位置?

  分析: 1)、这时候要有两个按钮点击,一个运动到200px,一个运动到400px

  2)、虽然有两个运动,但是其使用的功能都是一样,都是从一个点移动到另一个点,所以我们考虑将1中的运动封装一个函数,以供复用。

  上代码~
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8" />
  5.   <title>Document</title>
  6.   <style type="text/css">
  7.     * {
  8.       margin: 0;
  9.       padding: 0;
  10.     }
  11.     div {
  12.       position: absolute;
  13.       top: 50px;
  14.       width: 100px;
  15.       height: 100px;
  16.       background-color: red;
  17.     }
  18.     input {
  19.       width: 100px;
  20.       height: 30px;
  21.       color: #fff;
  22.       background-color: yellowgreen;
  23.     }

  24.   </style>
  25. </head>

  26. <body>
  27.   <div></div>
  28.   <input type="button" value="移动到200" />
  29.   <input type="button" value="移动到400" />
  30.   <script type="text/JavaScript">
  31.     // 封装函数,盒子和目标距离都是不确定的,我们可以将他们作为参数传递。
  32.     function animation(tag,target) {
  33.       var timer = null,
  34.           currentDistance = tag.offsetLeft,
  35.           step = 5;
  36.       step = currentDistance < target? step: -step;// 判断step的正负,200到400时是递增,400到200时是递减
  37.       timer = setInterval(function() {
  38.         if(Math.abs(currentDistance - target) > Math.abs(step)) { // 这里判断条件也要略作改动,使用绝对值进行比较
  39.           currentDistance += step; /
  40.           tag.style.left = currentDistance + 'px';
  41.         }else {
  42.           tag.style.left = target + 'px' // 当当前距离与目标距离之间的差值小于step改变的距离时,我们直接让盒子移动到目标距离。
  43.           clearInterval(timer);
  44.           timer = null;
  45.         }
  46.       },17)
  47.     }
  48.     var btns = document.querySelectorAll('input'),
  49.         dv = document.querySelector('div');
  50.     btns[0].addEventListener('click',function() {
  51.       animation(dv,200);
  52.     })
  53.     btns[1].addEventListener('click',function() {
  54.       animation(dv,400);
  55.     })
  56.   </script>
  57. </body>
  58. </html>
复制代码

  3、盒子来回运动的函数我们封装好了,但是我们再想一下轮播图的滚动效果,它并不是匀速移动,而是最开始很块,在接近滚动完成时,速度又逐渐减低。

  需求: 让盒子缓动(也就是变速运动)

  上代码~
  1. function animation(tag,target) {
  2.       var timer = null;
  3.       timer = setInterval(function() {
  4.         var currentDistance = tag.offsetLeft,
  5.             step = (target - currentDistance) / 5;// 通过目标距离与当前距离的差除以5便达到了我们需要的变速运动,因为step每次定制器执行都要改变,所以放入定时器内
  6.         step = step > 0 ? Math.ceil(step):Math.floor(step);// 这里如果将currentDistance定时器外面声明可以不用写,如果放在定时器内声明,因为offsetLeft取整的特性,要对step进行取整
  7.         if(Math.abs(currentDistance - target) > Math.abs(step)) {
  8.           currentDistance += step;
  9.           tag.style.left = currentDistance + 'px';
  10.         }else {
  11.           tag.style.left = target + 'px'
  12.           clearInterval(timer);
  13.           timer = null;
  14.         }
  15.       },17)
复制代码

  好了,一个轮播图需要的最基本的缓动函数完成了~

  这里补充一个比较完整的缓动函数:它的功能更全面一点,可以同时更改多样式。
  1. function perfectAnimate(tag, obj, fn) {// 传三个参数,运动的盒子,对象(可以传多个属性),回调函数(在执行完后可以再执行自定义的功能)
  2.     clearInterval(tag.timer);// 这里将定时器作为tag标签的属性保存,可以多次调用函数清除上一个定时器。
  3.     tag.timer = setInterval(function () {
  4.         var flag = true;
  5.         for (var k in obj) {
  6.        // 因为并不是所有属性都带px单位,所以这里进行判断分别设置
  7.             if (k == 'opacity') {
  8.                 var currentDistance = getStyle(tag, k) * 100,
  9.                     target = obj[k] * 100,
  10.                     step = (target - currentDistance) / 10;
  11.                 step = step > 0 ? Math.ceil(step) : Math.floor(step);
  12.                 currentDistance += step;
  13.                 tag.style[k] = currentDistance / 100;
  14.             } else if (k == 'zIndex') {
  15.                 tag.style[k] = obj[k];
  16.             else {
  17.                 var currentDistance = parseInt(getStyle(tag, k)) || 0,
  18.                     target = obj[k],
  19.                     step = (target - currentDistance) / 10;
  20.                 step = step > 0 ? Math.ceil(step) : Math.floor(step);
  21.                 currentDistance += step;
  22.                 tag.style[k] = currentDistance + 'px';
  23.             }
  24.             if (target != currentDistance) {
  25.                 flag = false // 只要还有属性没有运动完成,就不会清楚定时器
  26.             }
  27.         }
  28.         if (flag) {
  29.             clearInterval(tag.timer)
  30.             fn && fn();// 所有定时器走完,这里执行回调函数,短路操作避免不传回调函数也不会报错。
  31.         }
  32.     }, 17)
  33. }
  34. // 获取样式的兼容函数,上面的缓动函数的依赖
  35. function getStyle(tag, attr) {
  36.     if (tag.currentStyle) {
  37.         return tag.currentStyle[attr];
  38.     } else {
  39.         return getComputedStyle(tag, null)[attr];
  40.     }
  41. }
复制代码

相关帖子

发表于 2017-2-9 10:53:32 | 显示全部楼层
我是被标题吸引进来的
使用道具 举报

回复

发表于 2017-2-12 08:37:49 | 显示全部楼层
总觉得哪里有点问题啊
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部