原生JavaScript运动功能系列(一):运动功能剖析与匀速运动实现

在我们日常生活中运动就是必不可少的部分,走路、跑步、打篮球等。在网页交互设计上运动也是必不可少的部分,创建的网站交互设计运动模块有轮播图,下拉菜单,还有各种炫酷的游戏效果都跟运动密切相关。所以很重要,所以不废话了,先来分析一下运动这个功能的几个核心组成部分吧。

 一、运动功能的核心组成部分:

  • 位置变化:

    1.位置从一个位置到达另一个位置;

    2.位置变化有可视的变化过程;

    3.位置变化具有可控的方向性;

  • 速度变化:

    1.运动的速度是可变的;

    2.运动的是可控的,比如暂停,减速,加速,继续运动

  • 大小透明度变化(相对位置来说处于静态的运动):

      1.宽高及阴影的变化;

    2.透明度或者背景颜色图片的变化。

  • 可移植性(即一种运动功能可以适应不同场景,在主体功能不变的情况下可以设置一些样式差异):

    1.比如运动体的大小可以实现初始化;

    2.可以设置一些视觉差异效果(比如轮播图有幻灯片模式,轮转模式,类3D效果)

    3.UI设定模式与自定义(比如轮播图的按钮形状)

上面的分析中,又以位置变化和速度变化为运动功能的主要核心功能,接下来我们就通过一系列的运动示例来理解和实现运动功能。

 二、匀速运动:

 匀速运动是运动功能中最基本的运动功能,只需要将要移动的元素从一个位置移动到另一个位置,速度不变,将移动距离分成若干个片段,并将每个片段移动之间设置微弱的时间间隔,以达到视觉上的移动效果。

这里有一个需要注意的点:

1.移动元素需要给元素设置绝对定位或者相对定位,不然设置left和right位置不会发生变化。以下是示例的HTML和CSS代码:

//html
<div></div>
<span></span>
<button id="bit">run</button>

//css
div{
    position: absolute;
    left: 0px;/*向右移动*/
    /* left: 600px; *//*向左移动*/
    top: 0px;
    width: 100px;
    height: 100px;
    background: red;
}
span{
    position: absolute;
    left: 300px;
    top: 1px;
    width: 1px;
    height: 100px;
    background-color: #000;
}
button{
    margin-top: 150px;
    height: 25px;
    width: 35px;
}

2.要指定运动的起点和终点,不然运动会无限循环执行下去。在示例中,起点位置有css样式设定固定值,用DOM对象的的offsetLeft属性来获取元素距离浏览器左侧的距离,并且每执行一次移动之前都要判断距离目标位置的差值是否大于一次移动的距离,如果小于要移动的距离直接设置到达终点,结束运动。

 1 //通过标签名获取第一个div元素节点对象
 2 var oDiv=document.getElementsByTagName("div")[0];
 3 //通过id获取button节点对象
 4 var oBut=document.getElementById("bit");
 5 //创建一个定时器变量初始为空
 6 var timer=null;
 7 //通过button点击事件触发运动函数
 8 oBut.onclick=function(){
 9     startMove(oDiv);
10 }
11 //执行匀速运动的方法startMove,参数obj为运动的体的document节点对象
12 function startMove(obj){
13     //启动定时器前,关闭之前开启的定时器
14     clearInterval(timer);
15     //初始化一个变量,用于设置运动速度
16     var iSpeed;
17     //处理业务逻辑
18     //运动体大于距离目标点300时(这里是span标签的右侧零像素),运动体往左运动,反之则往右运动
19     if(obj.offsetLeft>300){
20         iSpeed= -8;
21     }else{
22         iSpeed= 8;
23     }
24     //定义定时器
25     timer = setInterval(function (){
26         //Math.ads()取当前位置与一单位移动距离的绝对值
27         //当前位置比一单位移动距离小时,直接设置运动体到终点,并结束定时器
28         //....................大时,执行运动运算
29         if(Math.abs(300-obj.offsetLeft)<Math.abs(iSpeed)){
30             clearInterval(timer);
31             obj.style.left='300px';
32         }else{
33             obj.style.left=obj.offsetLeft+iSpeed+'px';
34         }
35     },30);
36 }

3.看代码14行、30行代码clearInterval(timer)两处关闭定时器,setInterval()是每间隔多长时间执行一次,30行大家都通常能理解,当执行到终点时就关闭定时器。14行代码可能会有点懵,为什么在启动运动之前要关闭定时器呢?原因是如果出现多次触发运动启动时,会开启多个定时器叠加执行(具体知识点是闭包和定时器[模拟出来的]多线程),多个定时器叠加就相当于开倍速了,像实例中是点击触发运动,如果不管之前的定时器就出发运动,没点击一次就会有一次速度叠加。

4.最后既然要封装功能就要让代码具备复用性,所以可见将示例中的匀速移动函数提取出来,除了传入指定运动元素外,还需要用参数指定运动的终点位置和运动速度。

 

//匀速运动算法
function startMove(dom,target,iSpeed){
    clearInterval(timer);
    if(dom.offsetLeft>target){
        iSpeed= -1 * iSpeed;
    }else{
        iSpeed= 1 * iSpeed;
    }
    timer = setInterval(function (){
        if(Math.abs(target-dom.offsetLeft)<Math.abs(iSpeed)){
            clearInterval(timer);
            dom.style.left = target+'px';
        }else{
            dom.style.left=dom.offsetLeft+iSpeed+'px';
        }
    },30);
}
//参数:要运动的元素,运动到指定位置,运动的速度
//注意1:需要在调用方法的作用域上声明timer变量
//注意2:示例代码指定位置只有距离浏览器左侧的距离,如果是复杂的运动功能,可以将target封装成一个位置对象,还包括距离浏览器上边距、元素的大小,元素的透明度

 

后续博客持续更新,最后封装一个轮播图插件,当然这也不是最后的终点,学无止境,生命不息,挑战自我。

posted @ 2019-02-15 21:24  他乡踏雪  阅读(409)  评论(0编辑  收藏  举报