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>
이상 의 자 바스 크 립 트 프레임 애니메이션(실례 설명)은 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.여러분 에 게 참고 가 되 고 저희 도 많이 응원 해 주시 기 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Thymeleaf 의 일반 양식 제출 과 AJAX 제출텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.