[JS]骨灰級帶點新意:以關聯式下拉選單選擇郵遞區號

  • 12698
  • 0

以關聯式下拉選單選擇郵遞區號

唉…昨天打了一堆,結果在貼上程式碼的時候當掉了,
希望點部落的工作人員可以看一下,是否在貼上程式碼時有字數限制。


現在盡量用我昨天的印象回復吧…
話說郵遞區號這個功能是很多初學者會碰到的習題,
我覺得也是練兵的好所在,
因為這個功能可以用很多方式呈現,
但最終仍須朝著 User Friendly 來前進,
以下恕我用一點文字來介紹一下這個看似不起眼的功能也有一段演化歷程。



早期互動式網頁尚未大行其道時,
郵遞區號可能就是個文字方塊讓使用者自行填入,
這樣的缺點是無法驗證使用者是否惡意填入不相干號碼,
而且有些人在外地也可能熊熊不知道當地的郵遞區號,
亂填說不定還會被當成惡意攻擊…



之後就演變成用下拉式選單的方式,把所有郵遞區號全部納入,
當時也許有某工程師當時在竊笑著:這樣總不會亂填了吧?
問題是解決了,但是每當使用者要從三百多的選項中去找出自己要的答案時,
免不了一陣頭昏眼花。


後來網際網路逐漸發達以及 Server Side 的語言逐漸成熟,
有人想說何不把縣市、鄉鎮市以及郵遞區號全部做成關聯式的下拉選單呢?
這想法真的很不錯,一舉解決了上面所有問題,
然而這樣的做法反而衍生出一個新問題,就是 Post Back !
假如頁面上的元件只是文字圖片…那也許還可以接受,
可惜現在的網頁為了講求聲光效果,往往放置了一堆 Flash 元件,
所以使用者每選擇一次,就要忍受Post Back 的等待時間,
在某種程度上也是犧牲的使用者的便利性。



說了一堆…我們還是要尋求這個古老的語言 – JavaScript 的幫助,(也許不是古老…是富含傳統)
JS 在 Client Side 扮演了使用者與Server Side 緩衝介面,
讓一些安全性較低或是避免Post Back 的功能直接在使用者端作用,
近年來還發展出一些非同步的交換技術,可見網頁設計師無不為了Post Back這個問題努力尋求解答,
扯遠了…下面我會示範兩種寫法,
第一種方法稍微用到 C# 的語法,
再搭配 JS ,不過大致上是解決了Post Back 的問題。
第二個方法則是全寫在 JS 裡面,
讀者可以比較一下這兩種方法,寫法都很簡單,
但是可以複習一些基礎語法,對日後進階應用會有幫助。

 

01 private void initAddress()
02     {
03         string[] County = new string[] { "請選擇", "台北市", "基隆市", "連江縣", "台北縣", "宜蘭縣", "新竹市", "新竹縣", "桃園縣", "苗栗縣", "台中市", "台中縣", "彰化縣", "南投縣", "嘉義縣", "雲林縣", "台南市", "台南縣", "高雄市", "高雄縣", "澎湖縣", "金門縣", "屏東縣", "台東縣", "花蓮縣", "嘉義市" };
04         
05         if (City.Items.Count == 0 || Zone.Items.Count == 0)
06         {
07             City.Items.Clear();
08
09             for (int i = 0; i < County.Length; i++)
10             {
11                 City.Items.Add(County[i]);
12                 Zone.Items.Clear();
13                 Zone.Items.Add("請選擇");
14             }

15         }

16     }

17

 

首先是 C# 副程式,在畫面載入時用來初始縣市的下拉式選單,
這樣頁面一載入,縣市的下拉選單就已經有東西了,
可以放入 Page_Load 裡面。

接著是昨天讓我IE當掉的元兇…= =
就是一串寫在 JS 陣列裡面的鄉鎮縣市資料以及郵遞區號,
今天再用 FF 試過依然不行,
所以底下我就不用 Code 的方式張貼了:


County = new Array("請選擇", "台北市", "基隆市", "連江縣", "台北縣", "宜蘭縣", "新竹市", "新竹縣", "桃園縣", "苗栗縣", "台中市", "台中縣", "彰化縣", "南投縣", "嘉義縣", "雲林縣", "台南市", "台南縣", "高雄市", "高雄縣", "澎湖縣", "金門縣", "屏東縣", "台東縣", "花蓮縣", "嘉義市");



Zone = new Array(26);
        Zone[0] = new Array("請選擇");
        Zone[1] = new Array("中正區", "大同區", "中山區", "松山區", "大安區", "萬華區", "信義區", "士林區", "北投區", "內湖區", "南港區", "文山區(木柵)", "文山區(景美)");
        Zone[2] = new Array("仁愛區", "信義區", "中正區", "中山區", "安樂區", "暖暖區", "七堵區");
        Zone[3] = new Array("南竿鄉", "北竿鄉", "莒光鄉", "東引");
        Zone[4] = new Array("萬里鄉", "金山鄉", "板橋市", "汐止鎮", "深坑鄉", "石碇鄉", "瑞芳鎮", "平溪鄉", "雙溪鄉", "貢寮鄉", "新店市", "坪林鄉", "烏來鄉", "永和市", "中和市", "土城市", "三峽鎮", "樹林市", "鶯歌鎮", "三重市", "新莊市", "泰山鄉", "林口鄉", "蘆洲市", "五股鄉", "八里鄉", "淡水鎮", "三芝鄉", "石門鄉");
        Zone[5] = new Array("宜蘭市", "頭城鎮", "礁溪鄉", "壯圍鄉", "員山鄉", "羅東鎮", "三星鄉", "大同鄉", "五結鄉", "冬山鄉", "蘇澳鎮", "南澳鄉");
        Zone[6] = new Array("全區");
        Zone[7] = new Array("竹北市", "湖口鄉", "新豐鄉", "新埔鄉", "關西鎮", "芎林鄉", "寶山鄉", "竹東鎮", "五峰鄉", "橫山鄉", "尖石鄉", "北埔鄉", "峨嵋鄉");
        Zone[8] = new Array("中壢市", "平鎮", "龍潭鄉", "楊梅鎮", "新屋鄉", "觀音鄉", "桃園市", "龜山鄉", "八德市", "大溪鎮", "復興鄉", "大園鄉", "蘆竹鄉");
        Zone[9] = new Array("竹南鎮", "頭份鎮", "三灣鄉", "南庄鄉", "獅潭鄉", "後龍鎮", "通霄鎮", "苑裡鎮", "苗栗市", "造橋鄉", "頭屋鄉", "公館鄉", "大湖鄉", "泰安鄉", "鉰鑼鄉", "三義鄉", "西湖鄉", "卓蘭鄉");
        Zone[10] = new Array("中區", "東區", "南區", "西區", "北區", "北屯區", "西屯區", "南屯區");
        Zone[11] = new Array("太平市", "大里市", "霧峰鄉", "烏日鄉", "豐原市", "后里鄉", "石岡鄉", "東勢鎮", "和平鄉", "新社鄉", "潭子鄉", "大雅鄉", "神岡鄉", "大肚鄉", "沙鹿鎮", "龍井鄉", "梧棲鎮", "清水鎮", "大甲鎮", "外圃鄉", "大安鄉");
        Zone[12] = new Array("彰化市", "芬園鄉", "花壇鄉", "秀水鄉", "鹿港鎮", "福興鄉", "線西鄉", "和美鎮", "伸港鄉", "員林鎮", "社頭鄉", "永靖鄉", "埔心鄉", "溪湖鎮", "大村鄉", "埔鹽鄉", "田中鎮", "北斗鎮", "田尾鄉", "埤頭鄉", "溪州鄉", "竹塘鄉", "二林鎮", "大城鄉", "芳苑鄉", "二水鄉");
        Zone[13] = new Array("南投市", "中寮鄉", "草屯鎮", "國姓鄉", "埔里鎮", "仁愛鄉", "名間鄉", "集集鄉", "水里鄉", "魚池鄉", "信義鄉", "竹山鎮", "鹿谷鄉");
        Zone[14] = new Array("番路鄉", "梅山鄉", "竹崎鄉", "阿里山鄉", "中埔鄉", "大埔鄉", "水上鄉", "鹿草鄉", "太保市", "朴子市", "東石鄉", "六腳鄉", "新港鄉", "民雄鄉", "大林鎮", "溪口鄉", "義竹鄉", "布袋鎮");
        Zone[15] = new Array("斗南鎮", "大埤鄉", "虎尾鎮", "土庫鎮", "褒忠鄉", "東勢鄉", "臺西鄉", "崙背鄉", "麥寮鄉", "斗六市", "林內鄉", "古坑鄉", "莿桐鄉", "西螺鎮", "二崙鄉", "北港鎮", "水林鄉", "口湖鄉", "四湖鄉", "元長鄉");
        Zone[16] = new Array("中區", "東區", "南區", "西區", "北區", "安平區", "安南區");
        Zone[17] = new Array("永康市", "歸仁鄉", "新化鎮", "左鎮鄉", "玉井鄉", "楠西鄉", "南化鄉", "仁德鄉", "關廟鄉", "龍崎鄉", "官田鄉", "麻豆鎮", "佳里鎮", "西港鄉", "七股鄉", "將軍鄉", "學甲鎮", "北門鄉", "新營市", "後壁鄉", "白河鎮", "東山鄉", "六甲鄉", "下營鄉", "柳營鄉", "鹽水鎮", "善化鎮", "大內鄉", "山上鄉", "新市鄉", "安定鄉");
        Zone[18] = new Array("新興區", "前金區", "苓雅區", "鹽埕區", "鼓山區", "旗津區", "前鎮區", "三民區", "楠梓區", "小港區", "左營區");
        Zone[19] = new Array("仁武鄉", "大社鄉", "岡山鎮", "路竹鄉", "阿蓮鄉", "田寮鄉", "燕巢鄉", "橋頭鄉", "梓官鄉", "彌陀鄉", "永安鄉", "湖內鄉", "鳳山市", "大寮鄉", "林園鄉", "鳥松鄉", "大樹鄉", "旗山鎮", "美濃鎮", "六龜鄉", "內門鄉", "杉林鄉", "甲仙鄉", "桃源鄉", "三民鄉", "茂林鄉", "茄萣鄉");
        Zone[20] = new Array("馬公市", "西嶼鄉", "望安鄉", "七美鄉", "白沙鄉", "湖西鄉");
        Zone[21] = new Array("金沙鎮", "金湖鎮", "金寧鄉", "金城鎮", "烈嶼鄉", "烏坵鄉");
        Zone[22] = new Array("屏東市", "三地門鄉", "霧臺鄉", "瑪家鄉", "九如鄉", "里港鄉", "高樹鄉", "鹽埔鄉", "長治鄉", "麟洛鄉", "竹田鄉", "內埔鄉", "萬丹鄉", "潮州鎮", "泰武鄉", "來義鄉", "萬巒鄉", "嵌頂鄉", "新埤鄉", "南州鄉", "林邊鄉", "東港鎮", "琉球鄉", "佳冬鄉", "新園鄉", "枋寮鄉", "枋山鄉", "春日鄉", "獅子鄉", "車城鄉", "牡丹鄉", "恆春鎮", "滿州鄉");
        Zone[23] = new Array("臺東市", "綠島鄉", "蘭嶼鄉", "延平鄉", "卑南鄉", "鹿野鄉", "關山鎮", "海端鄉", "池上鄉", "東河鄉", "成功鎮", "長濱鄉", "太麻里鄉", "金峰鄉", "大武鄉", "達仁鄉");
        Zone[24] = new Array("花蓮市", "新城鄉", "秀林鄉", "吉安鄉", "壽豐鄉", "鳳林鎮", "光復鄉", "豐濱鄉", "瑞穗鄉", "萬榮鄉", "玉里鎮", "卓溪鄉", "富里鄉");
        Zone[25] = new Array("全區");


ZipCode = new Array(26);
        ZipCode[0] = new Array("請選擇")
        ZipCode[1] = new Array("100", "103", "104", "105", "106", "108", "110", "111", "112", "114", "115", "116", "117");
        ZipCode[2] = new Array("200", "201", "202", "203", "204", "205", "206");
        ZipCode[3] = new Array("209", "210", "211", "212");
        ZipCode[4] = new Array("207", "208", "220", "221", "222", "223", "224", "226", "227", "228", "231", "232", "233", "234", "235", "236", "237", "238", "239", "241", "242", "243", "244", "247", "248", "249", "251", "252", "253");
        ZipCode[5] = new Array("260", "261", "262", "263", "264", "265", "266", "267", "268", "269", "270", "272");
        ZipCode[6] = new Array("300");
        ZipCode[7] = new Array("302", "303", "304", "305", "306", "307", "308", "310", "311", "312", "313", "314", "315");
        ZipCode[8] = new Array("320", "324", "325", "326", "327", "328", "330", "333", "334", "335", "336", "337", "338");
        ZipCode[9] = new Array("350", "351", "352", "353", "354", "356", "357", "358", "360", "361", "362", "363", "364", "365", "366", "367", "368", "369");
        ZipCode[10] = new Array("400", "401", "402", "403", "404", "406", "407", "408");
        ZipCode[11] = new Array("411", "412", "413", "414", "420", "421", "422", "423", "424", "426", "427", "428", "429", "432", "433", "434", "435", "436", "437", "438", "439");
        ZipCode[12] = new Array("500", "502", "503", "504", "505", "506", "507", "508", "509", "510", "511", "5112", "513", "514", "515", "516", "520", "521", "522", "523", "524", "525", "526", "527", "528", "530");
        ZipCode[13] = new Array("540", "541", "542", "544", "545", "546", "551", "552", "553", "555", "556", "557", "558");
        ZipCode[14] = new Array("602", "603", "604", "605", "606", "607", "608", "611", "612", "613", "614", "615", "616", "621", "622", "623", "624", "625");
        ZipCode[15] = new Array("630", "631", "632", "633", "634", "635", "636", "637", "638", "640", "643", "646", "647", "648", "649", "651", "652", "653", "654", "655");
        ZipCode[16] = new Array("700", "701", "702", "703", "704", "708", "709");
        ZipCode[17] = new Array("710", "711", "712", "713", "714", "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725", "726", "727", "730", "731", "732", "733", "734", "735", "736", "737", "741", "742", "743", "744", "745");
        ZipCode[18] = new Array("800", "801", "802", "803", "804", "805", "806", "807", "811", "812", "813");
        ZipCode[19] = new Array("814", "815", "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", "830", "831", "832", "833", "840", "842", "843", "844", "845", "846", "847", "848", "849", "851", "852");
        ZipCode[20] = new Array("880", "881", "882", "883", "884", "885");
        ZipCode[21] = new Array("890", "891", "892", "893", "894", "896");
        ZipCode[22] = new Array("900", "901", "902", "903", "904", "905", "906", "907", "908", "909", "911", "912", "913", "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", "931", "932", "940", "941", "942", "943", "944", "945", "946", "947");
        ZipCode[23] = new Array("950", "951", "952", "953", "954", "955", "956", "957", "958", "959", "961", "962", "963", "964", "965", "966");
        ZipCode[24] = new Array("970", "971", "972", "973", "974", "975", "976", "977", "978", "979", "981", "982", "983");
        ZipCode[25] = new Array("600");


 

頁面的部分,放置了兩個下拉式選單以及一個文字方塊,
分別用來呈現縣市、鄉鎮市、郵遞區號,
比較要注意的是文字方塊在這邊是把它 disable 掉,
變成只能顯示而不能改變值,當然你也可以其他方式來呈現,
例如 div + innerHtml

 

1 <select id="City" runat="server" onchange="changeCity()"></select>                  
2 <select id="Zone" runat="server" onchange="changeArea()"></select>
3 <input id="Zip" runat="server" type="text" disabled="disabled" />

 

01 function changeCity()
02 {
03 var CityIndex=this.document.form1.City.selectedIndex; //取得被選取的城市的索引值
04 var AreaLength=Zone[CityIndex].length; //根據程式的索引值得知相對應(鄉鎮市)陣列的長度
05 document.getElementById("Zone").length=AreaArrayLength+1; //根據得到的(鄉鎮市)陣列長度來決定下拉選單的容量
06           
07 for (i=0; i<AreaLength; i++)
08 { //把內容塞入下拉選單
09 document.getElementById("Zone").options[i].text = Zone[CityIndex][i];
10 document.getElementById("Zone").options[i].value = Zone[CityIndex][i];
11 }

12           
13 document.getElementById("Zone").selectedIndex = 0; //設定預設被選取的選項
14 changeArea(); //順便帶出預設的郵遞區號
15 }

16

 

1 function changeArea()
2 {
3 var CityIndex=this.document.form1.City.selectedIndex; //取得被選取的城市的索引值
4 var AreaIndex=this.document.form1.Zone.selectedIndex; //取得被選取的鄉鎮市的索引值
5 document.getElementById("Zip").value=ZipCode[CityIndex][AreaIndex]; //取得並顯示郵遞區號
6 }

7

 


 

以上就是第一個方法,
其實印象中這個範例好像是網路上看到拿過來改的,
如果知道的網友麻煩跟我說一下囉,我會註明來源的。

第二個方法跟第一個很類似,但是全部都是用 JS 來完成,
寫法也比較精簡,可以和第一個比較看看,
我個人也偏愛第二種方法,因為可以不用綁 Server Side 的程式,
假如是寫 JSP或是PHP就可以直接拿來套用了,沒有平台的限制。

1 <body onload="JavaScript:changeCity();">

 

01 <select id="City" runat="server" onchange="changeCity()">
02     <option value="0">請選擇</option>
03     <option value="1">台北市</option>
04     <option value="2">基隆市</option>
05     <option value="3">連江縣</option>
06     <option value="4">台北縣</option>
07     <option value="5">宜蘭縣</option>
08     <option value="6">新竹市</option>
09     <option value="7">新竹縣</option>
10     <option value="8">桃園縣</option>
11     <option value="9">苗栗縣</option>
12     <option value="10">台中市</option>
13     <option value="11">台中縣</option>
14     <option value="12">彰化縣</option>
15     <option value="13">南投縣</option>
16     <option value="14">嘉義縣</option>
17     <option value="15">雲林縣</option>
18     <option value="16">台南市</option>
19     <option value="17">台南縣</option>
20     <option value="18">高雄市</option>
21     <option value="19">高雄縣</option>
22     <option value="20">澎湖縣</option>
23     <option value="21">金門縣</option>
24     <option value="22">屏東縣</option>
25     <option value="23">台東縣</option>
26     <option value="24">花蓮縣</option>
27     <option value="25">嘉義市</option>
28 </select>
29 <select id="Zone" runat="server" onchange="changeZone()"></select>
30 <input id="Zip" runat="server" type="text" disabled="disabled" />
31

Html 碼部分可以看得出縣市是直接寫在裡面,
我想這樣也有好處,因為縣市本來就不會變動了,(說有好幾個縣市要升格了…)
把這些瑣碎的東西放這邊也可以減少伺服器程式碼的複雜度。

01 function changeCity()
02        {  
03             document.getElementById("Zone").length=0; //先將鄉鎮市的下拉選單清除
04             //
05             var City=document.getElementById("City").selectedIndex; //取得被選取的縣市的索引
06             var ZoneLength=Zone[City].length; //根據縣市索引得知相對應鄉鎮市群組的陣列長度
07             //
08             for(var i=0; i<ZoneLength; i++)
09             { //塞值
10                 var newOpt=new Option(Zone[City][i], i, true, false);                
11                 document.getElementById("Zone").options.add(newOpt);
12             }
        
13             //
14             changeZone();
15        }

16


 

1 function changeZone()
2        {
3             var City=document.getElementById("City").selectedIndex; //取得被選取的縣市的索引
4             var Zone=document.getElementById("Zone").selectedIndex; //取得被選取的鄉鎮市的索引
5             document.getElementById("Zip").value=ZipCode[City][Zone]; //根據索引輸出郵遞區號
6        }

7

就是這樣而已,有沒有比第一個方法簡潔呢?
既不複雜也很好維護。
除此之外,用第二種方法的話,縣市那個陣列就可以砍掉囉,程式碼也可以看起來少一點。