定時器:頁面凍結問題及解決

思考

當咱們在事件處理程序中使用定時器時,沒觸發一次事件,就會啓動新的定時器,若是新的定時器與舊的定時器同時執行,最終的結果並非咱們預想的那樣,咱們應該怎麼去解決呢?總不可能讓用戶在一個時間段只能點擊一次吧。本文給出了一個簡單的解決方法,但願和你們共同探討。css

實現一個鼠標懸浮圖片名切換到相應圖片的效果

如下是未解決問題的代碼:html

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方法,兩個同時運行的方法對同一個元素執行不一樣的移動,就會形成圖片來回的移動或者移動速度加快,與預設的效果不一樣。spa

解決辦法

這種狀況須要及時的停止前一個一次性定時器的鏈式調用就能夠達到只執行最新的任務的目的
在moveElement方法中給目標元素添加一個movement屬性,經過將定時器的ID存入這個屬性中,每次執行定時器的移動代碼以前先清除以前的定時器,再執行,就能避免目標元素上同時存在兩個不一樣的定時器的問題。code

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);
}

若是使用間隙性定時器也可使用一樣的方法清除多餘的定時器,但建議使用一次性定時器的鏈式調用。htm

相關文章
相關標籤/搜索