[jQ]用 jQuery 做選單 - 山寨版的 HTC 首頁選單

在開始介紹之前,請各位先到 HTC 網站看一下他們首頁長怎樣。

htcmenu_1

有沒有覺得 HTC 網站上方的 Flash 選單很有趣呢!這次筆者就是要教各位怎樣用 jQuery 做出一個山寨版的 HTC 首頁選單

我們一樣先看 HTML 選單的部份:

1
2
3
4
5
6
7
8
9
10
11
<body>
	<ul id="menu">
		<li><a href="#" id="home">Home</a></li>
		<li><a href="#" id="abgne_tw">男丁</a></li>
		<li><a href="#" id="jellyyoyo">小神童</a></li>
		<li><a href="#" id="jquery">jQuery</a></li>
		<li><a href="#" id="flycan">飛肯</a></li>
	</ul>
	<div class="bhr"></div>
	<span id="menuMask"></span>
</body>

每一個連結都有各自的 id,這樣比較方便等下的 CSS 來使用它。接著就直接再來看 CSS 的部份:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
body {
	margin: 0;
	padding: 0;
}
#menu {
	float: right;
	margin: 50px 0 0;
	list-style: none;
}
#menu li {
	float: left;
}
#menu li a {
	display: block;
	width: 113px;
	height: 38px;
	text-indent: -9999px;
}
#home {
	background-image: url('home.png');
}
#abgne_tw {
	background-image: url('abgne_tw.png');
}
#jellyyoyo {
	background-image: url('jellyyoyo.png');
}
#jquery {
	background-image: url('jquery.png');
}
#flycan {
	background-image: url('flycan.png');
}
#menuMask {
	position: absolute;
	z-index: 10000;
	display: block;
	left: 0;
}
.bhr {
	clear: both;
	height: 15px;
	z-index: 200;
	margin: 0 auto;
	background-color: #000;
}

這邊要注意一下,為了方便等下程式的存取控制,因此筆者就把圖片的檔名設成跟連結的 id 一樣,然後遮罩用的黑色圖片也只是多加了個 _black 字樣而已。這邊雖然是把每個選單圖片都拆開來,但如果要改成一張大圖也是可以,只是要控制好 background-position 就好。

看一下圖片的寬高:

htcmenu_2

因為我們的遮罩比一般的大上一點,因此等一下程式中要做一點微調的設定,這樣才不會看起來怪怪的。若沒問題的話,就來看 jQuery 的部份囉!

?檢視原始碼 JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 避免無法正確取得選單圖片的寬高
// 因此動作延遲到 window.onload
$(window).load(function(){
	// 先取得選單的連結及找出 .selected 的選項
	// 再取得用來當遮罩的 #menuMask
	// 因為遮罩圖片比原來選單圖片大,所以設定要顯示的寬高及位置差距
	var _menu = $('#menu li>a'),
		_target = $(_menu).filter('.selected'),
		_menuMask = $('#menuMask'),
		_maskHeight = 10,
		_diffHeight = 8,
		_maskWidth = 5,
		_diffWidth = 5;
 
	// 如果沒有 .selected 的選項就預設第一個
	if(_target.length<=0){
		_target = $(_menu).eq(0);
	}
 
	// 圖片預載
	_menu.each(function(){
		$('<img />').attr('src', $(this).attr('id')+'_black.png').hide().appendTo('body');
	});
 
	// 當選單被點擊時..
	_menu.click(function(){
		// 先移除上一個有 .selected 的超連結
		$('.selected').removeClass('selected');
 
		// 把點擊到的項目加上 .selected
		var _this = $(this).addClass('selected'),
			_link = _this.attr('href');
 
		// 更換選單的背景圖片及移動選單到該選項上
		// 如果選項有連結時,則會在動畫移動完後來轉址
		_menuMask.css({
			backgroundImage: 'url('+_this.attr('id')+'_black.png)'
		}).stop().animate({
			width: $(this).width() + _maskWidth,
			height: $(this).height() + _maskHeight,
			top: $(this).offset().top - _diffHeight,
			left: $(this).offset().left - _diffWidth
		}, function(){
			// 如果有網址
			if(!!_link){
				// 如果有 target
				var _targetAttr = _this.attr('target');
				if(!!_targetAttr){
					// target = '_blank' 則開新窗
					if(_targetAttr.toLowerCase()=='_blank'){
						open(_link);
					}else{
						// 連結開在指定的 target id 上
						$('#'+_targetAttr).attr('src', _link);
					}
				}else{
					location = _link;
				}
			}
		});
 
		return false;
	}).focus(function(){
		$(this).blur();	
	});
 
	// 當瀏覽器尺寸改變時也要重新移動位置
	$(window).resize(function () {
		moveMenu($(_menu).filter('.selected'));
	});
 
	// 移動遮罩到指定的選項上面
	function moveMenu(obj){
		_menuMask.css({
			width: obj.width() + _maskWidth,
			height: obj.height() + _maskHeight,
			top: obj.offset().top - _diffHeight,
			left: obj.offset().left - _diffWidth,
			backgroundImage: 'url('+obj.attr('id')+'_black.png)'
		});
	}
 
	// 網頁載入後先移動遮罩
	moveMenu(_target);
});

一開始網頁載入後,如果連結有 .selectedclassName 時,則會把遮罩移到該選項上;反之若都沒有時,則把它移到第一個選項上面。因此,各位若有多個頁面時,就要一一的設定一下這樣的 .selected,不然就是要變更一下程式的判斷才行。

到這邊就完成整個山寨選單的製作了,讓我們看一下畫面及效果吧:
htcmenu_3

是不是給它有 9 成以上的相似度了呢!再特別說明一點,HTC 網站Flash 選單是當使用者點某一選項時,遮罩內容會馬上就變更,然後會移動到所點選的選項上面後再啟動連結的效果。因此筆者也把這功能加到我們的範例中,所以仔細注意一下整個移動的動作唷!

有上過 jQuery 課程的同學可以對照一下講義範例 5-13,做法及原理是一樣的!

更新:
2009-09-17
加入圖片預載功能
2010-01-18
加入連結開啟新窗及指定在 iframe

範例瀏覽:
http://demonstration.abgne.tw/jquery/0008/0008.html
http://demonstration.abgne.tw/jquery/0008/0008_home.html(有連結效果)

相關連結
推薦內容
發表留言

如果有任何 jQuery 問題也可以直接到 討論區 中發文討論。
  1. 梅干扣肉
    2009-09-17 15:25:37 回覆

    沙潑沙潑~~
    對了~~男丁版大~
    第一次執行時好像會出現點一下等圖載完才會顯示~~
    可以先把按到中圖片先作預載嗎?


    • 男丁格爾
      男丁格爾
      2009-09-17 17:00:42 回覆

      圖片預載的功能已經加進去囉..!!
      各位再試看看有沒有給它順下去~~


  2. 阿呆
    2009-11-04 16:29:19 回覆

    南丁老師。我整個網頁都抓下來,改了js連結
    還是不能用。要怎麼樣另存下來?


    • 男丁格爾
      男丁格爾
      2009-11-04 17:27:57 回覆

      唔~把你有問題的範例檔案上傳或是寄來看看
      不然只有這樣的描述很難知道問題..XD


  3. Felix
    2009-11-06 01:13:51 回覆

    男丁版大,我用了
    var $j = jQuery.noConflict();
    然後將所有你script的$符號改成$j
    但效果沒有了,不知是那裏弄錯 ><


    • 男丁格爾
      男丁格爾
      2009-11-06 09:48:00 回覆

      要有 sample 才知道你是錯在那..
      該行的所在位置會有影響的


  4. speEDmaniA!!!
    2009-12-16 10:02:49 回覆

    老師您好,如果我要把選單滑動的效果改成用 mouseover ,click 連結之後,可以出現下拉選單。需要改哪些地方呢?
    現在我是把 "_menu.click(function(){" 這一段改成 "_menu.mouseover(function(){"
    ,但是這樣會mouseover的地方就會直接連結,沒辦法再讓我 click


    • 男丁格爾
      男丁格爾
      2009-12-16 10:17:08 回覆

      因為原本我程式是在 click 時就把選單移到該選項後並連結到指定的網址..
      現在就算改成 mouseover 時也是會有連結的效果..
      所以你要把我範例程式的第40-44行的連結部份拿掉...把它寫在你的 click 事件中


  5. 路邊攤
    2010-01-13 23:06:45 回覆

    老師您好,請教一下,如果連結我想要另開新視窗的話要如何修改呀(或者網頁多了一個內置框架,想讓連結顯示在框架內)


    • 男丁格爾
      男丁格爾
      2010-01-14 23:01:07 回覆

      只要在超連結中加入 target 屬性後指定要開新頁還是框架 id 即可。


  6. 路邊攤
    2010-01-18 10:46:56 回覆

    謝謝大大的指導
    但我加了 target 屬性,但沒用說
    Yahoo
    又要麻煩大大指教了~


    • 男丁格爾
      男丁格爾
      2010-01-18 11:11:27 回覆

      不好意思..請把 htcmenu.js 中的第 41~43 行改用下面的程式:

      ?檢視原始碼 JavaScript
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      // 如果有網址
      if(!!_link){
      	// 如果有 target
      	var _target = _this.attr('target');
      	if(!!_target){
      		// target = '_blank' 則開新窗
      		if(_target.toLowerCase()=='_blank'){
      			open(_link);
      		}else{
      			// 連結開在指定的 target id 上
      			$('#'+_target).attr('src', _link);
      		}
      	}else{
      		location = _link;
      	}
      }

  7. 路邊攤
    2010-01-18 12:04:43 回覆

    謝謝老師
    剛才測試了開新視窗OK了
    但如果是內框的話無法使用說
    a target="I1" href="html/Home.htm" id="Home">Hone</a
    他不會顯示在內框,而是另開一個新視窗

    老師在順便請教一個問題
    backgroundImage: 'url('+_this.attr("id")+'_black.png)
    如果我有建立了一個資料夾"jpg" 如果修改語法,當我點選時他會至資料夾載入圖片
    謝謝,以上二個問題請教


    • 男丁格爾
      男丁格爾
      2010-01-18 12:38:33 回覆

      你所謂的內框是指 iframe 嗎..?它的 id 是叫 I1 嗎?
      如果你選單圖片是放在資料夾中的話..那就是把

      ?檢視原始碼 JavaScript
      1
      
       'url('+_this.attr("id")+'_black.png)'

      改成

      ?檢視原始碼 JavaScript
      1
      
       'url(資料夾/'+_this.attr("id")+'_black.png)'

  8. 路邊攤
    2010-01-18 12:47:38 回覆

    嗯~內置框架 iframe ID叫I1


    • 男丁格爾
      男丁格爾
      2010-01-18 12:49:25 回覆

      有範例網頁可參考看看嗎?


  9. 路邊攤
    2010-01-18 12:58:39 回覆
    • 男丁格爾
      男丁格爾
      2010-01-18 13:00:15 回覆

      幫 iframe 多加一個 id="I1" 後試試


  10. 路邊攤
    2010-01-18 13:16:17 回覆

    老師~抱歉我不太懂您說的意思
    原先就有這行了iframe name="I1" height="98%" width="98%" src="html/Home.htm"
    您的意思是把 iframe name="I1" 改為 iframe id="I1" 因為試了好像都沒有用


    • 男丁格爾
      男丁格爾
      2010-01-18 13:20:24 回覆

      仔細看剛剛回覆的的程式碼...
      你用到的是舊版的..不支援 iframe......如果替換最新的 code 之後..
      一樣是把 iframe 多加一個跟 name 同值的 id


  11. 路邊攤
    2010-01-18 14:48:25 回覆

    大大~真不好意思
    小弟不才,做了一些修改後又有新問題出現
    我方便寄檔給你幫忙看看嗎


    • 男丁格爾
      男丁格爾
      2010-01-18 14:51:03 回覆

      Mail 資訊在留言區塊的上方就有..


  12. 路邊攤
    2010-01-20 13:22:40 回覆

    老師您好,請教一下,此特效在Google瀏覽器下無法正常說。
    不知道有沒有辦法改善,謝謝。


    • 男丁格爾
      男丁格爾
      2010-01-20 13:27:35 回覆

      那邊不正常..?我試文章中的範例是ok的...


  13. 路邊攤
    2010-01-20 14:41:09 回覆

    謝謝老師,我使用原檔測也OK,我知道問題出現在那了@@
    我只是把選單下方那排黑色拿掉後在Google下就無法使用(但IE正常)


    • 男丁格爾
      男丁格爾
      2010-01-20 14:48:39 回覆

      黑色其實只是一條 bar 而已..應該是不影響程式的..
      可以的話..給個問題範例看看


  14. 路邊攤
    2010-01-20 21:11:20 回覆

    老師您好,已經mail給您了~


  15. kin
    2010-06-19 11:27:15 回覆

    老師您好
    我想將HTC選單與lightbox做結合
    可是開啟lightbox的圖片時
    HTC選單會顯示在lightbox上方
    請問要怎樣改在下方呢?
    範例:http://cid-3a078afd3bc4ed0f.office.live.com/self.aspx/.Documents/test.rar
    ※lightbox在平面設計選單下


    • 男丁格爾
      男丁格爾
      2010-06-19 18:54:47 回覆

      你可以先把 #menuMask 及 .bhr 的 z-index 調小一點後試看看。
      例如 #menuMask 的 z-index 設為 50, .bhr 的設成 20


  16. Angel
    2010-07-26 14:00:55 回覆

    請問板大圖片預載的功能是要放在
    // 圖片預載
    _menu.each(function(){
    $(").attr('src', $(this).attr('id')+'_black.png').hide().appendTo('body');
    });
    的那個位子...試好久都沒成功><"
    我圖片放在images...


  17. Angel
    2010-07-26 14:24:46 回覆

    圖片預載要放在哪個位子??


    • 男丁格爾
      男丁格爾
      2010-07-26 21:31:44 回覆

      你檔名也是一般跟 _blank 的區別嗎?


  18. Angel
    2010-07-26 23:52:51 回覆

    對!
    有_black
    放在images裡面


    • 男丁格爾
      男丁格爾
      2010-07-27 14:13:25 回覆

      你的問題是沒預載還是選單沒變圖片?


  19. Tao
    2010-08-03 15:20:39 回覆

    點選該按鈕,會跑去該頁!可是整個頁面會重新整理,按鈕會跑去"首頁"那選項(黑色),請問程式碼內要怎麼下?


    • 男丁格爾
      男丁格爾
      2010-08-04 11:07:37 回覆

      在每個頁面的該選項上多加個 selected 的 class


  20. cdavid
    2010-08-19 15:57:19 回覆

    點選之後,原來覆蓋黑色部分,是否連結一樣可以再次點選~


    • 男丁格爾
      男丁格爾
      2010-08-19 22:15:12 回覆

      那你要針對 _menuMask 再加上 click 事件


  21. cdavid
    2010-08-20 09:36:47 回覆

    有demo可以示範一下嗎~感恩^^


    • 男丁格爾
      男丁格爾
      2010-08-21 12:14:18 回覆

      有空時我會補上..也許你可以自己試試然後提出問題一起討論:D


  22. cdavid
    2010-08-26 16:32:42 回覆

    小弟愚笨~試了好久還是用不出來ㄋㄟ


    • 男丁格爾
      男丁格爾
      2010-08-27 16:27:42 回覆

      你要針對遮罩做 click 事件..然後點了之後找出原始的鈕來做動作