帧动画插件

▼魔方 西西 提交于 2019-12-12 01:40:28

动画插件封装

最近这段时间一直都在研究关于动画方法的知识,说实话确实不容易,主要还是动画算法这方面比较难,毕竟没学过。当然也有所收获,明白了基本动画的原理是什么,所以自己也封装了一个简单的动画插件来巩固自己所学。

动画插件的实现方式

对于前端来说,主要实现动画的方式就是css(transition , animation),js(setTimeout , setInterval , requestAnimationFrame),canvas,svg等方式,在这里我主要是通过requestAnimationFrame来实现动画效果的。

插件说明

该插件接受5个参数:

  1. 第一个参数是需要动画的目标元素。
  2. 第二个参数是需要动画的属性,是一个对象。
  3. 第三个参数是动画的总时长。
  4. 第四个参数是动画的效果。目前支持三种动画效果,linear,easeIn,easeOut。
  5. 第五个参数是动画结束之后的回调函数。

该插件可以实现多个属性一起动画效果,也可以实现单个属性动画效果,也可以实现一个属性接着一个属性动画效果。由于使用的是回调函数,所以当一个接着一个属性来实现动画效果的时候,会产生回调函数嵌套。

插件代码

function  (element , props , duration , easing , callback) {    if (typeof element !== 'object' && element.nodeType !== 1) {        return;    };    if (typeof props !== 'object' && props.toString() !== '[object Object]') {        return;    };    var noop = function () {};    this.element = element;    this.props = props;    this.duration = duration || 600;    this.easing = easing || 'linear';    this.callback = callback || noop;    this.tickID = 0;    this.styles = this.getStyle();    this.animate();};Animator.prototype = {    getStyle : function () {        return window.getComputedStyle ? window.getComputedStyle(this.element) : this.element.currentStyle();    },    animate : function () {        for (var prop in this.props) {            this.step.call(this , prop);        }    },    step : function (prop) {        var self = this;        var initialValue = 0;        var beginTime = new Date();        var endValue = parseFloat(this.props[prop]);        var beginValue = parseFloat(this.styles[prop]);        var changeValue = parseFloat(endValue - beginValue);          var distance = 0;        var move = function () {            var p = (new Date() - beginTime) / self.duration;            if (p > 1) {                self.element.style[prop] = (prop === 'opacity') ? endValue : endValue + 'px';                cancelAnimationFrame(self.tickID);                self.tickID = null;                self.callback.call(self);            } else {                if (self.easing === 'linear') {                    distance = changeValue * p;                } else if (self.easing === 'easeIn') {                    distance = changeValue * p * p;                } else if (self.easing === 'easeOut') {                    distance = changeValue * (2 * p - p * p);                };                self.element.style[prop] = (prop === 'opacity') ? (beginValue + distance) : (beginValue + distance + 'px');                this.tickID = requestAnimationFrame(move);              }        };        move();    }};

实例代码

<html lang="en"><head>    <meta charset="UTF-8">    <title>Document</title>    <style>        *{            margin: 0;            padding: 0;            list-style: none;        }        .box{            width:100px;            height:100px;            background:#f60;            position:absolute;            top:50;            left:0;            border: 1px solid #000;大专栏  帧动画插件iv>        }    </style></head><body><button id="btn">click</button><div id="box" class="box"></div><script>function  (element , props , duration , easing , callback) {    if (typeof element !== 'object' && element.nodeType !== 1) {        return;    };    if (typeof props !== 'object' && props.toString() !== '[object Object]') {        return;    };    var noop = function () {};    this.element = element;    this.props = props;    this.duration = duration || 600;    this.easing = easing || 'linear';    this.callback = callback || noop;    this.tickID = 0;    this.styles = this.getStyle();    this.animate();};Animator.prototype = {    getStyle : function () {        return window.getComputedStyle ? window.getComputedStyle(this.element) : this.element.currentStyle();    },    animate : function () {        for (var prop in this.props) {            this.step.call(this , prop);        }    },    step : function (prop) {        var self = this;        var initialValue = 0;        var beginTime = new Date();        var endValue = parseFloat(this.props[prop]);        var beginValue = parseFloat(this.styles[prop]);        var changeValue = parseFloat(endValue - beginValue);          var distance = 0;        var move = function () {            var p = (new Date() - beginTime) / self.duration;            if (p > 1) {                self.element.style[prop] = (prop === 'opacity') ? endValue : endValue + 'px';                cancelAnimationFrame(self.tickID);                self.tickID = null;                self.callback.call(self);            } else {                if (self.easing === 'linear') {                    distance = changeValue * p;                } else if (self.easing === 'easeIn') {                    distance = changeValue * p * p;                } else if (self.easing === 'easeOut') {                    distance = changeValue * (2 * p - p * p);                };                self.element.style[prop] = (prop === 'opacity') ? (beginValue + distance) : (beginValue + distance + 'px');                this.tickID = requestAnimationFrame(move);              }        };        move();    }};var box = document.querySelector('#box');var btn = document.querySelector('#btn');btn.addEventListener('click' , function () {    new Animator(box , {        width : 300,        height : 300,        top : 200,        left : 100,        opacity : 0.5,        borderWidth : 20    });});//效果二btn.addEventListener('click' , function () {    new Animator(box , {        width : 500    } , 1000 , 'easeOut' , function () {        new Animator(box , {            height : 300,            left : 100,            borderWidth : 50        } , 1000 , 'easeIn' , function () {            new Animator(box , {                opacity : 0.6            })        });    });});</script>
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!