Logan 如果前面还有路,答应我,跑下去...

JS 动画效果

2017-10-17
Logan

JS 速度动画

// 设置定时器,获取需要移动的元素
var timer = null,
	box = document.getElementById('box');
function moveAnimation(target) {
	// 函数开始清除定时器,防止定时器叠加
    clearInterval(timer);
    // 定义速度
    var speed = 0;
    // 根据当前位置与目标位置的大小关系来确定速度的正负值
    if (target > box.offsetLeft) {
        speed = 1;
    } else {
        speed = -1;
    }
    timer = setInterval(function(){
        if (box.offsetLeft == target) {
        	// 当运动到目标位置时清除定时器
            clearInterval(timer);
        } else {
        	// 设置位置的变化
            box.style.left = box.offsetLeft + speed + 'px';
        }
    },3)
}

JS 透明度动画

实现方式与速度动画大致相同。

// 设置定时器,获取需要移动的元素,设置透明度初始值
var timer = null,
	box = document.getElementById('box'),
	op = 30;
function moveAnimation(target) {
	// 函数开始清除定时器,防止定时器叠加
    clearInterval(timer);
    // 定义透明度改变速度
    var speed = 0;
    // 根据当前透明度与目标透明度的大小关系来确定速度的正负值
    if (target > op) {
        speed = 1;
    } else {
        speed = -1;
    }
    timer = setInterval(function(){
        if (op == target) {
        	// 当达到目标透明度时清除定时器
            clearInterval(timer);
        } else {
        	// 设置透明度的变化
            op += speed;
            box.style.opacity = op/100;
        }
    },3)
}

JS 缓冲动画

// 设置定时器,获取需要移动的元素
var timer = null,
	box = document.getElementById('box');
function moveAnimation(target) {
	// 函数开始清除定时器,防止定时器叠加
    clearInterval(timer);
    // 定义速度
    var speed = 0;
    timer = setInterval(function(){
    	// 距离目标位置越近,速度越小
    	speed = (target - box.offsetLeft)/40;
    	// 为防止速度过小而无效,对其取整
        speed = speed>0 ? Math.ceil(speed) : Math.floor(speed);
        if (box.offsetLeft == target) {
        	// 当运动到目标位置时清除定时器
            clearInterval(timer);
        } else {
        	// 设置位置的变化
            box.style.left = box.offsetLeft + speed + 'px';
        }
    },3)
}

JS 多物体动画

核心思想是通过设置相应元素的属性,为不同元素设置相应的定时器及参数

lis[i].timer = null;

window.onload = function(){
	// 获取到所有需要加动画的元素
    var lis = document.getElementsByTagName('li');
    // 遍历所有需要加动画的元素
    for (var i = 0; i < lis.length; i++) {
    	// 为每个元素设置相应的定时器
        lis[i].timer = null;
        lis[i].onmouseover = function(){
        	// 传入两个参数,第一个参数为了确保获取到相应元素的属性
            changeWidth(this,400);
        }
        lis[i].onmouseout = function(){
            changeWidth(this,200);
        }
    }
}
function changeWidth(obj,target) {
	// 清除对应的定时器
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
    	// 定义并设置速度的值
        var speed = 0;
        if (target>obj.offsetWidth) {
            speed = Math.ceil((target-obj.offsetWidth)/8);
        } else {
            speed = Math.floor((target-obj.offsetWidth)/8);
        }
        if (obj.offsetWidth == target) {
        	// 达到目标位置时清除定时器
            clearInterval(obj.timer);
        } else {
        	// 改变元素属性
            obj.style.width = obj.offsetWidth+speed+'px';
        }
    },30)
    return false;
}

JS 获取样式

obj.offsetWidth属性可以返回对象的padding+border+width属性值之和

objstyle.width返回值就是行内样式定义的width属性值

为防止出现偏差,我们封装一个getStyle的函数

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

整体的JS代码如下

window.onload = function(){
    var lis = document.getElementsByTagName('li');
    for (var i = 0; i < lis.length; i++) {
    	// 为元素设置对应的定时器
        lis[i].timer = null;
        lis[i].onmouseover = function(){
            changeWidth(this,400);
        }
        lis[i].onmouseout = function(){
            changeWidth(this,200);
        }
    }
}
function changeWidth(obj,target) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
        var speed = 0,
            icur = parseInt(getStyle(obj,'width'));
        if (target>icur) {
            speed = Math.ceil((target-icur)/10);
        } else {
            speed = Math.floor((target-icur)/10);
        }
        if (icur == target) {
            clearInterval(obj.timer);
        } else {
        	// 调用getStyle函数时注意属性使用引号括起来
            obj.style.width = icur+speed+'px';
        }
    },30)
    return false;
}
// 获得属性的函数
function getStyle(obj,attr){
    if(obj.currentStyle){
        return obj.currentStyle[attr];
    }else{
        return getComputedStyle(obj,false)[attr];
    }
}

JS 改变任意属性值

主要是区别透明度与其他属性值的不同

function changeStyle(obj,target,attr) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
        var icur = 0;
        if (attr == 'opacity') {
        	// 透明度取小数再乘一百
            icur = Math.round(parseFloat(getStyle(obj,attr))*100);
        } else {
            icur = parseInt(getStyle(obj,attr));
        }
        var speed = (target-icur)/10;
        speed = speed>0?Math.ceil(speed):Math.floor(speed);
        if (icur == target) {
            clearInterval(obj.timer);
        } else {
            if (attr == 'opacity') {
            	// 设置透明度
                obj.style[attr] = (icur+speed)/100;
            } else {
                obj.style[attr] = icur+speed+'px';
            }
        }
    },30)
    return false;
}

JS链式动画

元素运动达到目标位置之后,再次调用getStyle函数,注意this的变化

// 传入第四个参数
function changeStyle(obj,target,attr,fn) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
        var icur = 0;
        if (attr == 'opacity') {
            icur = Math.round(parseFloat(getStyle(obj,attr))*100);
        } else {
            icur = parseInt(getStyle(obj,attr));
        }
        var speed = (target-icur)/10;
        speed = speed>0?Math.ceil(speed):Math.floor(speed);
        if (icur == target) {
            clearInterval(obj.timer);
            // 调用第四个参数
            if (fn) {
            	// 改变this指向
                fn.call(obj);
            }
        } else {
            if (attr == 'opacity') {
                obj.style[attr] = (icur+speed)/100;
            } else {
                obj.style[attr] = icur+speed+'px';
            }
        }
    },30)
    return false;
}
// 调用方法
lis[0].onmouseover = function(){
    changeStyle(this,400,'width',function(){
        changeStyle(this,200,'height')
    });
}

最终运动框架

主要完成同时运动功能,运用JSON数据来实现

function changeStyle(obj,json,fn) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
    	// 定义检测动画是否完成的参数
        var flag = true;
        // 遍历元素样式
        for(var attr in json){
        	// 获得样式的值
            var icur = 0;
            if (attr == 'opacity') {
                icur = Math.round(parseFloat(getStyle(obj,attr))*100);
            } else {
                icur = parseInt(getStyle(obj,attr));
            }
            // 获得变化速度
            var speed = (json[attr]-icur)/10;
            speed = speed>0?Math.ceil(speed):Math.floor(speed);
            if (icur != json[attr]) {
            	// 若样式数值未达到目标值,则flag为false
                flag = false;
            }
            // 改变样式数值
            if (attr == 'opacity') {
                obj.style[attr] = (icur+speed)/100;
            } else {
                obj.style[attr] = icur+speed+'px';
            }
        }
        // 动画完成则清除定时器并执行链式动画
        if (flag) {
            clearInterval(obj.timer);
            if (fn) {
                fn.call(obj);
            }
        }
    },30)
    return false;
}
// 调用方法
lis[0].onmouseover = function(){
    changeStyle(this,{width:205,height:200},function(){
        changeStyle(this,{opacity:30})
    });
}

上一篇 JavaScript和树

下一篇 JS DOM事件

留言

目录