动画插件封装
最近这段时间一直都在研究关于动画方法的知识,说实话确实不容易,主要还是动画算法这方面比较难,毕竟没学过。当然也有所收获,明白了基本动画的原理是什么,所以自己也封装了一个简单的动画插件来巩固自己所学。
动画插件的实现方式
对于前端来说,主要实现动画的方式就是css(transition , animation),js(setTimeout , setInterval , requestAnimationFrame),canvas,svg等方式,在这里我主要是通过requestAnimationFrame来实现动画效果的。
插件说明
该插件接受5个参数:
- 第一个参数是需要动画的目标元素。
- 第二个参数是需要动画的属性,是一个对象。
- 第三个参数是动画的总时长。
- 第四个参数是动画的效果。目前支持三种动画效果,linear,easeIn,easeOut。
- 第五个参数是动画结束之后的回调函数。
该插件可以实现多个属性一起动画效果,也可以实现单个属性动画效果,也可以实现一个属性接着一个属性动画效果。由于使用的是回调函数,所以当一个接着一个属性来实现动画效果的时候,会产生回调函数嵌套。
插件代码
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> |
原文地址:https://www.cnblogs.com/lijianming180/p/12026664.html
时间: 2024-11-07 06:38:38