动画框架基础部分

滚动到顶部: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;
             50px;
            background: blue;
            border-radius: 50%;
            /* transform:translate(0px,100px) */
        }

        hr {
            border- 1px 0px 0px 1px;
            border-style: solid;
            border-color: red;
            position: absolute;
             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;
             50px;
            background: blue;
            border-radius: 50%;
            /* transform:translate(0px,100px) */
        }

        hr {
            border- 1px 0px 0px 1px;
            border-style: solid;
            border-color: red;
            position: absolute;
             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;
             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;
             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>

原文地址:https://www.cnblogs.com/leee/p/7404991.html