The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

在 Firefox 中使用 影像地圖(Image map) 該注意的事

之前我介紹過一個 jQuery Cycle Plugin 套件,非常適合用來做跑馬燈或廣告輪播,但是今天我遇到一個跨瀏覽器的問題。我們有做一個網站用到了 jQueryjQuery Cycle Plugin,為了讓 jQuery Cycle 可以在當滑鼠移進廣告看板的範圍時可以先停止輪播,否則使用者可能才剛想要點選廣告時廣告卻換走了的窘境。

如果你的 jQuery Cycle 這樣子宣告:

$('#banners').cycle({
    fx: 'fade',
    timeout: 600
});

你只要簡單的多加上一個 pause 參數設定即可,如下:

$('#banners').cycle({
    fx: 'fade',
    timeout: 600,
    pause: 1
});

雖然一個看似簡單的設定,在 IE 中可以正常運作,但在 Firefox 中卻永遠無法停止輪播!

我看了 jQuery Cycle Plugin 發現他有一行是負責註冊 jQuery 的 hover 事件 ( 即 onmouseover 與 onmouseout 事件 ) 到放置輪播圖片的 DIV 上,如下:

$cont.hover(function(){this.cyclePause++;},function(){this.cyclePause--;});

但我發現只要滑鼠移進輪播的圖片是會引發 onmouseover 事件,但卻也會立即觸發 onmouseout 事件,我覺得十分詭異,這樣的狀況只有在 Firefox 中會發生。

我原本還以為跟事件觸發順序(Event order)有關,一般來說 W3C 定義兩種事件觸發模式:

  1. 捕獲模式 ( Event capturing ) : 這是一種由外而內的事件觸發順序
    捕獲模式 ( Event capturing )
  2. 冒泡模式 ( Event bubbling )  :這是一種由內而外的事件觸發順序
    冒泡模式 ( Event bubbling )

但我怎麼想都覺得這邏輯不太對,因為這件事根本跟事件觸發「順序」無關,而是 onmouseout 事件提早被觸發了!

研究了好一番功夫才發現原來跟 Image Map 有關,先列出我所使用的 HTML 定義:

<div id="banners">
	<div><img src='images/Banners/b1.jpg' usemap='#FPMap1' /></div>
	<div><img src='images/Banners/b2.jpg' usemap='#FPMap2' /></div>
	<div><img src='images/Banners/b3.jpg' usemap='#FPMap3' /></div>
</div>

<map id="FPMap1" name="FPMap1">
	<area coords="0, 210, 359, 227"
          href="http://example.com/" shape="rect" />
</map>
<map id="FPMap2" name="FPMap2">
	<area coords="0, 210, 359, 227" 
          href="http://example.com/" shape="rect" />
</map>
<map id="FPMap3" name="FPMap3">
	<area coords="0, 210, 359, 227"
          href="http://example.com/" shape="rect" />
</map>

你可以看到我的輪播圖片是採用 Image Map 的方式設定連結,而這就是重點中的重點!

我的 <div id="banners"> 定義了 onmouseover 與 onmouseout 事件,但是只要遇到元素內的圖片有使用 Image Map 且剛好滑鼠移到 <map> 定義的連結上時,在 Firefox 中就會立即觸發 <div id="banners"> 定義的 onmouseout 事件,以致於我的 jQuery Cycle 圖片輪播永遠不會停!

我覺得這根本就是個 by design 的 defect,一個小問題耗了我將近兩個小時的時間(包括寫這篇文章),真的很討厭。

以後各位在使用 Image Map 時,一定要特別注意這個差異,否則光除錯就會花你一堆時間。

至於 jQuery Cycle 的 替代方案(Workaround) 就是多加一段程式碼,將事件多註冊一組事件到到所有會用到 <map><area> 上面,如下程式碼:

$('#banners').parent().find('area').hover(
    function() { $('#banners').cycle('pause');  },
    function() { $('#banners').cycle('resume'); }
);

原本的 jQuery Cycle 宣告並不需要修改,因為在 IE 下還是可以執行的!