javascript 프레임 애니메이션(실례 설명)

앞 말
프레임 애니메이션 은'연속 적 인 관건 프레임'에서 애니메이션 동작 을 분해 하 는 것 이다.즉,시간 축의 각 프레임 에 서로 다른 내용 을 그 려 서 연속 적 으로 재생 하도록 하 는 애니메이션 이다.한 폭 한 폭 의 그림 이기 때문에 프레임 애니메이션 은 매우 큰 유연성 을 가지 고 표현 하고 자 하 는 모든 내용 을 표현 할 수 있다.본 고 는 자 바스 크 립 트 프레임 애니메이션 을 상세 하 게 소개 할 것 이다
개술
[분류]
흔히 볼 수 있 는 프레임 애니메이션 의 방식 은 세 가지 가 있 는데 gif,CSS 3 animation 과 javascript 을 포함한다.
git 와 CSS 3 animation 은 애니메이션 의 일시 정지 와 재생 을 유연 하 게 제어 할 수 없고 프레임 애니메이션 을 더욱 유연 하 게 확장 할 수 없습니다.또한 gif 그림 은 애니메이션 이 완 성 된 사건 을 포착 할 수 없습니다.그래서 일반적으로 자바 script 을 사용 하여 프레임 애니메이션 을 실현 합 니 다.
[원리]
js 프레임 애니메이션 실현 은 두 가지 실현 방식 이 있다.
1.여러 프레임 의 애니메이션 그림 이 있 으 면 하나의 image 태그 로 그림 을 불 러 올 수 있 고 정시 에 image 의 src 속성 을 변경 할 수 있 습 니 다(추천 하지 않 음)
2.모든 애니메이션 키 프레임 을 한 장의 그림 에 그립 니 다.그림 을 요소 로 하 는 background-image 는 요소 의 background-position 속성 을 정기 적 으로 바 꿉 니 다(추천)
첫 번 째 방법 은 여러 개의 HTTP 요청 을 사용 해 야 하기 때문에 일반적으로 두 번 째 방법 을 추천 합 니 다.
【실례】
다음은 프레임 애니메이션 으로 제 작 된 인 스 턴 스 입 니 다.

<div id="rabbit" ></div> 
<button id="btn">    </button> 
<script>
var url = 'rabbit-big.png';
var positions = ['0,-854','-174 -852','-349 -852','-524 -852','-698 -852','-873 -848'];
var ele = document.getElementById('rabbit');
var oTimer = null;
btn.onclick = function(){
 if(btn.innerHTML == '    '){
  frameAnimation(ele,positions,url);
  btn.innerHTML = '    ';
 }else{
  clearTimeout(oTimer);
  btn.innerHTML = '    ';
 } 
}
frameAnimation(ele,positions,url);
function frameAnimation(ele,positions,url){
 ele.style.backgroundImage = 'url(' + url + ')';
 ele.style.backgroundRepeat = 'no-repeat'; 
 var index = 0;
 function run(){
  var pos = positions[index].split(' ');
  ele.style.backgroundPosition = pos[0] + 'px ' + pos[1] + 'px';
  index++;
  if(index >= positions.length){
   index = 0;
  }
  oTimer = setTimeout(run,80);
 }
 run();
} 
</script>
유 니 버 설 프레임 애니메이션
다음은 통용 되 는 프레임 라 이브 러 리 를 설계 하 겠 습 니 다.
[수요 분석]
1.그림 미리 불 러 오기 지원
2.두 가지 애니메이션 재생 방식 을 지원 하고 각 프레임 의 애니메이션 을 사용자 정의 합 니 다.
3.단일 애니메이션 제어 순환 횟수 지원(무한 회 지원)
4.애니메이션 완성 을 지원 하고 다음 애니메이션 을 진행 합 니 다.
5.모든 애니메이션 완료 후 대기 시간 지원
6.애니메이션 일시 정지 및 재생 지원
7.애니메이션 완성 후 리 셋 함수 실행 지원
[프로 그래 밍 인터페이스]
1.loadImage(imglist)//미리 불 러 온 그림
2.changePosition(ele,positions,imageUrl)//요 소 를 바 꾸 는 background-position 을 통 해 애니메이션 을 실현 합 니 다.
3.changesrc(ele,imglist)//image 요 소 를 바 꾸 는 src
4.enterFrame(callback)//각 프레임 의 애니메이션 이 실행 하 는 함수 로 사용자 가 각 프레임 의 애니메이션 을 사용자 정의 할 수 있 는 callback 에 해당 합 니 다.
5.repeat(times)/애니메이션 중복 실행 횟수,times 가 비어 있 을 때 무한 회 표시
6.repeat Forever()//지난번 애니메이션 을 무한 반복 하면 repeat()에 해당 합 니 다.
7.wait(time)//애니메이션 실행 완료 후 기다 리 는 시간
8.then(callback)/애니메이션 실행 완료 후 리 셋 함수
9.start(interval)/애니메이션 이 실 행 됩 니 다.interval 은 애니메이션 이 실 행 된 간격 을 표시 합 니 다.
10.일시 정지()/애니메이션 일시 정지
11.restart()/애니메이션 은 이전 일시 정지 에서 다시 실 행 됩 니 다.
12.dispose()//자원 방출
[호출 방식]
체인 호출 지원,동사 로 인터페이스 설명
[코드 디자인]
1.그림 미리 불 러 오기->애니메이션 실행->애니메이션 종료 등 일련의 작업 을 작업 체인 으로 봅 니 다.작업 체인 은 동기 화 실행 과 비동기 정시 에 두 가지 작업 을 수행 하 는 것 을 포함한다.
2.현재 퀘 스 트 체인 의 색인 기록
3.모든 작업 수행 완료 후 next 방법 을 호출 하여 다음 작업 을 수행 하고 작업 체인 색인 값 을 업데이트 합 니 다.

[인터페이스 정의]

'use strict';
/*      
 * @constructor
 */
function FrameAnimation(){}

/*         ,      
 * @param imglist     
 */
FrameAnimation.prototype.loadImage = function(imglist){}

/*           ,            ,     
 * @param ele dom  
 * @param positions       
 * @param imageUrl   URL  
 */
FrameAnimation.prototype.changePosition = function(ele,positions,imageUrl){}

/*           ,      image   src  ,     
 * @param ele dom  
 * @param imglist     
 */
FrameAnimation.prototype.changeSrc = function(ele,imglist){}

/*           ,              
 * @param tastFn             
 */
FrameAnimation.prototype.enterFrame = function(taskFn){}

/*         ,               
 * @param callback     
 */
FrameAnimation.prototype.then = function(callback){}

/*       ,           
 * @param interval
 */
FrameAnimation.prototype.start = function(interval){}

/*         ,        ,            ,         
 * @param times     
 */
FrameAnimation.prototype.repeat = function(times){}

/*         ,   repeat(),         
 * 
 */
FrameAnimation.prototype.repeatForever = function(){}

/*                          
 * @param time     
 */
FrameAnimation.prototype.wait = function(time){}

/*           
 * 
 */
FrameAnimation.prototype.pause = function(){}

/*                 
 * 
 */
FrameAnimation.prototype.restart = function(){}

/*     
 * 
 */
FrameAnimation.prototype.dispose = function(){}
그림 미리 불 러 오기
그림 미리 불 러 오 는 것 은 상대 적 으로 독립 된 기능 으로 모듈 imageloader.js 로 밀봉 할 수 있 습 니 다.

'use strict';
/**
 *        
 * @param  images             
 * @param  callback                 
 * @param  timeout        
 */
function loadImage(images,callback,timeout){
 //          
 var count = 0;
 //            
 var success = true;
 //  timer id
 var timeoutId = 0;
 //          
 var isTimeout = false;
 //     (   )    
 for(var key in images){
  //  prototype    
  if(!images.hasOwnProperty(key)){
   continue;
  }
  //        
  //     object:{src:xxx}
  var item = images[key];
  if(typeof item === 'string'){
   item = images[key] = {
    src:item
   };
  }
  //         ,       ,       
  if(!item || !item.src){
   continue;
  }
  //  +1
  count++;
  //       id
  item.id = '__img__' + key + getId();
  //       img,    Image  
  item.img = window[item.id] = new Image();
  doLoad(item);
 }
 //         0,     callback
 if(!count){
  callback(success);
 }else if(timeout){
  timeoutId = setTimeout(onTimeout,timeout);
 }

 /**
  *            
  * @param  item       
  */
 function doLoad(item){
  item.status = 'loading';
  var img = item.img;
  //             
  img.onload = function(){
   success = success && true;
   item.status = 'loaded';
   done();
  }
  //             
  img.onerror = function(){
   success = false;
   item.status = 'error';
   done();
  }
  //    http(s)  
  img.src = item.src;
  /**
   *              
   */
  function done(){
   img.onload = img.onerror = null;
   try{
    delete window[item.id];
   }catch(e){

   }
   //        ,    1,         ,        ,       ,       
   if(!--count && !isTimeout){
    clearTimeout(timeoutId);
    callback(success);
   }
  }
 }
 /**
  *     
  */
 function onTimeout(){
  isTimeout = true;
  callback(false);
 }
}
var __id = 0;
function getId(){
 return ++__id;
}
module.exports = loadImage;
시간 축
애니메이션 처리 에서 setTimeout()을 교체 해서 사용 한 것 이지 만 이 간격 은 정확 하지 않 습 니 다.다음은 시간 축 류 timeline.js 를 실현 합 니 다.

'use strict';

var DEFAULT_INTERVAL = 1000/60;

//     
var STATE_INITIAL = 0;
//    
var STATE_START = 1;
//    
var STATE_STOP = 2;

var requestAnimationFrame = (function(){
 return window.requestAnimationFrame || window.webkitRequestAnimationFrame|| window.mozRequestAnimationFrame || window.oRequestAnimationFrame || function(callback){
     return window.setTimeout(callback,(callback.interval || DEFAULT_INTERVAL));
    }
})();

var cancelAnimationFrame = (function(){
 return window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame  || function(id){
     return window.clearTimeout(id);
    } 
})();
/**
 *     
 * @constructor
 */
function Timeline(){
 this.animationHandler = 0;
 this.state = STATE_INITIAL;
}
/**
 *               
 * @param  time              
 */
Timeline.prototype.onenterframe = function(time){

}
/**
 *     
 * @param interval           
 */
Timeline.prototype.start = function(interval){
 if(this.state === STATE_START){
  return;
 }
 this.state = STATE_START;
 this.interval = interval || DEFAULT_INTERVAL;
 startTimeline(this,+new Date());
}

/**
 *     
 */
Timeline.prototype.stop = function(){
 if(this.state !== STATE_START){
  return;
 }
 this.state = STATE_STOP;
 //       ,                 
 if(this.startTime){
  this.dur = +new Date() - this.startTime;
 }
 cancelAnimationFrame(this.animationHandler);
}

/**
 *       
 */
Timeline.prototype.restart = function(){
 if(this.state === STATE_START){
  return;
 }
 if(!this.dur || !this.interval){
  return;
 }
 this.state = STATE_START;
 //      
 startTimeline(this,+new Date()-this.dur);
}

/**
 *          
 * @param  timeline       
 * @param  startTime             
 */
function startTimeline(timeline,startTime){
 //           
 var lastTick = +new Date();
 timeline.startTime = startTime;
 nextTick.interval = timeline.interval;
 nextTick();
 /**
  *         
  */
 function nextTick(){
  var now = +new Date();
  timeline.animationHandler = requestAnimationFrame(nextTick);
  //                         ,             
  if(now - lastTick >= timeline.interval){
   timeline.onenterframe(now - startTime);
   lastTick = now;
  }
 }
}
module.exports = Timeline;
애니메이션 클래스 구현
다음은 애니메이션 류 animation.js 가 구현 한 전체 코드 입 니 다.

'use strict';

var loadImage = require('./imageloader');
var Timeline = require('./timeline');
//     
var STATE_INITIAL = 0;
//    
var STATE_START = 1;
//    
var STATE_STOP = 2;
//    
var TASK_SYNC = 0;
//    
var TASK_ASYNC = 1;

/**
 *        ,  callback
 * @param  callback     
 */
function next(callback){
 callback && callback();
}
/*      
 * @constructor
 */
function FrameAnimation(){
 this.taskQueue = [];
 this.index = 0;
 this.timeline = new Timeline();
 this.state = STATE_INITIAL;
}

/*         ,      
 * @param imglist     
 */
FrameAnimation.prototype.loadImage = function(imglist){
 var taskFn = function(next){
  loadImage(imglist.slice(),next);
 };
 var type = TASK_SYNC;
 return this._add(taskFn,type);
}

/*           ,            ,     
 * @param ele dom  
 * @param positions       
 * @param imageUrl   URL  
 */
FrameAnimation.prototype.changePosition = function(ele,positions,imageUrl){
 var len = positions.length;
 var taskFn;
 var type;
 if(len){
  var me = this;
  taskFn = function(next,time){
   if(imageUrl){
    ele.style.backgroundImage = 'url(' + imageUrl + ')';
   }
   //            
   var index = Math.min(time/me.interval|0,len);
   var position = positions[index-1].split(' ');
   //  dom         
   ele.style.backgroundPosition = position[0] + 'px ' + position[1] + 'px';
   if(index === len){
    next();
   }
  }
  type = TASK_ASYNC;
 }else{
  taskFn = next;
  type = TASK_SYNC;
 }
 return this._add(taskFn,type);
}

/*           ,      image   src  ,     
 * @param ele dom  
 * @param imglist     
 */
FrameAnimation.prototype.changeSrc = function(ele,imglist){
 var len = imglist.length;
 var taskFn;
 var type;
 if(len){
  var me = this;
  taskFn = function(next,time){
   //            
   var index = Math.min(time/me.interval|0,len);
   //  image         
   ele.src = imglist[index-1];
   if(index === len){
    next();
   }
  }
  type = TASK_ASYNC;
 }else{
  taskFn = next;
  type = TASK_SYNC;
 }
 return this._add(taskFn,type); 
}

/*           ,              
 * @param tastFn             
 */
FrameAnimation.prototype.enterFrame = function(taskFn){
 return this._add(taskFn,TASK_ASYNC);
}

/*         ,               
 * @param callback     
 */
FrameAnimation.prototype.then = function(callback){
 var taskFn = function(next){
  callback(this);
  next();
 };
 var type = TASK_SYNC;
 return this._add(taskFn,type);
}

/*       ,           
 * @param interval
 */
FrameAnimation.prototype.start = function(interval){
 if(this.state === STATE_START){
  return this; 
 }
 //          ,   
 if(!this.taskQueue.length){
  return this;
 }
 this.state = STATE_START;
 this.interval = interval;
 this._runTask();
 return this;
  
}

/*         ,        ,            ,         
 * @param times     
 */
FrameAnimation.prototype.repeat = function(times){
 var me = this;
 var taskFn = function(){
  if(typeof times === 'undefined'){
   //          
   me.index--;
   me._runTask();
   return;
  }
  if(times){
   times--;
   //  
   me.index--;
   me._runTask();
  }else{
   //      ,        
   var task = me.taskQueue[me.index];
   me._next(task);
  }
 }
 var type = TASK_SYNC;
 return this._add(taskFn,type);
}

/*         ,   repeat(),         
 * 
 */
FrameAnimation.prototype.repeatForever = function(){
 return this.repeat();
}

/*                          
 * @param time     
 */
FrameAnimation.prototype.wait = function(time){
 if(this.taskQueue && this.taskQueue.length > 0){
  this.taskQueue[this.taskQueue.length - 1].wait = time;
 }
 return this;
}

/*           
 * 
 */
FrameAnimation.prototype.pause = function(){
 if(this.state === STATE_START){
  this.state = STATE_STOP;
  this.timeline.stop();
  return this;
 }
 return this;
}

/*                 
 * 
 */
FrameAnimation.prototype.restart = function(){
 if(this.state === STATE_STOP){
  this.state = STATE_START;
  this.timeline.restart();
  return this;
 }
 return this; 
}

/*     
 * 
 */
FrameAnimation.prototype.dispose = function(){
 if(this.state !== STATE_INITIAL){
  this.state = STATE_INITIAL;
  this.taskQueue = null;
  this.timeline.stop();
  this.timeline = null;
  return this;
 }
 return this;  
}

/**
 *            
 * @param taskFn     
 * @param type      
 * @private
 */
FrameAnimation.prototype._add = function(taskFn,type){
 this.taskQueue.push({
  taskFn:taskFn,
  type:type
 });
 return this;
}

/**
 *     
 * @private
 */
FrameAnimation.prototype._runTask = function(){
 if(!this.taskQueue || this.state !== STATE_START){
  return;
 }
 //      
 if(this.index === this.taskQueue.length){
  this.dispose();
  return;
 }
 //           
 var task = this.taskQueue[this.index];
 if(task.type === TASK_SYNC){
  this._syncTask(task);
 }else{
  this._asyncTask(task);
 }
}

/**
 *     
 * @param task        
 * @private
 */
FrameAnimation.prototype._syncTask = function(task){
 var me = this;
 var next = function(){
  //        
  me._next(task);
 }
 var taskFn = task.taskFn;
 taskFn(next);
}

/**
 *     
 * @param task        
 * @private
 */
FrameAnimation.prototype._asyncTask = function(task){
 var me = this;
 //            
 var enterframe = function(time){
  var taskFn = task.taskFn;
  var next = function(){
   //      
   me.timeline.stop();
   //       
   me._next(task);
  };
  taskFn(next,time);
 }
 this.timeline.onenterframe = enterframe;
 this.timeline.start(this.interval);
}

/**
 *         ,            ,     
 * @private
 */
FrameAnimation.prototype._next = function(task){
 this.index++;
 var me = this;
 task.wait ? setTimeout(function(){
  me._runTask();
 },task.wait) : this._runTask();
}

module.exports = function(){
  return new FrameAnimation();
}
웹 팩 설정
animation 프레임 워 크 갤러리 제작 에 AMD 모듈 규범 이 적용 되 었 으 나 브 라 우 저 차원 에서 지원 되 지 않 기 때문에 웹 팩 을 사용 하여 모듈 화 관 리 를 해 야 합 니 다.animation.js,imageloader.js 와 timeline.js 를 파일 로 포장 합 니 다.

module.exports = {
 entry:{
  animation:"./src/animation.js"
 },
 output:{
  path:__dirname + "/build",
  filename:"[name].js",
  library:"animation",
  libraryTarget:"umd",
 }
}
다음은 코드 인 스 턴 스 입 니 다.만 든 프레임 워 크 갤러리 를 통 해 블 로그 에서 시 작 된 애니메이션 효 과 를 실현 합 니 다.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
<div id="rabbit" ></div> 
<script src="../build/animation.js"></script> 
<script>var imgUrl = 'rabbit-big.png';
var positions = ['0,-854','-174 -852','-349 -852','-524 -852','-698 -852','-873 -848'];
var ele = document.getElementById('rabbit');
var animation = window.animation;
var repeatAnimation = animation().loadImage([imgUrl]).changePosition(ele,positions,imgUrl).repeatForever();
repeatAnimation.start(80); 
</script>
</body>
</html>
더 많은 인 스 턴 스
토끼 수레 의 효 과 를 실현 할 수 있 을 뿐만 아니 라 프레임 애니메이션 으로 토끼 의 승리 와 토끼 의 실패 효 과 를 실현 할 수 있다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
div{position:absolute;width:102px;height:80px;background-repeat:no-repeat;} 
</style>
</head>
<body>
<div id="rabbit1" ></div>
<div id="rabbit2" ></div>
<div id="rabbit3" ></div> 
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/animation.js"></script>
<script>
var baseUrl = 'http://7xpdkf.com1.z0.glb.clouddn.com/runjs/img/';
var images = ['rabbit-big.png','rabbit-lose.png','rabbit-win.png'];
for(var i = 0; i < images.length; i++){
 images[i] = baseUrl + images[i];
}
var rightRunningMap = ["0 -854", "-174 -852", "-349 -852", "-524 -852", "-698 -851", "-873 -848"];
var leftRunningMap = ["0 -373", "-175 -376", "-350 -377", "-524 -377", "-699 -377", "-873 -379"];
var rabbitWinMap = ["0 0", "-198 0", "-401 0", "-609 0", "-816 0", "0 -96", "-208 -97", "-415 -97", "-623 -97", "-831 -97", "0 -203", "-207 -203", "-415 -203", "-623 -203", "-831 -203", "0 -307", "-206 -307", "-414 -307", "-623 -307"];
var rabbitLoseMap = ["0 0", "-163 0", "-327 0", "-491 0", "-655 0", "-819 0", "0 -135", "-166 -135", "-333 -135", "-500 -135", "-668 -135", "-835 -135", "0 -262"];

var animation = window.animation;
function repeat(){
 var repeatAnimation = animation().loadImage(images).changePosition(rabbit1, rightRunningMap, images[0]).repeatForever();
 repeatAnimation.start(80); 
}
function win() {
 var winAnimation = animation().loadImage(images).changePosition(rabbit2, rabbitWinMap, images[2]).repeatForever();
 winAnimation.start(200);
}
function lose() {
 var loseAnimation = animation().loadImage(images).changePosition(rabbit3, rabbitLoseMap, images[1]).repeatForever();
 loseAnimation.start(200);
}
repeat();
win();
lose();
</script>
</body>
</html>
이상 의 자 바스 크 립 트 프레임 애니메이션(실례 설명)은 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.여러분 에 게 참고 가 되 고 저희 도 많이 응원 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기