/ Work

[jQuery note.] 在 hover 上微妙的變化

通常我們對於 .hover 這個事件的印象,就如同於 .mouseenter.mouseleave 這兩個事件的合體。這種互動式(Interaction Helpers)的事件在 jQuery 中還有一個,叫做 .toggle,在這裡就暫且不提。

一般來說,我們使用 .hover 的時候,就是希望能夠監聽使用者的滑鼠動作,然後在某種條件下觸發事件。那麼,最簡單的例子就是這樣

<!DOCTYPE html>
<html> 
<head> 
<meta http-equiv="content-Type" content="text/html; charset=utf-8" /> 
<title>hover test</title> 
<style type="text/css">
<!--
#hover_one {
    width: 100px;
    height: 100px;
    border: 1px solid #efefef;
    background-color: #333333;
    opacity: 1;
    color: #ffffff;
}
-->
</style>
</head>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<script type="text/javascript">
//<![CDDA[
$(document).ready(function() {
    $('#hover_one').hover(function() {
        $(this).animate({ 'opacity':0.5 });
    }, function() {
        $(this).animate({ 'opacity':1 });
    });
});
//]]>
</script>
<body>
<div id="container">
    <div id="hover_one">Mouse Enter/Leave Here.</div>
</div>
</body> 
</html>

我們把這個東西放到 Chrome 中實作,當你在區塊中將滑鼠移入(mouseenter)與移出(mouseleave)的時候,他會改變該區塊的透明度。也許你會問,這樣有甚麼問題?其實是有的,當你快速的在該區塊移入移出的時候,你就會發現問題在哪裡了。

發現了嗎?當你的滑鼠在快速移入移出的時候,.hover 會很誠實的把你移動所觸發的事件全部做完,這是好事,但是其中所使用的動態效果,在滑鼠結束移動之後還是繼續作用,這就不一定是好事了。

範例中的方格,就像是著猴(台語)一樣猛閃!

我們由 .hover 特性可以得知,他會很忠誠的,將所觸發的事件的總次數給做完,但是由於觸發事件中,包含了 animate 的動態效果(Fade 之類的效果亦同),這些動態效果都有所謂的執行時間差,在 .hover 快速且重複性的呼叫下,animate 也很誠實的,將每一個步驟全部做完之後,才會結束。

事實上,我們有時候不希望 animate 那麼老實做完所有的事情,所以,我們可以用 stop() 來干涉他!

/// 請直接修改上述例子,加入 stop() 干涉!
$('#hover_one').hover(function() {
  $(this).stop().animate({ 'opacity':0.5 });
}, function() {
  $(this).stop().animate({ 'opacity':1 });
});

差異很明顯就出現了,在滑鼠快速移入移出的時候,Animate 因為受到 stop() 的干涉,所以並不會做完上一個動作,為什麼說是上一個動作?我們把 .hoverfnInfnOut 拆成循序的清單開來看:

  1. 滑鼠移入
  • 呼叫 stop()
  • 停止物件本身所有 animate 效果
  • 呼叫 animate()
  • 執行物件本身 animate 效果
  • 滑鼠移出
  • 呼叫 stop()
  • 停止物件本身所有 animate 效果
  • 呼叫 animate()
  • 行物件本身 animate 效果

從 1. 滑鼠移入開始看,由於一開始物件並沒有任何動態效果,所以 stop() 其實等於沒有做事,然後,待等到 6. 滑鼠移出後,此時 7. 所呼叫的 stop() 就有效果了,8. 所停止的動態效果,其實是由 4. 的呼叫所產生,這也是為什麼我說他是干涉上一個動作的原因。

以任何的動態效果來說,使用 stop() 是可以有效的干涉其進行的步驟,對於 .hover 本身其實並沒有影響,以 .hover 的角度來看,他還是不斷的去執行 fnInfnOut 的動作。所以,倘若你要在 .hover 中呼叫其他的函式,最好還是使用旗標的方式來註記目前的執行狀態是 fnIn 還是 fnOut,避免重覆大量的呼叫而造成無法預期的結果。

stop() 還可以傳兩個參數,cleanQueuejumpToEnd,你可以自行試試看。