视频10:53处有解决方法
代码是存在问题,但错不在这,
var flag = true; 需要定义在定时器内
function commonStartMove(obj, json, fun) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var flag = true; // 需要将flag定义在此处 ?
for (var attr in json) {
...
}
if (flag) {
clearInterval(obj.timer);
if (fun) {
fun();
}
}
}, 30);
}
按自己的理解改了部分代码 :)
朋友,谁说同时运动不可以有链式运动呀,比如说你要把 width 和 height 同时运动完成了,再运动透明度opacity。那这时,你不就是需要链式运动了吗。
PS最后这位大神姐姐这一课都标明了,是更好的运动框架,
既可以同时运动,也可以链式运动,你要什么情况你就码什么代码就可以了
修改后的代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style type="text/css"> *{margin: 0; padding: 0;} ul,li{list-style: none;} ul li{width:200px;height:100px;background:yellow;opacity:0.3;filter:alpha(opacity:30);border: #ccc 4px solid;} </style> </head> <script type="text/javascript" > function startMove(obj, json, fn) { clearInterval(obj.timer); obj.timer = setInterval(function() { var flag = true; for(var attr in json) { //目标值 var iCur = 0; if(attr == 'opacity') { iCur = Math.round(parseFloat(getStyle(obj,attr)) * 100); } else { iCur = parseInt(getStyle(obj,attr)); } //speed var iSpeed = (json[attr] - iCur) / 8; iSpeed = iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed); //stop if(iCur != json[attr]) { flag = false; } if(attr == 'opacity') { obj.style.filter = 'alpha(opacity:'+ (iCur + iSpeed) +')'; obj.style.opacity = (iCur + iSpeed) / 100; } else { obj.style[attr] = iCur + iSpeed + 'px'; } } if(flag){ clearInterval(obj.timer); if(fn){ fn(); } } }, 30) } function getStyle(obj, attr) { if(obj.currentStyle) { return obj.currentStyle[attr]; } else { return getComputedStyle(obj, false)[attr]; } } </script> <script> window.onload = function(){ var oLi=document.getElementById('li1'); oLi.onmouseover = function(){ startMove(oLi,{width:400,height:200,opacity:100}); } oLi.onmouseout = function(){ startMove(oLi,{width:200,height:100,opacity:30}); } } </script> <body> <ul> <li id="li1"></li> </ul> </body> </html>
视频中flag的声明位置应该是写错了,实际上应该是写在定时器内。
视频中为什么动画会停止?完全是因为speed归0了,动画停止了,但实际上定时器并没有停止,还在继续运行。
视频中flag的声明位置应该是写错了,实际上应该是写在定时器内。
视频中为什么动画会停止?完全是因为speed归0了,动画停止了,但实际上定时器并没有停止,还在继续运行。
else {
icur = Math.round(parseFloat(getStyle(obj, attr)));
}
这句错了,应该是
else {
icur = parseInt(getStyle(obj, attr)); //整数型
}
要是缓冲运动就不需要flag
终于想通了,还是flag的问题。大家注意,var flag =true;这句话一定一定要放在for-in外面
理解如下:
首先for-in虽然使得看起来是同步进行,但实际还是你定义的运动1,运动2,运动3 顺序操作。
当放在外面的时候,三个运动是修改一个flag,有一个没满足都是false。
而当flag定义放在循环里的时候,每一个运动的每一次操作,都会重置flag为true。
模拟一下:
假定速度为1.
首先第一圈。宽是false,然运动,达到目标。高是false,运动,仍未达到。透明度是false,运动,仍未达到。
第二圈,宽为true,无运动,高是false,运动,仍未达到。透明度是false,运动,仍未达到。
第N-1圈,高值196,false, =197 ,透明度值0.31 false = 0.3
第N圈,高值为197,判断为false之后,高变成198 。而因为在刚刚N-1圈的时候,透明度的运动刚好达到目标值。所以这一圈初始就把运动2判断为false的flag掰成了true。
清除定时器。BUG出现。这也是为什么速度值改变结果会不一样。
总结:如果flag定义放在for-in。则你定义的3个运动里如果某个运动时间大于 排序靠后的,则这个运动无法完成。除非,你的速度够快。
没有attr呀~ 你代码里的 应该把attr改为i,for循环里 json的属性名。
新手哈
不是应该第一个循环结束后,执行第二个吗?按理说应该是顺序啊!
仔细检查检查
getComputedStyle( obj )[attr]; }需要flase,getComputedStyle要两个参数
你说的animate是指直接调用这个方法,主要传参就行了吗?
script标签不能写在<style></style>之间,而且函数名是startMove,调用的时候写出startMove1
有的这是vivian老师的主页
http://www.imooc.com/u/100329/courses?sort=publish
你可以在里面查看她的所有课程
``搞定了`` 一脸懵逼
不好意思,我已经找出来了,本人在for( var attr in json){}中把 attr 写成 i了,所以浏览器识别不了。
测试了一下可以用,看看是不是JS<script src="move.js"></script>引用路径有误,另外需要加Flag来保证只有每个值都达到target才停止动画,不然透明度到1宽度还没到400就不动了
把flag定义在定时器里,for循环外。评论里第一说了,你可以看下
startMove{this,opacity:100,width:300}
这是因为你要确定你设置的多运动都完成后才去清除定时器,这个flag就是用来判断你设置的所有运动,比如高度宽度透明度是否都达到了目标值,flag才为true,否则之前flag会变成flase,不执行清除定时器
//同步运动函数 function move(obj, json, fn) { //清除定时器,避免出现多个定时器 clearInterval(obj.timer); //设定定时器 obj.timer = setInterval(function () { //声明标杆变量 var flag = true; //遍历同步运动属性 for (var attr in json) { //获取属性值 var icur = 0; if (attr == 'opacity') { icur = Math.round(parseFloat(getStyle(obj,attr)) * 100); } else { icur = parseInt(getStyle(obj, attr)); } //设置运动速度 var speed = (json[attr] - icur)/100; speed = speed>0?Math.ceil(speed):Math.floor(speed); // 判断是否所有值都达到了目标值,判定暂停定时器的指标 if (icur != json[attr]) { flag = false; } if (attr == 'opacity') { obj.style.opacity = (icur + speed) / 100; obj.style.filter = 'alpha(opacity:' + (icur + speed) + ')'; } else { obj.style[attr] = (icur + speed) + 'px'; } } //清除定时器 if(flag){ clearInterval(obj.timer); if(fn){ fn(); } } }, 1); } //获取任意属性 function getStyle(obj, attr) { if (obj.currentStyle) { return obj.currentStyle[attr]; //IE取样式 } else { return getComputedStyle(obj, false)[attr]; } }
经过多番测试,视频中的完美运动代码存在bug,这个框架只可以实现同步动画,不可以实现链式动画。
同步动画最后会停止,不是因为
if(flag){ clearInterval(obj.timer); if(fn){ fn(); } }
而是代码中的
speed = (json[attr] - icur)/8;
这一部分等于0了,也就是说,动画不再变化了,看起来就好像清除了定时器一样。
如果在清除定时器的判定语句中加入一个测试语句,可以发现,第一次鼠标移入目标的时候,第一次执行到这个动画,是不会执行到测试的语句的,说明定时器的判定语句并未执行。
if(flag){ alert(12345678978979); //注意这部分,第一次执行动画的时候,是不会执行到这里的。因为flag一直是false clearInterval(obj.timer); if(fn){ fn(); } }
如果没有onmouseout的动画,那么,第二次鼠标移进去的时候,在执行动画之前,都满足
json[attr]=icur;
也就是说speed在第二次执行动画的时候,一直是0,那么这个时候,下面这个判定就没有执行了
if(icur != json[attr]){ flag = false; }
于是flag就是第二次执行动画的初始值,也就是:
var flag = true;
自然而然的,后面的这部分代码就能够执行了。
if(flag){ alert(12345678978979);//第二次执行onmouseover动画,就会执行到这里了 clearInterval(obj.timer); if(fn){ fn(); } }
上面讲得比较啰嗦,不知道大家有没有看懂,没看懂的可以照着一步一步去尝试一下,会得到我说的这个结果的
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj,false)[attr];
}
}
function move(obj,json,fn){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
var flag=true;
for(var attr in json){
var par=0;
if(attr=='opacity'){
var par=Math.round(parseFloat(getStyle(obj,attr))*100);
}else{
var par=parseInt(getStyle(obj,attr));
}
var speed=(json[attr]-par)/20;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(par!=json[attr]){
flag=false;
}
if(attr=='opacity'){
obj.style.filter='alpha(opacity:'+(par+speed)+')';
obj.style.opacity=(par+speed)/100;
}else{
obj.style[attr]=par+speed+"px";
}
}
if(flag){
clearInterval(obj.timer);
if(fn){ //检测是否有回调函数,有就执行
fn();
}
}
},30);
}
这是老师的 你看看 可能我们的方法名称不一样