級別: 初級
劉 筱
2002 年 4 月 01 日
隨
著internet的發展,XML作為一種跨平臺的通用結構化數據描述語言越來越得到人們的重視,并已經得到了廣泛應用,如MicroMedia公司出品
的Dreamweaver、Flash以及游戲搶灘登錄等軟件都利用了XML文件作為數據存儲方式,而且Microsoft.NET也是架構在XML上面
的。目前出現的取代HTML語言的下一代網頁制作語言XHTML(可擴展超文本標記語言),就是建立在XML基礎上,因此掌握XML技術是未來網頁制作者
必備技能。
本文通過一個模擬標準Windows菜單程序來介紹有關XML技術應用。
程序原理
考慮到層疊菜單復雜性,為使程序簡化,只模擬到二級子菜單。下面我們來看看標準windows菜單過程:鼠標移入菜單時突出顯示,移出時回復原狀,點擊則
菜單凹陷顯示并打開子菜單,鼠標點擊子菜單則完成相應功能。當子菜單打開后移動鼠標,則移入菜單凹陷顯示并打開相應子菜單,移出菜單則回復原狀并隱藏相應
子菜單,若鼠標并不是移動到另外菜單而是在頁面其它地方,則移出菜單仍凹陷顯示,相應子菜單也不隱藏,只有當在非菜單處點擊時才恢復原狀并隱藏子菜單。標
準Windows菜單一個重要特點就是子菜單打開后,在鼠標移出菜單時并不隱藏或者在文檔中非菜單處任意單擊時才隱藏。目前很多網頁菜單程序都做不到這
點,一般都是移入菜單時打開子菜單,移出菜單時隱藏子菜單。采用IE5.0中新提供的鼠標捕獲技術就可以完全解決這個問題。所謂鼠標捕獲,就是與鼠標相關
的所有事件都由設定鼠標捕獲的對象進行處理,而無論這些事件是否由該對象觸發。
由于xml文檔非常適合描述結構化數據,故我們使用xml文檔存儲菜單及一級子菜單的有關信息。
為
便于在其它頁面使用模擬標準Windows菜單,我們并不使用代碼功能重用性能比較差的外部腳本包含文件方法,而是采用IE
5.0新引入的DHTML行為(Behavior)技術將菜單功能代碼封裝在一個HTML 行為組件(HTC)內。
HTML行為組件封裝了頁面上特定的功能或動作,當把某個行為組件附加到頁面上的標準HTML元素(對象)時,將增強該元素(對象)的默認功能,使得該元
素(對象)含有行為的屬性、方法或事件,這使代碼重用變得十分容易,并簡化了頁面的HTML代碼,提高了頁面的可管理性。
因篇幅所限,有關xml文檔及HTML行為組件的更多細節請參閱有關資料,本文不予詳述。
程序實現
1.主頁面(index.htm)
我
們首先在主頁面中定義充當菜單容器的Div元素,并使用CSS中的behavior屬性附加行為組件(Menu.htc),這樣就可以使用元素擴充的屬性
xmlsrc來指定存儲菜單信息的數據文件(Menu.xml)以及使用onMenuClick來捕獲組件觸發的新事件并調用相應事件處理函數。
此外為簡化程序,在主頁面中定義了突出(Up_Menu)、凹陷(Dn_Menu)、原狀(Menu)三種菜單外觀樣式,在實際應用時應在組件中定義菜單顯示外觀,這樣更符合組件開發原則。
2.菜單組件(Menu.htc)
模
擬標準Windows菜單的功能主要由菜單組件提供。菜單由以下Html元素組成:充當菜單容器的Div元素(在主頁面定義)、用于一級菜單項的span
元素(初始化菜單時創建)、包含二級菜單項的Div元素(單擊一級菜單時建立)、二級菜單項的Div元素(單擊一級菜單時建立)。在該組件中定義了用于指
定菜單數據文件的xmlsrc屬性、點擊二級菜單時觸發的onMenuClick事件。
當主頁面解析完畢后觸發
ondocumentready事件,組件捕獲這個事件并調用事件處理MenuInit()函數初始化一級菜單。當觸發鼠標事件時,如
onmouseover、onmouseout、onmouseclick等,組件將分別捕獲這些事件并調用相應的事件處理函數MenuOver()、
MenuOut()、MenuClick()。在這些處理函數中首先通過Event.srcElement屬性確定觸發事件的對象,然后依據對象type
類型(如parentMenu、subMenu或其它)分別做相應處理,如更改菜單顯示外觀、打開或隱藏子菜單、觸發新事件等。
在
一級菜單觸發有關鼠標事件后,打開二級菜單并通過setCapture()方法對一級菜單對象設置鼠標捕獲。此后所有在該菜單或者文檔任意位置觸發的
onmouseover、onmouseout、onmouseclick鼠標事件都由該菜單對象負責處理,但event.srcElement屬性仍是
觸發鼠標事件的對象而不是設置鼠標捕獲的對象。當在二級子菜單或文檔中非菜單處任意單擊時,隱藏二級菜單并通過releaseCapture()方法釋放
鼠標捕獲。
單擊二級菜單時,其事件處理函數onmouseclick通過createEventObject方
法創建一個event(事件)對象,再通過fire方法觸發新事件,并利用event對象的有關屬性傳遞信息(如event.menuId返回所選定的菜
單ID),然后由容器捕獲這個事件,并調用相應事件處理函數HanderSubMenu ()。在主頁面中定義函數HanderSubMenu
()能夠使菜單組件更具通用性。
3.菜單數據文件(Menu.xml)
Item節點存儲一級菜單信息,SubItem節點存儲二級菜單信息,每個節點都含有兩個屬性:value(菜單ID)、name(菜單名稱)。
該程序必須在IE5.0及以上版本瀏覽器運行,運行結果如圖。怎么樣?象不象標準Windows菜單。
附:模擬標準Windows菜單源代碼(在Win98+IE5.0下通過)
index.htm文件:
<Html> <Head> <Title>菜單組件示例</Title> <style> <!-- .Menu{ border-top:2 solid #CCCCCC;border-bottom:1 solid #CCCCCC;border-left:2 solid #CCCCCC; border-right:1 solid #CCCCCC; } .Up_Menu { border-top:2 outset;border-left:2 outset;border-right:1 outset #FFFFFF; border-bottom:1 outset #FFFFFF; background-color:#CCCCCC; } .Dn_Menu{ border-top:2 inset ;border-left:2 inset ;border-right:1 inset ;border-bottom:1 inset ; background-color:#CCCCCC; } --> </style> <script> function HanderSubMenu(){//選擇子菜單后相應處理 switch(event.menuId){ case event.menuId: alert(event.menuId); break; } } </script> </Head> <Body style="background-color:#CCCCCC;"> <TABLE style="font-size:12px;"> <TBODY><TR height="10" > <TD Align="center" height=25 style="border-top:2px groove;border-bottom:2px groove;"> <div id="Menu" style="behavior:url(Menu.htc)" xmlsrc="Menu.xml" onMenuClick="HanderSubMenu()"></div> </TD> </TR> </TBODY> </TABLE> </Body> </Html>
|
Menu.htc文件:
<PUBLIC:COMPONENT> <PUBLIC:PROPERTY Name="xmlsrc" PUT="putxmlsrc"/> <PUBLIC:EVENT Name="onMenuClick" ID="menuClick" /> <PUBLIC:ATTACH EVENT="ondocumentready" For="element" ONEVENT="MenuInit()" /> <PUBLIC:ATTACH EVENT="onmouseover" for="element" ONEVENT="MenuOver()" /> <PUBLIC:ATTACH EVENT="onmouseout" for="element" ONEVENT="MenuOut()" /> <PUBLIC:ATTACH EVENT="onclick" for="element" ONEVENT="MenuClick()" /> <Script language="JavaScript"> var xmldoc=null;// xml文檔對象變量 var activeMenu=null;//打開子菜單的父菜單對象變量 var menuContainer=null;//包含子菜單項容器對象變量 function putxmlsrc(str){//載入菜單數據文件 xmldoc= new ActiveXObject("Microsoft.XMLDOM");//創建xml文檔對象 xmldoc.async=false; xmldoc.load(str);//載入菜單數據 } function MenuInit(){//初始化菜單 var parentMenuItems = xmldoc.selectNodes("http://Itemlist/Item"); //讀取一級菜單數據 var xmlElement = parentMenuItems.nextNode(); var newElement; while (xmlElement != null){ newElement = document.createElement("span"); //創建菜單元素 newElement.type = "parentMenu"; with (newElement){ innerHTML = xmlElement.getAttribute("name"); id=xmlElement.getAttribute("value"); className="Menu"; } with (newElement.style){ position="relative"; width= 60; cursor="default"; } element.appendChild(newElement); //element指附加行為的元素 xmlElement = parentMenuItems.nextNode(); } } function MenuOver(){ var EventSource=event.srcElement;//捕獲觸發事件的對象 switch(activeMenu){//判斷子菜單是否存在 case null://不存在子菜單 if(EventSource.type=="parentMenu")EventSource.className="Up_Menu"; break; default: switch(EventSource.type){//判斷觸發事件對象類型 case "parentMenu"://移入到一級菜單 if(activeMenu!=EventSource){//判斷是否移入到新一級菜單 removeSubMenu();//刪除原有子菜單 buildSubMenu(EventSource.id);//建立新子菜單 EventSource.setCapture();//對新菜單設置鼠標捕獲 activeMenu.className="Menu"; activeMenu=EventSource; //更新打開子菜單的父菜單對象變量 activeMenu.className="Dn_Menu"; } break; case "subMenu"://移入到子菜單 EventSource.style.color="#FF0000"; EventSource.style.textDecoration="underline"; break; } break; } } function MenuOut(){ EventSource=event.srcElement switch(activeMenu){ case null: if(EventSource.type=="parentMenu")EventSource.className="Menu"; break; default: if(EventSource.type=="subMenu"){ EventSource.style.color="#000000"; EventSource.style.textDecoration="none"; } break; } } function MenuClick(){ EventSource=event.srcElement switch(EventSource.type){ case "parentMenu": if(activeMenu!=EventSource){ removeSubMenu(); buildSubMenu(EventSource.id); EventSource.setCapture(); EventSource.className="Dn_Menu"; activeMenu=EventSource; } break; case "subMenu": removeSubMenu(); activeMenu.className="Menu"; activeMenu.releaseCapture();//釋放鼠標捕獲設置 activeMenu=null; var eventObject = createEventObject();//創建事件對象 eventObject.menuId = EventSource.id;//通過事件對象屬性傳遞所選子菜單ID menuClick.fire(eventObject);//將事件觸發到容器頁面 break; default: removeSubMenu(); if(activeMenu!=null){ activeMenu.releaseCapture(); activeMenu.className="Menu"; activeMenu=null; } break; } } function buildSubMenu(EventSourceid){//建立子菜單 menuContainer = document.createElement("div"); with (menuContainer.style){ position="absolute"; left=0; top=15; color="#000000"; cursor="default"; } eval(EventSourceid).appendChild(menuContainer); var subMenuItems = xmldoc.selectNodes("http://Item[@value='"+EventSourceid+"']/SubMenu"); var xmlElement = subMenuItems.nextNode(); var newElement; while (xmlElement != null){ newElement = document.createElement("div"); newElement.type = "subMenu"; with (newElement){ innerHTML ="□ "+xmlElement.getAttribute("name"); id=xmlElement.getAttribute("value"); } with (newElement.style){ width=75; height=18; } menuContainer.appendChild(newElement); menuContainer.className="Up_Menu"; xmlElement = subMenuItems.nextNode(); } } function removeSubMenu(){//刪除子菜單 if(menuContainer!=null)menuContainer.removeNode(true); } </Script> </Component>
|
Menu.xml文件:
<?xml version="1.0" encoding="gb2312" ?>//xml處理指令指明為中文編碼,若不指明則不支持中文 <Itemlist> <Item value="file" name="文件" > <SubMenu value="New" name="新建"></SubMenu> <SubMenu value="Open" name="打開"></SubMenu> <SubMenu value="Save" name="保存"></SubMenu> <SubMenu value="Print" name="打印"></SubMenu> <SubMenu value="Exit" name="退出"></SubMenu> </Item> <Item value="Edit" name="編輯" > <SubMenu value="Cut" name="剪切"></SubMenu> <SubMenu value="Copy" name="復制"></SubMenu> <SubMenu value="Paste" name="粘貼"></SubMenu> <SubMenu value="Del" name="刪除"></SubMenu> </Item> <Item value="Help" name="幫助"> <SubMenu value="Topic" name="主題"></SubMenu> <SubMenu value="About" name="關于"></SubMenu> </Item> </Itemlist>
|
關于作者