ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript アニメーション_JavaScript スキルの簡単な分析

JavaScript アニメーション_JavaScript スキルの簡単な分析

WBOY
WBOYオリジナル
2016-05-16 17:50:291090ブラウズ
アニメーションの原理

いわゆるアニメーションは、一連の動きによって形成される動画です。 Web ページでは、要素の CSS 値を常に変更することで動的な効果を実現できます。

使用される式

合計距離 S = 合計時間 T * 速度 V、つまり: V = S/T
現在の距離 s = S/T * 経過時間 t、つまりs = S * (t/T)
つまり、現在の距離 = 合計距離 * (経過時間/合計時間)
つまり、アニメーション要素の開始値 (アニメーション要素の終了値 - アニメーション要素の開始値) ) * (現在時刻 - 開始時刻) / (アニメーションにかかる時間) 値の形式

上記の式を使用すると、JavaScript の setInterval または setTimeout を使用して簡単なアニメーションを作成できます。
ただし、アニメーション ライブラリを構築したい場合は、他の要素を考慮する必要があります。 たとえば、同じ要素のアニメーションは連続して実行する必要があります。さまざまな要素のアニメーションを同時に実行できます。

この場合、これらのアニメーションを管理するには別のオブジェクトを使用する必要があります。私の最初のアイデアは、各要素を配列に配置し、いくつかの setInterval を使用して配列内のアニメーション関数をループし、それらを順番に実行することでした。

animate1 = [{elem,fn},{elem,fn}];
animate2 = [{elem,fn},{elem,fn}];これにより、同じ要素のアニメーションが連続して実行されますが、異なる要素のアニメーションを同時に実行することもできます。しかし、これには問題があります。つまり、アニメーションの要素が 10 を超える場合です。プログラムは 10 個の setInterval を開く必要があります。

このような状況を回避するために、上記を踏まえていくつかの改善を行いました。アニメーションがいくつあっても大丈夫です。すべては setInterval を使用して行われます。変更後の構造は以下の通りです。



[
[elem ,[fn ,fn,fn,fn]],
[elem,[fn,fn,fn,fn]],
[elem,[fn,fn,fn,fn]]
]


このようにして、setInterval を使用してすべてのアニメーションを完了できます。 行う必要があるのは、elem をループアウトし、fn の実行後に要素の最初の fn を実行することだけです。次の fn を呼び出します。すべての fn が空の場合は、大きな配列から elem を削除します。elem が空の場合は、setInterval をクリアします。そうすれば、論理は理にかなっています。

しかし、アニメーションにはもう一つ最も重要な要素があり、それは緩和です。 イージングを行わないと、アニメーションは非常に硬く見えます。同一性。現在、js アニメーションで使用されるイージング アルゴリズムは多数あり、大きく 2 つのカテゴリに分類できます。
1 つはフラッシュ クラスで、もう 1 つはプロトタイプ クラスです。

フラッシュには 4 つのパラメータが必要です。それらは、
1. 時間 t
2. アニメーションの初期値 b
3. アニメーションの終了値 c
4. 🎜>以下は Flash タイプの均一運動アルゴリズムです。
Linear: function(t,b,c,d){ return c*t/d b; }
もう 1 つはプロトタイプのみが必要です。 one, then 現在時刻 t と継続時間 d の比 (t/d)
パラメーターが便利なので 2 番目の方法を使用しました。これは、上記のアニメーションの式にもより適しています。以下は、プロトタイプの均一運動アルゴリズム
linear: function(t){ return t;} です。
イージングを追加すると、上の式は
アニメーション要素になります。開始値 (アニメーション要素の終了値 - アニメーション要素の開始値) * イージング関数 ((現在時刻 - 開始時刻) / (アニメーション所要時間)) 値の形式。
これでアニメーション全体のデザインは終了です。他の方のブログも参考にさせていただきましたので、感謝申し上げます
最後に詳細なコードを載せておきます。



コードをコピー コードは次のとおりです:

/**
* 作成時刻 2012/08/29
* @author lynx cat.
* @バージョン 0.77ベータ。
*/

(function(win,doc){
var win = win || window;
var doc = doc || win. document,
pow = Math.pow,
sin = Math.sin,
PI = Math.PI,
BACK_CONST = 1.70158;
var Easing = {
// 匀速运動
linear : function(t){
return t;
},
easeIn : function (t) {
return t * t;
},
easeOut : function (t) {
return ( 2 - t) * t;
},
ease Both : function (t) {
return (t *= 2)
.5 * t * t :
.5 * (1 - (--t) * (t - 2));
},
easeInStrong : function (t) {
return t * t * t * t;
},
easeOutStrong : function (t) {
return 1 - (--t) * t * t * t;
ease BothStrong: function (t ) {
return (t *= 2)
.5 * t * t * t :
.5 * (2 - (t -= 2) * t * t * t);
},
easeOutQuart : function(t){
return -(pow((t-1), 4) -1)
},
easeInOutExpo : function(t ){
if(t===0) 戻り値 0;
if(t===1) 戻り値 1;
if((t/=0.5) return 0.5 * (-pow(2, -10 * --t) 2);
easeOutExpo : function(t){
return (t===1) ? 1 : -pow(2, -10 * t) 1;
},
swingFrom : function(t) {
return t*t*((BACK_CONST 1)*t - BACK_CONST);
},
swingTo: function(t) {
return (t-=1)*t*((BACK_CONST 1)*t BACK_CONST) 1;
},
正弦波 : function(t) {
return (-Math.cos(t*PI)/2) 0.5;
},
フリッカー : function(t) {
var t = t (Math.random()-0.5)/5;
return this.sinusoidal(t 1 ? 1 : t);
},
backIn : function (t) {
if (t === 1) t -= .001;
return t * t * ((BACK_CONST 1) * t - BACK_CONST);
},
backOut : function (t) {
return (t -= 1) * t * ((BACK_CONST 1) * t BACK_CONST) 1;
},
bounce : function (t) {
var s = 7.5625, r;
if (t r = s * t * t;
}
else if (t r = s * (t -= (1.5 / 2.75)) * t .75;
}
else if (t r = s * (t -= (2.25 / 2.75)) * t .9375;
}
else {
r = s * (t -= (2.625 / 2.75)) * t .984375;
}
r を返します。
}
};
/**
* 会話メソッドを含むオブジェクトを返すために使用されるコーナーストーン
* @param elem
* @return {Object}
*/
function catfx(elem){
elem = typeof elem === 'string' ? doc.getElementById(elem) : 要素;
新しい fx(elem) を返します;
}
/**
* 会話メソッドを含むオブジェクトを返すために使用される内部コーナーストーン
* @param elem
* @return {Object}
*/
function fx(elem){
this.elem = elem;
これを返します;
}
/**
* 基本クラスには、いくつかの基本的なメソッドと不変式が含まれています
*/
var fxBase = {
速度 : {
遅い : 600、
速い : 200、
デフォルト : 400
},
fxAttrs : [],
fxMap:[],
/**
* オブジェクト要素の CSS 値を返します
* @param elem
* @param p
* @return css value
*/
getStyle : function(){
var fn = function (){} ;
if('getComputedStyle' in win){
fn = function(elem, p){
var p = p.replace(/-(w)/g,function(i,str){
return str.toUpperCase()
});
var val = getComputedStyle(elem, null)[p];
if(~(' ' p ' ').indexOf(' 左、右、上、下 ') && val === 'auto'){
val = '0px';
}
値を返します。
}
}else {
fn = function(elem, p){
var p = p.replace(/-(w)/g,function(i,str){
str.toUpperCase() を返します
});
var val = elem.currentStyle[p];
if(~(' ' p ' ').indexOf(' width height') && val === 'auto'){
var rect = elem.getBoundingClientRect();
val = ( p === 'width' ? rect.right - rect.left : rect.bottom - rect.top ) 'px';
}
if(p === 'opacity'){
var filter = elem.currentStyle.filter;
if( /opacity/.test(filter) ){
val = filter.match( /d / )[0] / 100;
val = (val === 1 || val === 0) ? val.toFixed(0) : val.toFixed(1);
}else if( val === 未定義 ){
val = 1;
}
}
if(~(' ' p ' ').indexOf(' 左、右、上、下 ') && val === 'auto'){
val = '0px';
}
値を返します。
}
}
return fn;
}(),
/**
* オブジェクト要素の CSS 値を返します
* @param カラー値 (赤、ピンク、青、その他の英語はまだサポートされていません)
* @return rgb(x,x,x)
*/
getColor : function(val){
var r, g, b;
if(/rgb/.test(val)){
var arr = val.match(/d /g);
r = arr[0];
g = arr[1];
b = arr[2];
}else if(/#/.test(val)){
var len = val.length;
if( len === 7 ){
r = parseInt( val.slice(1, 3), 16);
g = parseInt( val.slice(3, 5), 16);
b = parseInt( val.slice(5), 16);
}
else if( len === 4 ){
r = parseInt(val.charAt(1) val.charAt(1), 16);
g = parseInt(val.charAt(2) val.charAt(2), 16);
b = parseInt(val.charAt(3) val.charAt(3), 16);
}
}else{
戻り値;
}
return {
r : parseFloat(r),
g : parseFloat(g),
b : parseFloat(b)
}
},
/**
* 구문 분석된 CSS를 반환합니다.
* @param prop
* @return {val:val,unit:unit}
*/
parseStyle : function(prop){
var val = parseFloat(prop),
unit = prop.replace(/^[-d.] / , '');
if(isNaN(val)){
val = this.getColor(unit);
단위 = '';
}
return {val : 값, 단위 : 단위};
},
/**
* 요소의 투명도 설정
* @param elem
* @param val
*/
setOpacity : function(elem, val){
if( 'getCompulatedStyle' in win ){
elem.style.opacity = val === 1 ? '' : 발;
}else{
elem.style.zoom = 1;
elem.style.filter = val === 1 ? '' : 'alpha(opacity=' val * 100 ')';
}
},
/**
* 요소의 CSS 값 설정
* @param elem
* @param prop
* @param val
*/
setStyle : function(elem, prop, val){
if(prop != 'opacity'){
prop = prop.replace(/-(w)/g,function(i,p){
return p.toUpperCase();
});
elem.style[prop] = 발;
}else{
this.setOpacity(elem, val);
}
},
/**
* 구문 분석된 prop 반환
* @param prop
* @return {prop}
*/
parseProp : function(prop){
var props = {};
for(var i in prop){
props[i] = this.parseStyle(prop[i].toString());
}
반환 소품;
},
/**
* 올바른 사용자 매개변수
* @param elem
* @param 기간
* @param easing
* @param 콜백
* @return {options}
*/
setOption : function(elem,duration, easing, callback){
var options = {};
var _this = this;
options.duration = function(duration){
if(typeof Duration == 'number'){
반환 기간;
}else if(기간 유형 == '문자열' && _this.speed[기간]){
return _this.speed[기간];
}else{
return _this.speed.defaults;
}
}(기간);
options.easing = function(easing){
if(typeof easing == 'function'){
return easing;
}else if(typeof easing == 'string' && Easing[easing]){
return Easing[easing];
}else{
return Easing.linear;
}
}(완화);
options.callback = 함수(콜백){
var _this = this;
반환 함수(){
if(typeof callback == 'function'){
callback.call(elem);
}
}
}(콜백)
반환 옵션;
},
/**
* setInterval 기능 유지 및 애니메이션 시작
*/
tick : function(){
var _this = this;
if(!_this.timer){
_this.timer = setInterval(function(){
for(var i = 0, len = _this.fxMap.length; i < len; i ){
var elem = _this.fxMap[i][0];
var core = _this.data(elem)[0]
core(elem)
},16 );
}
},
/**
* 모든 애니메이션 중지
*/
stop : function(){
if(this.timer){
clearInterval(this.timer);
this.timer = 정의되지 않음;
}
},
/**
* 대기열 저장 또는 꺼내기
* @param elem
*/
data : function(elem){
for(var i = 0, len = this.fxMap.length; i < ; len; i ){
var data = this.fxMap[i];
if(elem === 데이터[0]){
return 데이터[1];
}
}
this.fxMap.push([elem,[]]);
return this.fxMap[this.fxMap.length - 1][1];
},
/**
* 대기열 삭제
* @param elem
*/
removeData : function(elem){
for(var i = 0, len = this.fxMap.length; i < len; i ){
var data = this.fxMap[i];
if(elem === data[0]){
this.fxMap.splice(i, 1);
if(this.isDataEmpty()){
this.stop();
}
}
}
},
isDataEmpty : function(){
return this.fxMap.length == 0;
}
}, $ = fxBase;
/**
* 애니메이션 개체를 생성하는 데 사용되는 핵심 개체입니다.
* @param elem
* @param props
* @param 옵션
* @return {Object}
*/
function fxCore(elem, props, options){
this.elem = elem;
this.props = 소품;
this.options = 옵션;
this.start();
}
fxCore.prototype = {
constructor : fxCore,
/**
* 대기열에 애니메이션 기능을 추가하고 애니메이션을 시작하세요.
*/
start : function(){
var cores = $.data(this .elem);
cores.push(this.step());
$.tick();
},
/**
* 核心 方法 , 控結每一帧元素的状态。
* @return function
*/
step : function(){
var _this = this;
var fn = function(elem){
var t = Date.now() - this.startTime;
if(Date.now() < this.startTime this.options.duration){
if(t for(this.target の変数 i ){
if(typeof this.source[i]['val'] === 'number'){
var val = parseFloat((this.source[i]['val'] (this.source[i]['val']) target[i]['val'] - this.source[i]['val']) * this.options.easing(t / this.options.duration)).toFixed(7));
}else{
var r = parseInt(this.source[i]['val']['r'] (this.target[i]['val']['r'] - this.ソース[i]['val']['r']) * this.options.easing(t / this.options.duration));
var g = parseInt(this.source[i]['val']['g'] (this.target[i]['val']['g'] - this.source[i][' val']['g']) * this.options.easing(t / this.options.duration));
var b = parseInt(this.source[i]['val']['b'] (this.target[i]['val']['b'] - this.source[i][' val']['b']) * this.options.easing(t / this.options.duration));
var val = 'rgb(' r ',' g ',' b ')';
}
$.setStyle(this.elem,i,val this.source[i]['unit']);
}
}else{
for(this.target の変数 i){
if(typeof this.target[i]['val'] === 'number'){
var val = this.target[i]['val'];
}else{
var val = 'rgb(' this.target[i]['val']['r'] ',' this.target[i]['val']['g' ] ',' this.target[i]['val']['b'] ')';
}
$.setStyle(elem,i,val this.source[i]['unit']);
}
var cores = $.data(elem);
cores.shift();
this.options.callback();
if(cores.length == 0){
$.setStyle(elem,'overflow',this.overflow);
$.removeData(elem);
}
}
}
return function(elem){
if(!_this.startTime){
var source = {};
_this.target = _this.props;
for(var i in _this.props){
var val = $.getStyle(_this.elem, i);
ソース[i] = $.parseStyle(val);
}
_this.source = ソース;
_this.startTime = Date.now();
_this.overflow = $.getStyle(elem,'overflow');
$.setStyle(elem,'overflow','hidden');
}
fn.call(_this,elem);
}
}
}
/**
* 外部インターフェイス クラス。
*/
fx.prototype = {
constructor : fx,
/**
* アニメーション メソッド
* @param prop
* @param 継続時間
* @param イージング
* @param callback
* @return {Object}
*/
animate : function(prop, period, easing, callback){
if(arguments.length == 3 && typeof easing === 'function'){ //複数回候用户第三个パラメータは回调
コールバック = イージング;
イージング = 未定義;
}
var props = $.parseProp(prop);
var options = $.setOption(this.elem,duration,easing,callback);
var core = new fxCore(this.elem,props,options);
これを返します;
},
/**
* アニメーションを停止するメソッド
* メソッド catjs('your element id').stop() を使用します
*/
stop : function(){
$.removeData(this.elem);
}
}
win.catfx = catfx;
})(this,document);

使用起来也比较简单.directcatfx('ID').animate({'margin-left':200,'background-color':'#ff0000'},600,'easeOut '、関数(){});

jquery の使用方法には大きな違いがあり、2 番目のパラメータが伝達されない場合は 400 秒とみなされます。3 番目のパラメータは関数であり、合計で 3 つのパラメータだけが共有されます。

例:catfx('ID').animate({'margin-left':200,'background-color':'#ff0000'},600,function (){alert('昭和家是回调関数~')});
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。