动画框架基础部分
滚动到顶部:requestAnimationFrame
function goTop(ms){
var originTop=document.body.scrollTop;
var translatYPS=originTop*16.7/ms;
var count=0;
console.log(translatYPS)
requestAnimationFrame(function frameFn(){
console.log(count++)
var currentTop=document.body.scrollTop;
// console.log(currentTop)
if(currentTop>0){
document.body.scrollTop=currentTop-translatYPS;
requestAnimationFrame(frameFn)
}
})
}
goTop(1000)
滚动到顶部:定时器
function goTop(ms){
var originTop=document.body.scrollTop;
var translatYPS=originTop*1000/60/ms;
var count=0;
console.log(translatYPS)
var timer=setInterval(()=>{
var currentTop=document.body.scrollTop;
if(currentTop>0){
console.log(count++)
document.body.scrollTop=currentTop-translatYPS;
}else{
clearInterval(timer)
}
},1000/60)
}
goTop(1000)
正弦余弦函数
<!DOCTYPE html>
<html>
<head>
<style>
*{margin: 0}
body {
height: 500px;
}
[type="button"]{
position: relative;
left:-50px;
}
#circle {
position: relative;
top: 225px;
float: left;
text-align: center;
line-height: 50px;
width: 50px;
background: blue;
border-radius: 50%;
/* transform:translate(0px,100px) */
}
hr {
border-width: 1px 0px 0px 1px;
border-style: solid;
border-color: red;
position: absolute;
width: 500px;
}
hr:nth-of-type(1) {
top: 0px;
}
hr:nth-of-type(2) {
top: 125px;
}
hr:nth-of-type(3) {
top: 225px;
}
hr:nth-of-type(4) {
top: 250px;
}
hr:nth-of-type(5) {
top: 275px;
}
hr:nth-of-type(6) {
top: 375px;
}
hr:nth-of-type(7) {
top: 500px;
}
</style>
</head>
<body>
<button type="button">开始正弦运动</button>
<button type="button">开始余弦运动</button>
<div id='circle'>X</div>
<hr>
<hr>
<hr>
<hr>
<hr>
<hr>
<hr>
<script>
let btns = document.querySelectorAll('[type=button]');
let circle = document.querySelector('#circle');
let x = 0;
let maxLength = 500;
//Y轴最大高度
let A = 100;
//x轴的系数
let w = 2;
//A*Math.sin(++y*w*Math.PI/180)(1px相当1角度)一帧水平方向走1px(这里为一角度)。
//Math.PI/180 每角度占的弧度y*Math.PI/180增加的弧度(1px这里相当1角度相当多少弧度)
//(!inx?0:Math.PI / 2) 正弦 余弦 是否加Math.PI/2
for (let [inx, btn] of btns.entries()) {
(function () {
let tranX=!inx?0:Math.PI / 2;
btn.addEventListener('click', function () {
requestAnimationFrame(function frameFn() {
console.log(circle.style.transform)
if (getTranslatePosition(circle, 'x') < maxLength) {
++x;
circle.style.transform = 'translate(' + x + 'px,' + (-A * Math.sin(w * (x * Math.PI / 180 + tranX))) + 'px)';
requestAnimationFrame(frameFn);
}
})
})
})(inx)
}
//"translate(264px, 99.4522px)".match(/translate\((.*)px,(.*)px\)/)
function getTranslatePosition(el, direction) {
let reg = /translate\((.*)px,(.*)px\)/;
let transformArr = el.style.transform.match(reg);
return !transformArr ? 0 :
direction = 'x' ? transformArr[1] :
direction = 'y' ? transformArr[2] :
[transformArr[1], transformArr[2]];
}
</script>
</body>
</html>
精确控制动画的时间
<!DOCTYPE html>
<html>
<head>
<style>
* {
margin: 0
}
body {
height: 500px;
}
[type="button"] {
position: relative;
left: -50px;
}
#circle {
position: relative;
top: 225px;
float: left;
text-align: center;
line-height: 50px;
width: 50px;
background: blue;
border-radius: 50%;
/* transform:translate(0px,100px) */
}
hr {
border-width: 1px 0px 0px 1px;
border-style: solid;
border-color: red;
position: absolute;
width: 500px;
}
hr:nth-of-type(1) {
top: 0px;
}
hr:nth-of-type(2) {
top: 125px;
}
hr:nth-of-type(3) {
top: 225px;
}
hr:nth-of-type(4) {
top: 250px;
}
hr:nth-of-type(5) {
top: 275px;
}
hr:nth-of-type(6) {
top: 375px;
}
hr:nth-of-type(7) {
top: 500px;
}
</style>
</head>
<body>
<button type='button' id='sin'>开始正弦运动5S</button>
<button type='button' id='cos'>开始余弦运动5S</button>
<div id='circle'>X</div>
<hr>
<hr>
<hr>
<hr>
<hr>
<hr>
<hr>
<script>
let circle = document.querySelector('#circle');
let x = 0;
//动画持续时长
let duration = 5000;
//Y轴最大高度
let A = 100;
//x轴的系数
let w = 2;
sin.addEventListener('click', function () { move(circle, duration, sinFn) });
cos.addEventListener('click', function () { move(circle, duration, cosFn) });
//duration {{numebr}}持续时长
//movefn {{function}}移动函数
//console.log(timeProportion,circle.style.transform)
//timeProportion 当前帧占整个周期的时间比例
function move(el, duration, movefn) {
let start = Date.now()
requestAnimationFrame(function frameFn() {
let timeProportion = (Date.now() - start) / duration;
if (timeProportion < 1) {
movefn(el)
requestAnimationFrame(frameFn);
}
})
}
function sinFn(el) {
el.style.transform = 'translate(' + ++x + 'px,' + (-A * Math.sin(w * (x * Math.PI / 180))) + 'px)';
}
function cosFn(el) {
el.style.transform = 'translate(' + ++x + 'px,' + (-A * Math.sin(w * (x * Math.PI / 180 + Math.PI / 2))) + 'px)';
}
</script>
</body>
</html>
动画的基本封装
start: function (finished) {
var startTime = Date.now();
var duration = this.duration,
self = this;
requestAnimationFrame(function step() {
var p = (Date.now() - startTime) / duration;
if (p < 1.0) {
self.progress(p);
requestAnimationFrame(step);
} else {
if (typeof finished === 'function') {
finished()
}
self.progress(1.0);
}
});
}
动画的暂停与继续(封装时基于promise,使用时基于async await步)
<!DOCTYPE html>
<html>
<head>
<style>
#block {
position: absolute;
left: 100px;
top: 100px;
width: 20px;
height: 20px;
background: red;
border-radius: 50%;
}
</style>
</head>
<body>
<button type="button" id='btn'>暂停</button>
<button type="button" id='continuebtn'>继续</button>
<div id='block'></div>
<script>
class Animator {
constructor(fn, duration = 500) {
this.duration = duration;
this.pauseState = false;
this.startTime = 0;
this.pauseTime = [];
this.continueTime = [];
this.pauseCount=-1;
this.fn = fn;
}
static sum(arr=[]){
return arr.reduce((current,next)=>{
return current+next
},0)
}
go(delay = 0) {
console.log('delay',delay)
if (!delay) this.startTime = Date.now();
return new Promise((resolve, reject) => {
let frameFn = () => {
var proport = (Date.now() - this.startTime - delay) / this.duration;
if (proport < 1) {
if (!this.pauseState) {
this.fn(proport);
requestAnimationFrame(frameFn);
}
} else {
this.fn(1);
resolve('done');
}
}
requestAnimationFrame(frameFn);
})
}
pause() {
this.pauseCount++;
this.pauseTime.push(Date.now());
console.log('this.pauseTime',this.pauseTime)
this.pauseState = true;
}
continue() {
this.continueTime.push(Date.now());
console.log(this.continueTime,this.pauseTime)
this.pauseState = false;
this.go(Animator.sum(this.continueTime) - Animator.sum(this.pauseTime))
}
}
var a1 = new Animator(function (p) {
var tx = 500 * p;
block.style.transform = 'translateX(' + tx + 'px)';
}, 3000);
var a2 = new Animator(function (p) {
var ty = 300 * p;
block.style.transform = 'translate(500px,' + ty + 'px)';
}, 3000);
block.addEventListener('click', async function () {
await a1.go();
await a2.go();
});
btn.addEventListener('click', function () {
a1.pause();
})
continuebtn.addEventListener('click', function () {
a1.continue();
})
</script>
</body>
</html>
多动画的控制(暂停、继续)(promise async await)
<!DOCTYPE html>
<html>
<head>
<style>
#block {
position: absolute;
left: 100px;
top: 100px;
width: 20px;
height: 20px;
background: red;
border-radius: 50%;
}
</style>
</head>
<body>
<button type="button" id='btn'>暂停</button>
<button type="button" id='continuebtn'>继续</button>
<div id='block'></div>
<script>
class Cartoon {
constructor(fn, duration = 500) {
this.duration = duration;
this.fn = fn;
this.startTime = 0;
this.pauseTimeArr = [];
this.continueTimeArr = [];
}
static sum(arr = []) {
return arr.reduce((current, next) => {
return current + next
}, 0)
}
//执行动画
go() {
this.startTime = Date.now();
return new Promise((resolve, reject) => {
let frameStep = () => {
let proport = 0;
let isPause = this.pauseTimeArr.length > this.continueTimeArr.length;
if (isPause) {
//console.log('length', this.pauseTimeArr.length, this.continueTimeArr.length)
proport = (Cartoon.sum(this.pauseTimeArr) - Cartoon.sum(this.continueTimeArr) - this.startTime) / this.duration;
}
else {
proport = (Date.now() - this.startTime - (Cartoon.sum(this.continueTimeArr) - Cartoon.sum(this.pauseTimeArr))) / this.duration;
}
//console.log('比例', proport)
if (proport < 1) {
if (!isPause) {
this.fn(proport);
}
requestAnimationFrame(frameStep);
} else {
this.fn(1);
resolve('done');
}
}
requestAnimationFrame(frameStep);
})
}
//暂停动画
pause() {
if (this.startTime) this.pauseTimeArr.push(Date.now())
}
//继续动画(暂停过)
continue() {
if (this.startTime && (this.pauseTimeArr.length > this.continueTimeArr.length)) this.continueTimeArr.push(Date.now())
}
//重置动画
reset() {
}
}
class Cartoons {
constructor(...cartoons) {
this.cartoons = []
this.currentInx=0;
for (let cartoon of cartoons) {
this.cartoons.push(new Cartoon(...cartoon))
}
}
async go() {
while (this.currentInx < this.cartoons.length) {
if (await this.cartoons[this.currentInx].go()=='done')
this.currentInx++
}
}
pause() {
this.cartoons[this.currentInx].pause()
}
continue() {
this.cartoons[this.currentInx].continue()
}
}
// let a1 = new Cartoon(function (p) {
// let tx = 500 * p;
// block.style.transform = 'translateX(' + tx + 'px)';
// }, 3000);
// let a2 = new Cartoon(function (p) {
// let ty = 300 * p;
// block.style.transform = 'translate(500px,' + ty + 'px)';
// }, 3000);
var c1 = [function (p) {
let tx = 500 * p;
block.style.transform = 'translateX(' + tx + 'px)';
}, 3000]
var c2 = [function (p) {
let ty = 300 * p;
block.style.transform = 'translate(500px,' + ty + 'px)';
}, 3000]
let c = new Cartoons(c1, c2)
block.addEventListener('click', function () {
c.go();
// console.log(111, await a1.go())
//await a2.go();
});
btn.addEventListener('click', function () {
c.pause();
})
continuebtn.addEventListener('click', function () {
c.continue();
})
// block.addEventListener('click', async function () {
// console.log(111, await a1.go())
// //await a2.go();
// });
// btn.addEventListener('click', function () {
// a1.pause();
// })
// continuebtn.addEventListener('click', function () {
// a1.continue();
// })
</script>
</body>
</html>
知识没有高低贵贱之分。