你好,我也遇到了这个问题。正如老师所讲的那样,一定是有属性在到达自己的位置的时候,立刻触发了清除定时器,导致其他的属性虽然还没有到达target,就被终止了运行。当你再次用鼠标指向的时候,定时器只会被触发一次,for循环一遍,就遇到opacity属性已经变成1,因此目标宽度只被遍历1次,增长1,所以需要移入移出4次,这个情况将会在你把目标宽度修改成201时相当明显。
我觉得应该是一个覆盖的意思,后面的会覆盖前面的功能
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
*{
margin:0;
padding:0;
}
.div{
width:360px;
background: #999;
margin:0 auto;
font-size: 0;
}
a{
width:100px;
height:100px;
text-align: center;
display:inline-block;
text-decoration: none;
font-size: 12px;
filter:alpha(opacity:100);
opacity:1;
position: relative;
background: #000;
}
.a{
margin:10px 15px;
}
.b{
margin:10px 0;
}
i{
position: absolute;
top:25px;
left:25px;
}
span{
display: block;
width:100px;
text-align: center;
color:orange;
position: absolute;
bottom: 0;
left:0;
}
img{
width:50px;
height:50px;
}
</style>
<script>
var eventUnit={
//添加句柄
addHanlder:function(element,type,hanlder){
if(element.addEventListener){
element.addEventListener(type,hanlder);
}else if(element.attachEvent){
element.attachEvent('on'+type,hanlder);
}else{
element['on'+type]=hanlder;
}
},
//删除句柄
removeHanlder:function(element,type,hanlder){
if(element.removeEventListener){
element.removeEventListener(type,hanlder);
}else if(element.detachEvent){
element.detachEvent('on'+type,hanlder);
}else{
element['on'+type]=null;
}
},
//获取事件本身
getEvent:function(event){
return event?event:window.event;
},
//获取事件类型click等事件
getType:function(event){
return event.type;
},
//获取事件目标
getElement:function(event){
return event.target.nodeName||event.srcElement.nodeName;
},
//阻止默认事件
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue=true;
}
},
//阻止事件冒泡
stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
window.event.cancelBubble=true;
}
},
//获取元素style属性由于width,height等需parseInt(getStyle(element,attr))
getStyle:function(element,attr){
if(element.currentStyle){
return element.currentStyle[attr];
}else{
return getComputedStyle(element,false)[attr];
}
}
},
timer=null;
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(eventUnit.getStyle(obj,attr))*100);
}else{
icur=parseInt(eventUnit.getStyle(obj,attr));
}
var speed=(json[attr]-icur)/20;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(json[attr]!=icur){
flag=false;
}
if(attr=='opacity'){
obj.style.opacity=(icur+speed)/100;
obj.style.filter='alpha('+(icur+speed)+')';
}else{
obj.style[attr]=(icur+speed)+'px';
}
}
if(flag){
clearInterval(obj.timer);
if(fn){
fn();
}
}
},10)
}
window.onload=function(){
var aLi=document.getElementsByTagName('a');
for(var i=0;i<aLi.length;i++){
eventUnit.addHanlder(aLi[i],'mouseenter',function(){
var _this=this.getElementsByTagName('i')[0];
startMove(_this,{top:0,opacity:0},function(){
_this.style.top=45+'px';
startMove(_this,{top:25,opacity:100})
})
})
}
}
</script>
</head>
<body>
<div class="div">
<a href="#" class="a"><i><img src="w.png" alt=""></i><span>1</span></a>
<a href="#" class="b"><i><img src="w.png" alt=""></i><span>2</span></a>
<a href="#" class="a"><i><img src="w.png" alt=""></i><span>3</span></a>
<a href="#" class="a"><i><img src="w.png" alt=""></i><span>4</span></a>
<a href="#" class="b"><i><img src="w.png" alt=""></i><span>5</span></a>
<a href="#" class="a"><i><img src="w.png" alt=""></i><span>6</span></a>
</div>
</body>
</html>
没有细看。但是感觉应该是{“opacity”,"30"}这个样子。
var flag=true; 及for(var attr in json) 应该放在定时器n内, json的for循环之前
if(flag){清除定时器和fn回调}应该放在定时器n内, json的for循环之后
具体解释可以参考<JS动画效果课程 6-2小节>的评论区讨论,希望能帮到你
更改后的参考code如下(未贴上来的其他code不变):
function move(obj, json,fn){ //清除与调用计时器 //attr是json内的name clearInterval(obj.n); obj.n=setInterval(function(){ // console.log(obj.offsetWidth) // 当有边框时不能用offsetWidth,而要用clientwidth或者 // 是通过获取非行间样式的方法或的width(getStyles) var flag = true; for (var attr in json) { var cur = 0; //判断是哪种类型 if (attr == "opacity") { cur = parseFloat(getStyle(obj, attr)) * 100; } else { cur = parseInt(getStyle(obj, attr)); } //计算速度 var speed = (json[attr] - cur) / 10; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); //给对象赋值 if (cur != json[attr]) { flag = false; } if (attr == "opacity") { obj.style.opacity = (cur + speed) / 100; obj.style.filter = "alpha(opacity:" + cur + speed + ")"; } else { obj.style[attr] = cur + speed + "px"; } } if (flag) { clearInterval(obj.n); if (fn) { fn(); } } },17); }
animate 是jquery封装好的方法。这里是用原生自己写的
http://www.imooc.com/qadetail/121930应该是他回答的这样
第一个函数相当于通知它去改变宽度,通知完之后,不管完成没完成,都继续执行第二个函数了,而第二个函数里面也有clearInterval();就把前一个未执行完的动画清除了,相当于覆盖了。(改变宽度可能要300ms,而通知可能就要1ms,第二个函数通知的时候也就1ms,很快,就相当于覆盖了),不知道我说明白了吗
经过我的测试,可以这样理解,在执行第一个startmove中定时器里面的函数的时候是在设定的30ms后才会执行第一次定时器里面的函数,但之后的程序仍然会继续执行,所以这时就会继续执行下一个startmove函数,而下一个startmove的第一步就是clearinterval,所以你会发现,第一个startmove的定时器中的函数其实根本就没有执行,宽度根本一次都没变,第一个startmove中的定时器在还没有等到30ms开始执行的时候就已经被clearinterval了,所以你会感觉是第一个没执行完就开始执行下一个了
html 呢?
你打过的debugger看看是不是这样一套步骤就行了嘛
可能是播放器的问题吧