前言
最近在研究web端链式动画,多个元素按给的点位列表同时移动,并且可暂停或继续
一、动画的两种实现方式
1.JavaScript
setTimeOut(fn,time):经过time时间后执行回调fn,只执行一次。
setInterVal(fn,time):每过time时间执行回调fn,执行多次,直到执行清除函数cleanInterVal()。
requestAnimationFrame(): 执行时间是浏览器刷新频率决定的,一般遵循 W3C 标准,它在浏览器每次刷新页面之前执行。
2.CSS3
过渡效果:transition
动画:animation
还有canvans等其他的就不说了
二、运动效果
1.setInterVal+transition
需要canvans画出元素的移动轨迹,在test的css样式增加transition: all .5s,达到每改变一次位置的过渡效果:
<body>
<canvas id="myCanvas" width="500px" height="500px" style="position:absolute;left:0;top:0;z-index:-1">
</canvas>
<button id="btn1" >点击</button>
<div id="test" style="height: 50px;width: 50px;background:pink;position:absolute;top:40px;left:0;"></div>
</body>
setInterVal的500ms交互时间与test元素的.5s过渡时间一样,js使元素每.5s改变一次位置:
//路线数据
var pointList = [{x:'50',y:'20'},{x:'100.9',y:'100.1'},{x:'250',y:'150'},{x:'200',y:'250'},{x:'180',y:'80'}];
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//画路线
context.beginPath();
context.moveTo(pointList[0].x, pointList[0].y);
for(var i = 1; i < pointList.length; i++){
context.lineTo(pointList[i].x, pointList[i].y);
console.log(pointList[i].x, pointList[i].y);
}
btn1.onclick = function(){
var i = 0;
var times = setInterval( function() {
test.style['left'] = pointList[i].x + 'px';
test.style['top'] = pointList[i].y + 'px';
i++;
if (i == pointList.length) {
clearInterval(times);
}
},500)//每500ms改变一次元素位置
}
2.setInterVal+js
如果想要canvans的画线跟元素运动同时进行,元素到哪就画到哪,move函数的两个点之间的动画函数,每隔16ms移动(x1到x2的距离/20),实现画线与元素同时前进一点点,由于浏览器刷新的间隔差不多为16ms所以每次移动1像素,就会有滑动的效果:
function getCSS(obj,style){
if(window.getComputedStyle){
return getComputedStyle(obj)[style];
}
return obj.currentStyle[style];
}
function move(obj,left,top,targetX,targetY,step,fn){
//如果没有建立定时器对象,则在obj下建立定时器对象
if(!obj.timers){obj.timers = {};}
//清除定时器
clearInterval(obj.timers[left]);
//声明当前值变量cur
var cur,cur2,times=0;
//判断步长step的正负值
//获取样式当前值并赋值给cur
curX = parseFloat(getCSS(obj,left));
curY = parseFloat(getCSS(obj,top));
var stepX = (targetX-curX) / 20;
var stepY = (targetY-curY) / 20;
console.log(stepX,stepY,"步长")
//开启定时器
obj.timers[left] = setInterval(function(){
times++;
//获取样式当前值并赋值给cur
curX = parseFloat(getCSS(obj,left));
curY = parseFloat(getCSS(obj,top));
若步长设置值使得元素超过目标点时,将步长设置值更改为目标点值 - 当前值
if((curX + stepX - targetX)*stepX > 0){
stepX = targetX - curX;
console.log(stepX,'超过')
}
//将合适的步长值赋值给元素的样式
// console.log(times,"draw")
obj.style[left] = curX + stepX + 'px';
obj.style[top] = curY + stepY + 'px';
createCanvasTracks(obj.offsetLeft,obj.offsetTop);
//当元素到达目标点后,停止定时器
if(times == 20){
clearInterval(obj.timers[left]);
obj.timers[left] = 0;
times = 0;
fn && fn.call(obj);
}
},16);
}
function createCanvasTracks(x,y){
context.lineTo(x,y);
context.stroke();
}//画图
每隔400ms运行move函数。
btn1.onclick = async function(){
var i = 0
var timeBox = setInterval(() => {
move(test,'left','top',pointList[i].x,pointList[i].y,10)
console.log(pointList[i].x,'pointIndex')
if(i == pointList.length - 1 && pointList[i].x == pointList[0].x && pointList[i].y == pointList[0].y){
i = 0;
console.log('回到原点',pointList[i])
}else{
i++;
}
if(i == pointList.length ){
if(pointList[i-1].x == pointList[0].x && pointList[i-1].y == pointList[0].y){
i = 0;
}else{
clearInterval(timeBox)
console.log('end')
}
}
}, 400);
}
总结
以上都是自己搜索文章结合自己理解写出来的,还有一种是让元素暂停运动并且可以继续运动的代码实现,但是今天先写这些吧,如果有更好的实现方案欢迎你提出来。