JS实现动画原理一(闭包方式)
前提:
你必须了解js的闭包(否则你看不懂滴)
我们就来做一个js实现jq animate的动画效果来简单探索一下,js动画实现的简单原理;
html代码 <div id="man" style="background:gray; height:1px; width:100%;"> </div>
原理:就是让它的高度逐渐从 1px ----100px
jq 代码实现:$("#id").animate({height:"100px"})
JS (too yong too simple) 代码实现方式:
function addHeight(){ var obj=document.getElementById("man"); for(var i=1;i<10;i++){ var len=i*10; obj.style.height=len+"px"; } } //为什么too young too simple 我不解释;
JS(sometimes naive)代码实现方式:
function addHeight2(){ var obj=document.getElementById("man"); for(var i=1;i<10;i++){ setTimeout(function(){ var len=i*10; obj.style.height=len+"px"; },i*1000) } }
//为什么说 sometimes naive 呢? 因为你的 i 直接就等10 了 不信你 alert 一下,就是10;
//这里还需要插播一点关于setTimeout 的使用方法;
setTimeout 的使用方法
var g=100;
function Test(val){
alert(val);
}
setTimeout(Test,3000); //三秒手执行
setTimeout(Test(),3000); //马上执行
setTimeout(Test(g),3000); //马上执行
//那么,我们如何传递参数呢;
//方式一(如果是静态参数的话)
setTimeout(function (){
Test("静态参数");
},3000)
//方式二(如果是动态参数)
setTimeout(function (g){
Test(g);
}(g),3000)
//方式三(通用) 这里的参数只能是字符串;
setTimeout("Test("+g+")");
分析,问什么,i会变成10 呢?
答案如下:
function addHeight3(){ var obj=document.getElementById("man"); for(var i=1;i<10;i++){ setTimeout(function(){ alert(i) //什么变量i是10 呢 //你可以借助异步的概念来理解; //第一次循环 i=1 //seTimeout 中的 delay=1000 //在着1000内 循环,早已结束,结果i=10 //现在的问题就是 将 i 传递进去呢; },i*1000) } }
改进
function addHeight4(){ var obj=document.getElementById("man"); for(var i=1;i<10;i++){ setTimeout(function(para){ //这样写的话 是可以将参数传递进去,不过函数会立即执行;没有时间间隔! alert(para); //1 2 3 4 5 6 7 8 9 10 }(i),i*5000) //也就是说,这里的delay 时间设置无效果; } }
最总完整代码:(并不推荐这种方式来实现动画)
function addHeight(){ var obj=document.getElementById("man"); for(var i=1;i<10;i++){ setTimeout((function(para){ // 第一个函数(也就是function(para))执行后 ,返回 返回函数引用(函数体) return function (){ //立即执行之后 返回一个匿名函数; var len=para*10; //这个参数可以理解成 动画元素中帧的概念! obj.style.height=len+"px"; } })(i),i*20) //如果想让效果平滑一点,那么 就将时间参数设置小一点呀; } }
//这样就实现jq animate的效果的;
实现不停地变化,我们用setInterval来实现(就是,在最外层嵌套一个seInterval函数;)
扩展
我们可以使用opacity 来达到渐变的效果的呀;
代码如下:
function addHeight(){ var obj=document.getElementById("man"); for(var i=1;i<10;i++){ setTimeout((function(para){ return function (){ obj.style.opacity=para; } })(i/10),i*1000) } }
总结:
其实这种实现方式并不是最佳的,最佳实现方式
情看我的JS-实现动画原理二(非闭包方式)
---------------------------------------------------------------------更新:有了新的方法LET 产生局部变量滴啊;
下边附带各种草稿;
<!DOCTYPE HTML> <html> <script> //這種閉包的問題還出現在我們的數組中滴呀; function fn1(){ var list = document.getElementById('list1'); for(var i=1;i<=5;i++){ var item = document.createElement('li'); item.appendChild(document.createTextNode('item ' +i)) console.log(i); item.onclick=function (ev){ console.log('item' +i+ 'is clicked') } list.appendChild(item) }; } function fn2(){ var obj=document.getElementById("list1"); //同樣的問題還出現在我們數組中滴; for(var i=0;i<=5;i++){ setTimeout(function (){ var len=i*10; obj.style.height=len+"px"; //這裡會執行五次, 這個for循環相當於生成了五個timeout對象; //每次都講長度設置為50 console.log('--'); },i*1000) } } function fn3(){ //只要在我們不用的作用域中就會出現問題; var index=1; (function (){ console.log('立即執行') console.log(index); //index })(); setTimeout(function (){ console.log('100s'); console.log(index); index=300; },100) setTimeout(function (){ console.log('300s'); console.log(index); },300) } function fn4(){ //解決方案1 建立副本 var index=1; setTimeout(function (){ console.log(index); index=300; console.log("值被改变了") },100) //解決方法二 使用快級別作用域 setTimeout(function (index){ return function (){ console.log("使用了闭包中的值value:"+index); } }(index),500) setTimeout(function (){ console.log("没有使用闭包的值:"+index) },400) } //现在有了新的方法 let使用我们的块级别作用域滴呀; function fn5(){ var list = document.getElementById('list0'); for(var i=1;i<=5;i++){ var item=document.createElement("li"); item.appendChild(document.createTextNode("item" +i)); //再来绑定我们的额事件滴哎呀; (function (index){ item.onclick=function (ev){ console.log(' item '+index) } })(i) list.appendChild(item); } } //形成我们的块级别作用域; function fn6(){ var list=document.getElementById("list0"); for(let i=1;i<=5;i++){ var item=document.createElement("li"); item.appendChild(document.createTextNode("item" +i)); console.log(i); item.onclick=function(ev){ console.log("item "+i); } list.appendChild(item); } } function test(){ for(var i=1;i<=5;i++){ setTimeout(function (){ console.log(i); },300*i) } } function test2(){ for(let i=1;i<=5;i++){ setTimeout(function (){ console.log(i); },300*i) } } window.onload=function (){ //test(); console.log("--------------") test2(); //fn1(); // fn2(); // fn3(); //fn4(); //fn5(); fn 基本能够达到我们想要的基本效果了 // fn6(); // 这样,就形成了我们的局部变量; } </script> <body> <div id="list0"></div> <div id="list1" style="background-color:red;"></div> <div id="list2"></div> <div id="list3"></div> </body> </html>
這裡還有一種情況:就是我們數組;
function showInfo(){ //现在还有我们想要的基本法则; var arr=[]; for (var i=0;i<5;i++){ arr[i]=function (){ return i; } } console.log(arr); console.log(arr[0]()); console.log(arr[1]()); var arr=[]; for (var i=0;i<5;i++){ arr[i]=i; //这里已经进行了赋值操作操作呀; } console.log(arr); console.log(arr[0]); console.log(arr[1]); //然后我们通过传递参数的形式 var arr=[]; for (var i=0;i<5;i++){ ///一个立即执行的函数里,返回一个函数;再加上我们的()就执行了的啊; arr[i]=(function (index){ return function (){ return index; } })(i) } console.log(arr); console.log(arr[0]()); console.log(arr[1]()); //当然,最后,可以使用我们es5 中的 let关键之; }