JS学习-基础运动

多物体运动

多个物体用同一个函数时,函数里定义的定时器应该要每个物体对应一个定时器名称,不然会导致未完成运动就被关闭了,因为定时器名称一样,而开启定时器前会清除一下。

obj.timer

多值同时运动

  • 怎样同时运动?
startMove(this, 'width', 200, 10);
startMove(this, 'height', 200, 10);

下面的运动会清除掉上面的定时器,因为定时器开启前会先清除一下,所以这样不行。应该通过json传入数据,for in遍历。

  • 一个值到target了,另外一个还没有到,怎样判断?

要所有值都到了目标点才能清除定时器
解决方案

var oDiv1 = document.getElementById('div1');

oDiv1.onclick = function() {
    
    startMove(this, {
        width : 200,
        height: 300
    }, 10); //////json
}

function startMove(obj, json, iSpeed) {
    clearInterval(obj.iTimer);
    var iCur = 0;
        
    obj.iTimer = setInterval(function() {
        
        var iBtn = true;
                    
        for ( var attr in json ) {
            
            //什么时候停止定时器?所有属性都运动到了目标点的时候
            
            var iTarget = json[attr];
            
            if (attr == 'opacity') {
                iCur = Math.round(css( obj, 'opacity' ) * 100);
            } else {
                iCur = parseInt(css(obj, attr));
            }
            
            if (iCur != iTarget) {
                iBtn = false; //判断是不是所有属性都运动到了目标点
                if (attr == 'opacity') {
                    obj.style.opacity = (iCur + iSpeed) / 100;
                    obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
                } else {
                    obj.style[attr] = iCur + iSpeed + 'px';
                }
            }
            
        }
        
        //在for in循环外来看下,所有属性是不是都到了目标点
        if (iBtn) {
            clearInterval(obj.iTimer);
        }
        
    }, 30);
}

function css(obj, attr) {
    if (obj.currentStyle) {
        return obj.currentStyle[attr];
    } else {
        return getComputedStyle(obj, false)[attr];
    }
}

缓冲运动(减速运动)

越接近目标点,速度就越小

框架:
速度要在定时器里定义
速度=(目标值-当前值)/缩放系数
速度取整(保证能达到目标点)
停下条件:到达目标点

基本框架和前面的运动一样,只是速度iSpeed的处理不一样
json同样可以传入多值,都有缓冲效果,像多值同时运动一样

function startMove(obj, json, fn) {
    clearInterval(obj.iTimer);
    var iCur = 0;
    var iSpeed = 0;
        
    obj.iTimer = setInterval(function() {
        
        var iBtn = true;
                    
        for ( var attr in json ) {
                            
            var iTarget = json[attr];
            
            if (attr == 'opacity') {
                iCur = Math.round(css( obj, 'opacity' ) * 100);
            } else {
                iCur = parseInt(css(obj, attr));
            }
            //不同的运动形式主要速度算法不一样,其他部分都差不多
            iSpeed = ( iTarget - iCur ) / 8;
            //这里除/乘小数/减都可以,主要处理是这里,可以很好的控制停下的点
            iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
            //向上取整和向下取整
            //取整是因为offsetLeft是js解释出来的,会四舍五入,当乘或除到iSpeed小于0.5时就达到不了目标点
            //看下表解释
            if (iCur != iTarget) {
                iBtn = false;
                if (attr == 'opacity') {
                    obj.style.opacity = (iCur + iSpeed) / 100;
                    obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
                } else {
                    obj.style[attr] = iCur + iSpeed + 'px';
                }
            }
        }
        if (iBtn) {
            clearInterval(obj.iTimer);
            fn && fn.call(obj);
        }
    }, 30);
}

function css(obj, attr) {
    if (obj.currentStyle) {
        return obj.currentStyle[attr];
    } else {
        return getComputedStyle(obj, false)[attr];
    }
}
offsetLeft iSpeed style.left
495 0.625 495.625
496 0.5 496.5
497 0.375 497.375
497 0.375 497.375
497.375后一直四舍五入,所以得出速度也一直是0.375,导致停在497.375的位置。

offsetLeft是JS解释,是计算后的值,会四舍五入并不带单位
style.left是CSS解释,会认小数的

JS运动应用

多图片展开、收缩

元素居中放大:除了要改变元素的宽高以外,还要改变元素定位(left,top),如果图片方法一倍,那么位移放大的宽高的一半

在用js去设置css样式的时候:在同一个代码块中,有些css样式的设置的权限(优先级)要高于其他的样式
解决方案:不放在同一代码块

带运动效果的留言本(瀑布流)

淘宝首页幻灯片

带运动的返回顶部

图片的预先加载 Image对象

如果一个页面有几十张图片,都是用src加载进去会导致打开页面慢,页面未加载完成,js也没有动作。

可以用数组把所有图片地址存起来,只用一个src,用户点下一张时把src地址换一下。这个可以解决一次加载多个src的问题,但当用户网络慢或者一张图片太大,会导致按下一张后要隔一定时间才加载出来。

最好方法应该是先把图片预加载
在页面刚打开的时候,我们去加载第一张图片,然后页面加载完成以后,在用户看的时间内,去加载后面的内容,那么我们必须有个工具 -> Image对象

new Image()

var oImage = new Image();

属性:

  • src : 当我们给Image对象的src属性赋值一个url的时候,这个Image对象就去会加载url资源(有点像下载器),加载完成以后的资源被保存到了浏览器的缓存文件夹里面,下次如果我们要去调用这个url地址的时候,直接是从缓存文件夹读取到的,所以速度很快。
  • onload : 当资源加载完成的时候触发
  • onerror : 当资源加载失败的时候触发

应用:预加载图片-相册

var iCur = 0;//记录第几张
function xunlei() {
    oImage.src = arr[iCur];
    oImage.onload = function() {
        iCur++;
        if (iCur < arr.length) {
            xunlei();    //递归
        }
    }
}
//当第0张加载完成后,开始加载第一张,一直到全部加载完成,
//加载完成以后的资源被保存到了浏览器的缓存文件夹里面,当需要用这个url时,照常赋值给src,它会直接从缓冲文件里读取

按需加载

高级运动

加减速运动

速度 +/-= 加速度

弹性运动

框架:
速度要是全局变量
速度 += (目标点 - 当前值)/系数;
速度 *= 摩擦系数;

系数最适取值:6 7 8
摩擦系数最适取值:0.7 0.75

停下条件:速度足够小,距离目标点足够近

if( Math.abs(速度)<=1 && Math.abs(目标点 - 当前值offset)<=1 ){
  ...
}

应用:弹性菜单

和缓冲运动区别:
缓冲运动框架
速度要在定时器里定义
速度=(目标值-当前值)/缩放系数
速度取整
停下条件:到达目标点

滚动歌词

用两行一样的歌词,叠在一起,上面一行是滚动的,下面行固定

弹性过界问题

当宽高出现负值时,非标准IE会报错
解决方案:有可能出现负值的时候,先判断是否 < 0 ,若是小于零则赋0;

碰撞运动

碰撞运动 : 首先找到碰撞的临界点 , 再确定运动的方向 , 然后去改对应的速度(速度取反)
应用:浮动广告

定时器问题

速度版的运动框架在老版本的浏览器中,切换到别的页面时,定时器会变得缓慢,导致多个定时器时会时间不一致,在新版本的浏览器中已经修复了这个问题。
解决方案

window.onfocus = function(){
    timer = setInterval(...);
};
//在切换页面时停止定时器,切换回来时在开定时器
//方法不算很好,onfocus、onblur可能还有兼容性问题
window.onblur = function(){
    clearInterval(timer);
};

这个问题在时间版运动框架中也有但是时间版中控制对象位置的t在切换回页面时会马上到时间了,所以位置也一瞬间从原来的位置跳到目标位置了;

时间版运动框架

与经典startMove的区别

  • 以时间为单位,而不是以速度为单位
  • 例子 : 从中间放大的图片

优点:经典版同时移动两个值的时候,如果两个值移动的距离不一样,会导致一个快一个慢的问题,时间版运动框架就没有这个问题

Tween

一个来自flash的运动算法
JQ中也在使用tween算法

Tween公式:4个参数

  • t:current time(当前时间)
  • b:beginning value(初始值)
  • c: change in value(变化量)
  • d:duration(持续时间)
  • return (目标点)

还有几个运动有a,p的值,这是用来控制幅度之类的,不写也可以,本身有默认值;

通过( new Date() ).getTime()获取当前时间

var startTime = now(); //放在定时器外,是1970年到现在的毫秒时间
var changeTime = now();//放在定时器内

var t = d - Math.max(0,startTime - changeTime + d);
//d是持续时间
//Math.max(0,startTime - changeTime + d)得到d-0的时间段
// d - Math.max(0,startTime - changeTime + d)得到0到d的时间段
//通过上面的方法获取到t的值
function now(){
    return (new Date()).getTime();
}

包含的运动有:

  • 匀速
  • 加/减速曲线
  • 加加/减减速曲线
  • 正弦衰减/增强曲线(弹动渐入/渐出)
  • 回退加速/减速(回退渐入/渐出)
  • 弹球减振/加振(弹球渐出/渐入)
posted @ 2017-05-05 17:53  CHENJIAJIE  阅读(371)  评论(0编辑  收藏  举报