<!DOCTYPE html>
<html>
<!--
简述:做一个可控动画,能够根据用户输入判断是逐帧播放还是完全播放,同时也能够根据输入前进或者后退。
要点分析:
监听交互:单击,触摸,滚动等等
识别临界值:位移等。临界值内逐帧并且放弃交互时回退到交互前的状态;临界值外则动画完全播放。
动画:可在前进和后退之间切换(可通过传参);可逐帧播放(帧可以是小动画)
优化效率
相关交互:
下拉时:逐帧退和整节退
上拉时:逐帧前进和整节前进
放弃操作:超过临界值(动画完成)和未超过临界值(动画回退)。
动画关键点:帧和节都可进退,同时进退皆可控。
-->
<head>
<meta charset="UTF-8">
<title>可控动画</title>
</head>
<style>
ul,
li {
list-style: none;
padding: 0;
margin: 0;
}
ul {
font-size: 0;
}
.btn-wrap{
text-align: center;
margin-top: 20px;
}
.window {
width: 300px;
height: 200px;
overflow: hidden;
margin: 60px auto;
border: 1px solid red;
}
.canvas {
width: 1200px;
height: 200px;
}
.canvas img {
height: 200px;
width: 300px;
}
ul li {
display: inline-block;
width: 300px;
text-align: center;
background-color: greenyellow;
}
</style>
<body>
<div>
<div class="btn-wrap">
<button id="move">逐帧前进</button>
<button id="single-reverse">逐帧后退</button>
<button id="play">整节前进</button>
<button id="reverse">整节后退</button>
</div>
<div class="window">
<div class="canvas" id="main">
<ul>
<li class="item"><img draggable="false" src="img/img1.jpg"></li>
<li class="item"><img draggable="false" src="img/img2.jpg"></li>
<li class="item"><img draggable="false" src="img/img3.jpg"></li>
</ul>
</div>
</div>
</div>
</body>
<script>
//变量定义
var canvas = document.getElementsByClassName('canvas')[0],
main=document.getElementById("main"),//画布元素,也就是移动主体。
items=document.getElementsByClassName('item'),
item_len=items.length,
value = false,//是否在临界值之外,true为在临界值之外,false为临界值之内。
key=false,//鼠标是否按下
index=0,//当前是第几节动画
reverse = false,//节动画是否反方向播放
single_reverse=false,//帧动画是否反方向播放
frameTime = 13,//帧与帧之间播放间隔
stepDistance = (300 / (3000 / 30)), //每次移动的小距离,也就是每帧位移,单位为像素。
stepDistanceSum = 0; //移动的总距离
//交互
//顺序播放
document.getElementById('play').onclick = function() {
index++;//每单击一次播放一节
if(index>item_len){
index=0;//如果节动画完全播放完毕,从头开始播放
};
reverse = false;
value = true;
littleMove(index);
};
//倒叙播放
document.getElementById('reverse').onclick = function() {
index--;//每单击一次后退一节
if(index<0){
index=0;
};
value = true;
reverse = true;
littleMove(index);
};
//正向移动帧,没有实际意义,用于临界值之内的帧移动
document.getElementById('move').onclick = function() {
value = false;
reverse = false;
single_reverse=false;
littleMove(index);
};
//反向移动帧,没有实际意义,用于临界值之内的帧后退
document.getElementById('single-reverse').onclick = function() {
value = false;
reverse = false;
single_reverse=true;
littleMove(index);
};
main.onmousedown=function(e){
var e = e || event;
key=true;
};
main.onmouseup=function(){
key=false;
};
main.addEventListener('mousemove',function(e){
var e = e || event;
if(key){
//鼠标被按下
if(stepDistanceSum<50){
//并且小于临界值,一帧一帧播放动画
value = false;
reverse = false;
single_reverse=false;
littleMove(index);
}else{
//临界值之外,播放完整节动画
reverse = false;
value = true;
littleMove(index);
}
}
});
//动画函数
function littleMove(index) {
// console.log('进入littleMove函数');
if(!value) {
if(stepDistanceSum<=300*(item_len-1)){
//临界值之内,每次交互移动一次
if((stepDistanceSum-(300*index))<300) {//如果小于300则一直可以帧移动
if(single_reverse){
stepDistanceSum -= stepDistance;
canvas.style.marginLeft = -stepDistanceSum + 'px';
}else{
stepDistanceSum += stepDistance;
canvas.style.marginLeft = -stepDistanceSum + 'px';
}
} else {
}
}else{
clearInterval(interval);
}
} else {
//临界值外,小节动画一次性播放完毕
var interval = setInterval(function() {
if(stepDistanceSum<=300*(item_len-1)){//未超过边界
// console.log('边界之内');
if(stepDistanceSum%300==0){
clearInterval(interval);
};
if(reverse) {
if(stepDistanceSum<0){
clearInterval(interval);
}else{
canvas.style.marginLeft = +stepDistanceSum + 'px';
console.log(stepDistanceSum);
stepDistanceSum -= stepDistance;
console.log(stepDistanceSum);
}
} else {
canvas.style.marginLeft = -stepDistanceSum + 'px';
stepDistanceSum += stepDistance;
}
}else{//超过边界,从头开始
clearInterval(interval);
stepDistanceSum=0;
}
}, frameTime)
}
};
</script>
</html>