一个原生JavaScript动画库原型
设计目标:简单易用,不依赖其他库,对旧版浏览器具有一定兼容性,功能可扩展。
动画调用:
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>为若干个标签添加若干个动画,动画要有变化属性(默认为样式属性)、动画名、属性值类型、是否循环、多关键帧、ease函数(默认为线性)、有添加方法、删除方法</title>
6 <style>
7 .div_ani {background: red;width: 100px;height:100px;position:relative}
8 </style>
9 <script src="Ani.js"></script>
10 </head>
11 <body>
12 <div class="div_ani">111</div>
13 <div class="div_ani">222</div>
14 </body>
15 <!--script type="module"-->
16 <script>
17 //import Ani from './ani.js'
18 let objs1=document.querySelector(".div_ani");
19 let objs2=document.querySelectorAll(".div_ani");
20 Ani.addAni(objs2,[
21 {
22 arr_pname:"width",loop:true,endcallback:function(){console.log("动画结束")}//动画属性
23 ,arr_key:[//关键帧数组
24 {ms:0,value:100,callback:function(ani){console.log(ani.elem.innerHTML+"第0ms")}},
25 {ms:1000,value:300,callback:function(){console.log("第1000ms")}},
26 {ms:2000,value:100,callback:function(){console.log("第2000ms")}},
27 ]
28 }
29 ]//addAni的第一个参数可以是dom对象或dom对象数组,第二个参数是动画对象数组
30 )
31 //可以多次执行addAni添加更多动画
32 Ani.startAni();//启动所有动画
33
34
35
36
37
38 </script>
39 </html>
代码实现:
1 //考虑到更好的兼容性
2 // export default class Ani{
3 // constructor(elem,p){
4 // /*let p_default={
5 // type:"css_px",
6 // id:Ani.randomString(32),//没有必要生成两次
7 //
8 // }*/
9 // this.type=p.type||"css_px";
10 // this.id=p.id||Ani.randomString(32);
11 // this.arr_key=[];
12 // let len=p.arr_key.length;//每个基础类型属性都要用直接量赋值
13 // for(let i=0;i<len;i++)
14 // {
15 // let key=p.arr_key[i]
16 // this.arr_key.push(
17 // {
18 // ms:key.ms,
19 // value:JSON.parse(JSON.stringify(key.value)),
20 // callback:key.callback,//回调函数可以共用一个
21 // }
22 // )
23 // }
24 // //this.arr_key=p.arr_key;
25 // this.loop=p.loop;
26 // this.elem=elem;
27 // this.countms=0;
28 // this.arr_pname=p.arr_pname;
29 // this.func_ease=p.func_ease||Ani.obj_func_ease.float_line;
30 // //this.arr_framecallback=p.arr_framecallback||[];
31 // this.endcallback=p.endcallback;
32 // this.func_set=p.func_set||Ani.setValue;
33 // }
34 // }
35 function Ani(elem,p){
36 this.type=p.type||"css_px";
37 this.id=p.id||Ani.randomString(32);
38 this.arr_key=[];
39 var len=p.arr_key.length;//每个基础类型属性都要用直接量赋值
40 for(var i=0;i<len;i++)
41 {
42 var key=p.arr_key[i]
43 this.arr_key.push(
44 {
45 ms:key.ms,
46 value:JSON.parse(JSON.stringify(key.value)),
47 callback:key.callback,//回调函数可以共用一个
48 }
49 )
50 }
51 //this.arr_key=p.arr_key;
52 this.loop=p.loop;
53 this.elem=elem;
54 this.countms=0;
55 this.arr_pname=p.arr_pname;
56 this.func_ease=p.func_ease||Ani.obj_func_ease.float_line;
57 //this.arr_framecallback=p.arr_framecallback||[];
58 this.endcallback=p.endcallback;
59 this.func_set=p.func_set||Ani.setValue;
60 }
61 Ani.obj_anis={};
62 Ani.addAni=function(objs,p_anis)//添加动画
63 {
64 if(objs.outerHTML)//如果是一个html标签
65 {
66 objs=[objs];
67 }
68 var len1=objs.length;
69 var len2=p_anis.length;
70 for(var i=0;i<len1;i++)
71 {
72 var obj=objs[i];
73 /*if(!obj.arr_ani)//如果以前没有动画数组,dom元素没有易于使用的唯一id,所以不应把动画配置保存再dom元素对象里
74 //使用一个全局obj_anis保存所有动画对象
75 {
76 obj.arr_ani=[];
77 }*/
78 for(var j=0;j<len2;j++)
79 {
80 var p_ani=p_anis[j];
81 var ani=new Ani(obj,p_ani);
82 Ani.obj_anis[ani.id]=ani;
83 //let len3=obj.arr_ani;
84 /*let flag_canpush=true;
85 for(let k=0;k<len3;k++)
86 {
87 //if(obj.arr_ani[k]===ani)//如果已经添加过这个动画对象
88 if(obj.arr_ani[k].id==p_ani.id)
89 {
90 flag_canpush=false;
91 }
92 }
93 if(flag_canpush==true)
94 {
95 obj.arr_ani.push(p_ani);
96 }*/
97 }
98
99 }
100 }
101 Ani.runningAni=false;
102
103 //这里的一个问题是dom元素可能没有唯一id,后面很难再找到它的对象-》使用一个公用对象?
104 Ani.startAni=function()
105 {
106 if(Ani.runningAni==false)
107 {
108 Ani.lastframe=new Date().getTime();
109 //Ani.currentframe=Ani.lastframe;
110 window.requestAnimFrame(function(){
111 Ani.Frame();
112 })
113 }
114 Ani.runningAni=true;
115 }
116 Ani.pauseAni=function()
117 {
118 Ani.runningAni=false;
119 }
120
121 Ani.Frame=function()
122 {
123 Ani.currentframe=new Date().getTime();
124 Ani.framems=Ani.currentframe-Ani.lastframe;
125
126 //key_called=null;
127 for(var key in Ani.obj_anis)
128 {
129 var ani=Ani.obj_anis[key];
130 ani.countms+=Ani.framems;
131 var len=ani.arr_key.length;
132 var value=null;
133 for(var i=0;i<len-1;i++)
134 {
135 var key1=ani.arr_key[i];
136 var key2=ani.arr_key[i+1];
137 if(ani.countms>=key1.ms&&ani.countms<=key2.ms)
138 {
139 value=ani.func_ease(key1,key2,ani.countms);
140 //Ani.setValue(ani.elem,value,ani.type,ani.arr_pname);
141 ani.func_set(ani.elem,value,ani.type,ani.arr_pname);
142 if(key1.callback&&!key1.called)//如果这个关键帧上有回调函数,并且这个帧没有被调用过
143 {
144 key1.callback(ani);
145 key1.called=true;//多个动画时有多个key1,要分别标记
146 }
147 break;
148 }
149 }
150 var endKey=ani.arr_key[len-1];
151 if(ani.countms>endKey.ms)//如果完成了一次动画
152 {
153 //Ani.setValue(ani.elem,endKey.value,ani.type,ani.arr_pname);
154 ani.func_set(ani.elem,value,ani.type,ani.arr_pname);
155 if(endKey.callback)//如果结束帧上有回调函数
156 {
157 endKey.callback();
158 console.log(ani.countms);
159 }
160 if(ani.loop)
161 {
162 ani.countms=ani.countms%endKey.ms;
163 for(var i=0;i<len;i++)
164 {
165 var key1=ani.arr_key[i];
166 key1.called=false;
167 }
168
169 }
170 else{
171 if(ani.endcallback)//如果有动画结束回调
172 {
173 ani.endcallback(ani);
174 }
175
176 delete Ani.obj_anis[key];
177 ani=null;
178 }
179 }
180
181 }
182
183
184 Ani.lastframe=Ani.currentframe;
185 if(Ani.runningAni==true)
186 {
187 window.requestAnimFrame(function(){
188 Ani.Frame();
189 })
190 }
191 }
192
193
194 Ani.setValue=function(elem,value,type,arr_pname)//在这里扩展更多的属性设置方法
195 {
196 if(type=="css_px")//这时arr_pname只有一层,是一个字符串,处理颜色时则可能是3维数组
197 {
198 elem.style[arr_pname]=value+"px";
199 }
200 else if(type=="transform-rotate-deg")//
201 {
202 elem.style["transform"]="rotate("+value+"deg)";
203 }
204 }
205 Ani.obj_func_ease={//在这里扩展更多的插值方法
206 //单浮点数线性
207 float_line:function(key1,key2,countms){
208 var ms1=key1.ms;
209 var ms2=key2.ms;
210 var v1=key1.value;
211 var v2=key2.value
212 return Ani.inBetween(ms1,ms2,v1,v2,countms);
213 }
214 };
215 //插值
216 Ani.inBetween=function(ms1,ms2,v1,v2,ms)
217 {
218 var v=v1+((ms-ms1)/(ms2-ms1))*(v2-v1);
219 return v;
220 }
221 Ani.randomString=function(len)
222 {
223 len = len || 32;
224 var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
225 var maxPos = $chars.length;
226 var pwd = '';
227 for (var i = 0; i < len; i++) {
228 pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
229 }
230 return pwd;
231 }
232
233 // Copyright 2010, Google Inc.
234 window.requestAnimFrame = (function() {
235 return window.requestAnimationFrame ||
236 window.webkitRequestAnimationFrame ||
237 window.mozRequestAnimationFrame ||
238 window.oRequestAnimationFrame ||
239 window.msRequestAnimationFrame ||
240 function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
241 window.setTimeout(callback, 1000/60);
242 };
243 })();
编写过程中参考了Babylon.js动画模块、Google requestAnimFrame方法、网上的randomString方法。可基于MIT协议发布的部分基于MIT协议发布,项目Github地址:https://github.com/ljzc002/SimpleAni。
赞 (0)
