DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> XUL教程 - 9.2 - 模板
XUL教程 - 9.2 - 模板
編輯:XML詳解     

 本文示例源代碼或素材下載

  在這一小節,我們將學習如果使用數據填充元素。

  填充元素(Populating Elements)

  XUL提供了通過RDF數據建立元素的方法,來源可以是一個RDF文件,也可以是一個內部數據源。Mozilla本身提供了很多數據源,比如書簽、歷史記錄、郵件列表等。我們在下一小節會針對這部分進行更多的討論。

  我們通常會向treeitems和menuitems這類的元素填充數據。但你完全可以根據實際情況向其他元素填充數據。在這裡,我們還是從這些其他元素入手開始講解,因為實現樹型和菜單需要的代碼比較多。

  為了使用RDF數據建立元素,首先要為這些元素提供一個復制用的模板。實際上,我們只是提供了第一個元素而已,剩下的元素都是在第一個元素的基礎上構造出來的。

  模板是通過template元素建立的。template元素裡用於放置那些新構建元素的內容。template元素要置於包含新構建元素的容器中,比如說你要創建一個tree元素,那麼就要把template元素置於tree元素中。

  上面這些通過一個簡單的例子來說明會很直觀明了,在這個例子中,我們會為每個書簽都建立 一個按鈕。Mozilla提供了一個書簽的數據源,我們可以直接拿來使用,為了簡便,我們只取最頂層的書簽(也可能是文件夾)來建立按鈕。對於那些子標 簽,我們可能會通過樹型結構或者菜單等來顯示這種層疊的結構。

  這個例子和其他直接引用內部數據源的程序一樣,只能通過Chrome開頭的地址來調用,處於安全考慮,Mozilla禁止從其他數據源間接調用內部數據源。

  為了運行這個例子,你需要建立一個Chrome包並把文件都置於包中,這時就可以通過在浏覽器的地址欄輸入Chrome地址運行了。

  示例 9.2.1:

<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1">
<template>
<button uri="rdf:*" label="rdf:http://home.Netscape.com/NC-rdf#Name"/>
</template>
</vbox>

XUL教程 - 9.2 - 模板  

  在這個例子中,建立了一個vbox,vbox裡面包含一列的按鈕,每個按鈕都對應一個頂級的書簽。你可以注意到template元素內只有一個button元素。這個唯一的按鈕元素是所有按鈕元素建立的基礎。旁邊的圖片就是最後的運行結果,每個按鈕對應於一個書簽。

  你可以試著在保持這個例子打開的情況下,向浏覽器添加一個書簽,你會發現這個例子中會立刻添加一個按鈕,對應於你剛剛添加的那個書簽。(你可能需要重新激活這個窗口,這樣才能看到結果)

  模板本身被置於vbox中,而box容器有兩個特性專門是為模板服務的,可以標識數據的來源。第一個是datasource特性,用來聲明用來建立 元素的RDF數據源。在這個例子中,對應的是rdf:bookmarks。你一定可以猜到這個RDF對應的就是書簽數據源。這個數據源是由Mozilla 提供的。如果要使用自己的數據源,只需要在datasources特性中指定自定義的RDF地址就可以,就像下面例子中的一樣:

  也還可以同時設置多個數據源,只要在不同的數據源地址間加上空格就可以。這通常用於顯示多個來源的數據。

  ref特性用於說明你想從數據源獲取哪些數據。在這個書簽的例子中,使用的是NC:BookmarksRoot,對應的是最頂級的書簽。ref具體取什麼值依賴於要使用的數據源。如果你使用自己的RDF文件作為數據源,ref的value值通常被設置為Bag、Seq或者Alt元素的about特性的值。

  當向box容器添加了這兩個特性以後,就可以使用模板來生成元素了。模板裡的元素要使用不同的方式來聲明。你應該注意到上面例子中,button元素設置了uri特性,同時為label特性設置了一個特殊含義的值。

 

模板裡的特性值如果是以“rdf:”開頭的,就表明這個值是要從數據源中讀取的。在上面的例子中,label特性就是這種情況。value中除了“rdf:”的剩余部分由命名空間和屬性名稱組成,表明要使用數據源中的name屬性。如果你對這部分感到迷糊,請重新閱讀《XUL教程 - 9.1 - RDF概述》的最後一段。那個例子描述了RDF中的資源是怎樣被指向的。在這裡我們只使用name屬性,當然其他屬性在這裡也是可以使用的。

  我們為這些按鈕的label特性設置了特定的URI,是因為我們需要用RDF數據源中的name屬性來填充label。我們可以把URI放到按鈕的 任何一個特性中,放到其他元素中也是可以的。不管放到哪個特性中,都會被數據源中相應的值替換。最後的結果,就是我們用按鈕label顯示出了每個書簽的 名字。

  下面的例子展示了我們如何為按鈕的其他特性設置數據源。當然我們已經假設數據源中包含相應的資源。如果需要的資源在數據源中沒有被找到,那麼特性的value就會被設置為空字符串。

<button class="rdf:http://www.example.com/rdf#class"
    uri="rdf:*"
    label="rdf:http://www.example.com/rdf#name"
    crop="rdf:http://www.example.com/rdf#crop"/>

  如上面例子所示,你可以通過不同的數據源動態設置元素的每個特性。

  uri特性用定義開始生成內容的元素。之前的內容只會生成一次,而之後的內容會每次都生成。在後面通過模板建立樹型元素的例子中,我們將對這點進行更加詳細的闡述。

  當我們將這些特性添加進模板所在的容器後(在這個例子中是box),就可以使用外部數據來建立各種有趣的列表了。我們當然可以在模板中多放幾個元素,也可以在任何元素的特性上添加RDF引用,下面就是一個例子:

實例 9.2.2:

<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1">
<template>
<vbox uri="rdf:*">
<button label="rdf:http://home.Netscape.com/NC-rdf#Name"/>
<label value="rdf:http://home.Netscape.com/NC-rdf#URL"/>
</vbox>
</template>
</vbox>

  這個模板建立了一個vbox,容器中每個書簽都對應於一個按鈕和一個標簽。按鈕上顯示的是書簽的名字,標簽上顯示的是書簽的地址。

  新建立的元素從功能上來說,和直接向XUL中添加數據是沒有差別的。每一個通過模板建立的元素都會被自動添加id特性,用來標識這個資源,你也可以使用這個特性對每個資源進行引用。

  你還可以在同一個特性的值中,定義多個不同的資源,中間用空格分隔,下面就是一個例子。可以在這裡查看更多關於資源定義的語法。

  示例 9.2.3:

<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot"
   flex="1">
<template>
<label uri="rdf:*" value="rdf:http://home.Netscape.com/NC-rdf#Name
rdf:http://home.Netscape.com/NC-rdf#URL"/>
</template>
</vbox>

  建立模板(How Templates are Built)

  一旦為元素設置了datasources特性,就表明這個元素將會通過模板來生成。要明確這點,是否生成內容不是由template標 記決定的,而是由atasources特性來決定的。只要設置了這個特性,元素就會自動被添加一個叫做構造器的對象。這個對象的責任就是通過模板來構建內 容。在JavaSciprt中,你可以使用builder屬性來訪問這個構造器對象,但通常你只有在需要手動重新生成內容的時候才需要調用這個對象。

構造器有兩種類型,最常用的是內容構造器(content builder),另外一種是樹型構造器(tree builder),當然只有在構造樹型元素的時候才用的到。

  內容構造器從template元素中讀取內容,並在每行都進行復制。比如在上面的例子中如果有十個書簽,就會構建10個label元素,並都會添加到vbox元素下面。如果你使用DOM函數對樹型結構進行遍歷,你可以找到這些元素,並可以調用它們的屬性。這些元素最終會在界面顯示出來,但是template元素本身是不會顯示的,雖然在DOM中是可以找到template元素的。另外,每個label的id特性將被設置為RDF資源中對應的值。

  內容構造器總是從uri="rdf:*"定義的地方開始操作。如果uri特性所在的元素不是在第一行,那麼之前的元素都值將被建立一次。下面的例子中會建立一個hbox,hbox內會用一組label來填充。

<template>
<hbox>
<label uri="rdf:*" value="rdf:http://home.Netscape.com/NC-rdf#Name"/>
</hbox>
</template>

  如果設置了datasources特性的元素內還有其他內容,但這些內容是在template元素外部的,這些內容也是會被顯示出來的。通過這種方式,你可以把靜態內容和動態內容混合起來顯示。

  樹型構造器與內容構造器不同的是,不會為每行數據都生成DOM元素,取而代之的,它會直接從RDF數據源中按需獲取數據,這是因為樹型組件通常用於 數據量非常大的情況,而為每條數據都建立元素是很耗費資源的,這樣實現當然會更有效率,然而這樣做也有一些限制,就是樹型組件只可以用來顯示文本,還有就 是因為沒有建立任何元素,自然就無法使用CSS屬性對樹型組件設置樣式了。

 樹型構造器只能用於樹型組件。其他的元素只能使用內容構造器。因為向菜單這樣其他的元素不會顯示太多的數據項,所以這也沒有什麼差別。當然你也可以使用內容構造器來生成樹型組件,這樣做的話,每行都會生成一個treeitem元素以及其他相關元素。

  規則(Rules)

  在上面的例子中,你應該注意到第三個按鈕上面只有一堆連字符,這個按鈕應該是書簽列表的分隔符。按照現在的實現方式,RDF數據源把這些分隔符當成 普通的書簽對待。而我們需要做的,是要用一小段空白來作為分隔符,而不是現在的按鈕。這就是說,我們需要建立兩種類型的內容,一種是書簽,一種是分隔符。

  我們可以通過rule元素來實現上面的目標。我們為每一種不同類型的元素定義一條規則。在這個例子中,我們需要分別為書簽和分隔符各定義一條規則。而具體那個規則最終會調用數據源是由規則上的特性來決定的。

  只要找到符合數據的規則後,會馬上使用這個rule元素來顯示數據。這意味著規則的順序是很重要的,兩條規則如果都匹配數據的話,前面的規則優先於後面的規則。

  下面的例子對前面的例子進行擴展,增加了兩條規則:

  示例 9.2.4:

<window
 id="example-window"
 title="Bookmarks List"
 XMLns:html="http://www.w3.org/1999/xHtml"
 XMLns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
 XMLns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1">
<template>
<rule rdf:type="http://home.Netscape.com/NC-rdf#BookmarkSeparator">
<spacer uri="rdf:*" height="16"/>
</rule>
<rule>
<button uri="rdf:*" label="rdf:http://home.Netscape.com/NC-rdf#Name"/>
</rule>
</template>
</vbox>
</window>

XUL教程 - 9.2 - 模板 通過這兩條規則,我們就可以有選擇的通過模板生成內容。在第一條規則中,通過rdf:type特性可以判斷這是一條針對分隔符的規則。第二條規則沒有設置任何特性,也就是可以匹配所有數據。

  rule元素上的所有特性都是用來匹配的。在這個例子中,書簽的數據源提供了rdf:type屬性區分分隔符。在數據源中,如果一條數據是分隔符,那麼就會為rdf:type這個特性設置值,我們就是通過這種方式把分隔符和普通書簽區分開的。你可以使用類似方法區分任意元素。

  在這個例子中,第一條規則對應的那個特定地址專門用來描述分隔符,意思是說分隔符會按照第一條規則來生成一組16像素的空白。普通的書簽項將會忽略 第一條規則,並使用第二條規則生成數據。第二條規則沒有設置任何特性,這意味著可以匹配所有的數據。當然這也是我們想要的,匹配除了分隔符以外的所有數 據。

  你應該已經注意到,因為我們要獲取指定命名空間下的特性(rdf:type),我們需要在window元素上聲明這個命名空間,如果不這麼做,系統將會在XUL命名空間下來尋找這個特性,而這肯定是找不到的,規則也就不會匹配,當然這不是我們想要的。如果你要使用自己建立的命名空間下的特性,也需要在使用前首先聲明這個命名空間。

  如果把第二條規則去掉,你應該可以猜到結果會變成什麼樣子,最後只會顯示一個空白,而不會顯示任何書簽,道理很簡單嘛,因為書簽不匹配所有的規則嘛,呵呵。

  簡單的說,如果rule元素上通過特性定義的規則和數據源中的特性匹配,這個規則就會生效。如果數據源是一個RDF文件,那麼將對應於資源中的description元素。

  但也確實存在一些例外情況,你不可以基於id特性來匹配,rdf:property和rdf:instanceOf也不可以。因為你只能使用自己命名空間下那些自己定義的特性,但這個限制可能沒有什麼實際意義。

  需要注意的是,一個沒有定制任何規則的模板(比如第一個例子)和只定義了一條規則但沒限制任何特性的模板,從功能上來說是一模一樣的。




XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved