定时器:页面冻结问题及解决

思考

当我们在事件处理程序中使用定时器时,没触发一次事件,就会启动新的定时器,如果新的定时器与旧的定时器同时执行,最终的结果并不是我们预想的那样,我们应该怎么去解决呢?总不可能让用户在一个时间段只能点击一次吧。本文给出了一个简单的解决方法,希望和大家共同探讨。

实现一个鼠标悬浮图片名切换到相应图片的效果

以下是未解决问题的代码:

html
<h1>图片预览</h1>
    <ul>
        <li><a href="#">图片1</a></li>
        <li><a href="#">图片2</a></li>
        <li><a href="#">图片3</a></li>    
    </ul>
    <div id="container" style="border-color:red">
        <div id="content">
            <img src="image/1.jpg"><img src="image/2.jpg"><img src="image/3.jpg">
        </div>
    </div>
css
#container{
    position:relative;
    overflow:hidden;
    width:200px;
    height:150px;
    border:1px solid #666;
}
img{ width:200px; }
#content{
    position:absolute;
    width:600px;
}
js
window.onload=function(){ move(); }
function move(){
    var link=document.querySelectorAll('ul>li>a');
    //因为通过style属性只能读取内部样式,所以通过script设置好top和left。
    content.style.top="0";
    content.style.left="0";
    `//将参数传入moveElement方法中
    link[0].onmouseover=function(){ moveElement('content',0,0,10); }
    link[1].onmouseover=function(){ moveElement('content',-200,0,10); }
    link[2].onmouseover=function(){ moveElement('content',-400,0,10); }
}
//移动目标元素的方法
function moveElement(elemID,fina_x,fina_y,interval){
    var elem=document.getElementById(elemID);
    //如果有正在执行的定时器,则清除
    var xpos=parseInt(elem.style.left);
    var ypos=parseInt(elem.style.top);
    if (xpos==fina_x&&ypos==fina_y) { return true; }
    if (xpos<fina_x) { xpos+=2; }
    if (xpos>fina_x) { xpos-=2; }
    if (ypos<fina_y) { ypos+=2; }
    if (ypos>fina_y) { ypos-=2; }
    elem.style.left=xpos+"px";
    elem.style.top=ypos+"px";
//将当前定时器函数的参数值组合好
    var repeat="moveElement('"+elemID+"',"+fina_x+","+fina_y+","+interval+")";
//链式调用一次性定时器继续执行
    setTimeout(repeat,interval);
}
页面效果

鼠标悬浮于li标签上,下方的图片就会移动位置直到到达目标图片的位置
图片描述

问题提出

当图片在移动的过程中,鼠标又移动到另一个li上方,图片就会来回的抖动,看起来就像不再移动了一样,或者运动速度变得更快,到达后仍然在抖动。

图片描述

问题原因

当第一鼠标悬浮到li元素上,启动moveElement方法,但在图片未到达目标位置上时,未到达定时器停止的条件,方法就会不断的执行一次性定时器调用。
而这时鼠标又移到了另一个li元素上,又启动了另一个moveElement方法,两个同时运行的方法对同一个元素执行不同的移动,就会造成图片来回的移动或者移动速度加快,与预设的效果不同。

解决办法

这种情况需要及时的中止前一个一次性定时器的链式调用就可以达到只执行最新的任务的目的
在moveElement方法中给目标元素添加一个movement属性,通过将定时器的ID存入这个属性中,每次执行定时器的移动代码之前先清除之前的定时器,再执行,就能避免目标元素上同时存在两个不同的定时器的问题。

function moveElement(elemID,fina_x,fina_y,interval){
    var elem=document.getElementById(elemID);
    //如果有正在执行的定时器,则清除
    if (elem.movement) { clearTimeout(elem.movement); }
    var xpos=parseInt(elem.style.left);
    var ypos=parseInt(elem.style.top);
    if (xpos==fina_x&&ypos==fina_y) { return true; }
    if (xpos<fina_x) { xpos+=2; }
    if (xpos>fina_x) { xpos-=2; }
    if (ypos<fina_y) { ypos+=2; }
    if (ypos>fina_y) { ypos-=2; }
    elem.style.left=xpos+"px";    
    elem.style.top=ypos+"px";
    var repeat="moveElement('"+elemID+"',"+fina_x+","+fina_y+","+interval+")";
    //将定时器ID存入elem的movement属性中
    elem.movement=setTimeout(repeat,interval);
}

如果使用间隙性定时器也可以使用同样的方法清除多余的定时器,但建议使用一次性定时器的链式调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值