正常情况下我们要写一个运动的效果会用到tween.js这么一个插件,这个东西不是一般人写出来的,因为里面涉及的运动效果都是经过一堆数学的函数运算出来的,我们平常人是写不出来的,所有我们作为js初学者可以为自己封装一个简单的(匀速线性)运动框架。涉及到复杂运动时只需改变函数中的公式即可。
如何运动:
给大家出一道题,从起点A走到目的地B,一共用了1000毫秒,每一次是30毫秒,请问你在这里面得到了哪些信息?
信息有哪些呢?
第一个,总时长是:1000毫秒
第二个,多久时间走一次?30毫秒
第三个,走的总次数:1000/30
第四个,距离:B-A
第五个,步长:距离/总次数
总结以上可以得出运动动画几要素:起始位置、结束位置、位移、运动经过的时间、元素每次移动的步长、多久时间走一步。
运动框架的实现思路:就是在一定的时间段里面改变left、top、width、height,到达目的地之后停止。
可以先思考一下,在页面里如何让div动起来?
思考如下:
1. 设置div的时候为绝对定位,因为只有绝对定位之后,left、top等值才会在页面上显示出来。否则在页面上看不见div。
2. 可以给div设置点击事件,在函数里面定义总的步数count,总距离dis,速度step=dis/count,还需要设置一个当前的步数,给它进行初始化n=0
3. 然后使用计时器setInterval(),获取到div当前的距离,让div动起来。
—单属性运动框架封装代码如下—-
/**
* 单属性运动框架
*/
function animate(element, attrName, end, speed) {
// 先清除 element 上已有的运动动画效果
clearInterval(element.timer);
var start = parseFloat(css(element, attrName)), // 起点
range = end - start; // 范围
// 启动计时器前记录起始运动时间
var startTime = +new Date();
// 启动计时器,开始运动
element.timer = setInterval(function() {
// 实际运动时间
var elapsed = Math.min(+new Date() - startTime, speed);
// 公式
var result = elapsed * range / speed + start;
// 设置css
element.style[attrName] = result + "px";
// 判断
if (elapsed === speed)
clearInterval(element.timer);
}, 1000/60);
}
该函数只能改变元素单一属性,简单的来说就是不能让元素宽和移动同时改变,同时进行。
- 示例
$("#start").onclick = function(){
animate($("#box"), "left", 500, 3000);
}//当点击start时,id名为box的div定位属性left在3s中变成500px;
—–多属性运动框架封装—–
通过将要改变的属性存在对象options中,来实现多属性改变:
/**
* 运动
* @param element 待添加运动动画效果的 DOM 元素对象
* @param options 多属性目标终值选项
* @param speed 限定运动的总时间
* @param fn 在运动结束后需要继续执行的函数
*/
function animate(element, options, speed, fn) {
// 清除元素上已有的运动动画计时器
clearInterval(element.timer);
// 多属性初值、范围值
var start = {}, range = {};
for (var attrName in options) {
start[attrName] = parseFloat(css(element, attrName));
range[attrName] = options[attrName] - start[attrName];
}
// 记录开始运动的时间
var startTime = +new Date();
// 启动计时器,实现运动动画效果:将计时器 id 缓存
element.timer = setInterval(function() {
// 计算已经运动的时间
var elapsed = Math.min(+new Date() - startTime, speed);
// 多属性按公式运算:线性运动
for (var attrName in options) {
// 公式:结果 = 运动时间 * 总范围 / 总时间 + 起始
var result = elapsed * range[attrName] / speed + start[attrName];
// 设置CSS
element.style[attrName] = result + ("opacity" === attrName ? "" : "px");
}
// 判断是否停止计时器
if (elapsed === speed) {
clearInterval(element.timer);
// 如果有运动结束后需要继续执行的函数,则调用函数执行
fn && fn();
}
}, 1000/60);
}
- 示例
animate($("img")[0], {width: 590,left:500}, 5000, function() {
// animate($("img")[0], {opacity: 0}, 3000)
});//在5s中内将img元素宽设置为590px,定位属性left设置为500px,
在该运动执行完毕后继续执行跟随function函数里面的内容(运动),可在后面依次跟随多个function来设置运动的逻辑。