本文章是由機器翻譯。

新型應用程式

掌控以 JavaScript 建置的 Windows 市集應用程式中的控制項和設定

Rachel Appel

良好的使用者體驗可將資料自然而然地以直觀的方式展現給使用者,無論什麼外觀尺寸都是如此。 展現資料和內容時,需要使用經過更新的 API、控制項和工具創造新式體驗。 在 Windows 應用商店應用中,所需的代碼量以及控制項的複雜程度取決於創建何種應用程式、它是生產力應用程式、遊戲、社交應用程式還是財務應用程式。 任何用 JavaScript 構建 Windows 應用商店應用的開發人員均可輕鬆掌握 Windows JavaScript 庫 (WinJS) 控制項,接下來我將談論這些控制項。

Windows 8 引入了新的 UI 範例和新的 UI 控制項

Windows 應用商店應用的外觀和行為與在 Windows 早期版本中運行的程式大相徑庭。 Windows 中已進行了重大革新,啟動後顯示新的「開始」頁面,上面全都是動態磁貼,作為您與應用程式的第一層交互。 其他的明顯變化是 Windows 應用商店應用以全屏模式或對齊視圖運行,使內容在正面居中,同時命令和功能表停留在視線之外,直到使用者請求它們時才出現。

曾經無處不在的最小化、最大化和關閉按鈕等 Windows UI 元素在 Windows 應用商店應用中不復存在,因為觸摸輕掃和滑鼠移動已使這些控制項失去用處。 若要關閉應用程式,只需從螢幕頂部到底部輕掃或下移滑鼠。 甚至功能表都不再固定出現在每個螢幕的頂部。 在 Windows 應用商店應用中,功能表保持隱藏,直至觸摸輕掃或滑鼠手勢從 AppBar 底部展現這些功能表,如圖 1所示,其中使用一個小型倒計時器應用程式作為示例。


圖 1:應用程式底部的 AppBar

如您可在圖 1中所見,功能表在外側,命令元素先是圖形,後是一些文字,而非傳統的先是文字功能表,偶爾配有圖形。 這些元素也完全符合手指大小。 如果除了只是底部還需要更多空間容納選項,則可放置巡覽列,即頁面頂部的 AppBar。

在傳統 Windows 功能表中導航有時非常麻煩。 我們都討厭級聯功能表深達 13 級的程式,以至於忘記最初所尋找的內容。 在 Windows 應用商店應用中,導航本身與內容交織在一起,因為對 ListView 項的觸摸和滑鼠手勢將調用其他頁面。 手指開合手勢與 Ctrl 鍵+滑鼠滾輪可啟動語義式縮放 (bit.ly/16IDtdi),即 Windows 應用商店應用中的控制和導航範例。 Semantic­Zoom 是整個 WinJS 控制項清單 (bit.ly/w1jLM5) 的一部分。

使用 HTML 和 WinJS 控制項

Windows 應用商店應用中主要有兩種使用 JavaScript 的控制項:標準 HTML 元素和 WinJS 控制項。 WinJS 控制項是 HTML 與擴展 HTML 元素外觀或行為的預生成 JavaScript 相結合。 由於這些控制項是 HTML,因此可用 CSS 設置 WinJS 控制項的樣式。 圖 2 是一個基本 WinJS 控制項的示例 WinJS DatePicker,它是由表示日、月和年的多個 DropDown 控制群組成的一個控制項,顯示此代碼的預設輸出:

<span id="eventDate" data-win-control="WinJS.UI.DatePicker" />


圖 2:WinJS DatePicker 控制項

當然,圖 2 中的 DatePicker 控制項在預設 WinJS 樣式之外沒有其他樣式,但可通過重寫 .win-datepicker-date、.win-datepicker-month 和 .win-datepicker-year WinJS CSS 選取器,改變這種情況。使用 .win-datepicker 設置整個控制項的樣式。

DatePicker(或任何 WinJS 控制項)之所以正常工作是因為 HTML5 data-* 特性,稱為 data-win-control。data-win-control 特性表示 WinJS 將在適當位置呈現的控制項類型,因此當您將 data-­win-control 特性的值設置為 WinJS.UI.DatePicker 時,該控制項呈現圖 2 中的下拉清單。通過 data-win-options 特性,可設置控制項的其他屬性。例如,可對 DatePicker 設置預設顯示日期以及最小和最大日期範圍的 data-win-options。雖然它名叫 DatePicker,但可更改該控制項,讓其改為捕獲時間,例如小時、分鐘和秒。

由於 WinJS 生成並呈現最終控制項輸出,因此設計時 HTML 與運行時 HTML 看起來頗有區別。圖 3 演示 WinJS 在運行時注入到 host 元素的 HTML。可從 DOM 資源管理器(「調試」|「Windows」|「DOM 資源管理器」)中查看它。

圖 3:DatePicker 呈現三個 DropDown,其中填寫了日期/月/年的選項

<span class="win-datepicker" id="eventDate" role="group"
   lang="en-US" dir="ltr" data-win-control="WinJS.UI.DatePicker">
<select tabindex="0" class="win-datepicker-month win-order0"
   aria-label="Select Month">
<option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<!-- more <options> that show the other months -->
</select>
<select tabindex="0" class="win-datepicker-date win-order1"
   aria-label="Select Day">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<!-- more <options> that  show day numbers -->
</select>
<select tabindex="0" class="win-datepicker-year win-order2"
   aria-label="Select Year">
<option value="1913">1913</option>
<option value="1914">1914</option>
<option value="1915">1915</option>
<option value="1916">1916</option>
<!—more <options> that show years -->
<option value="2112">2112</option>
<option value="2113">2113</option>
</select>

支援 DatePicker 等 WinJS 控制項的代碼位於 <ProjectRoot>\References\Windows Library for JavaScript 1.0\js\ui.js 檔內,同某些核心 WinJS 相關元件在一起。 注意,這就是在 Windows 應用商店應用頁的 <head> 元素中需要的同一個 <script> 引用,即:

<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

修改這些檔需自擔風險,因為這些檔由核心 WinJS 代碼組成。

在運行時可通過一個名為 winControl 的屬性訪問包括 DatePicker 在內的任何 WinJS 控制項。 WinJS 在運行時向 winControl 屬性添加 WinJS 控制項類型特有的子屬性。 舉例來說,ListView 包含其項清單,也可向 WinJS.UI.Ratings 控制項查詢使用者選擇的評級。 可按如下方式訪問元素的 winControl:

var control = document.getElementById("WinJSElementId").winControl

Button、CheckBox、RadioButton、DropDown、TextBox 等控制項的作用均與其在傳統的普通 HTML 頁中相同;但是,WinJS.UI 命名空間充滿了用於許多複雜方案的 UI 控制項,包括重要的清單控制項。

清單和網格控制項

許多應用程式需要在網格或清單中展示資料,因此當然有一個名為 ListView 的控制項用於這些方案,該控制項可將自身呈現為網格或清單,裡面進行了全面的分組,並且項大小可變。 ListView 不僅非常靈活,還可自動縮放以適合螢幕以及根據解析度和設備顯示幕大小將清單項放置在大小可變的行列中等,因此非常適合新式 Windows 體驗。

雖然大多數其他 WinJS 控制項均獨立,但 ListView 與作為範本的對應 HTML 協同工作。 這意味著需要同時設置範本 HTML 和控制項容器本身,如圖 4 所示。 注意,範本的 data-win-control 和 ListView 的 data-win-options 特性包含將 ListView 與其範本連結在一起的設置。

圖 4:創建 WinJS ListView 所需的 HTML

<div id="maincontent">     
  <div id="listViewTemplate"
         data-win-control="WinJS.Binding.Template" >
    <div data-win-bind="style.background: color" class="win-item">
      <h1 data-win-bind=" innerText: daysToGo"></h1>
      <h2 class="subtitle" 
             data-win-bind="innerText: eventTitle"></h2><br />
      <h2 class="subtitle-bottom" 
             data-win-bind=" innerText: eventDate"></h2>
    </div>
  </div>
  <div id="listView" data-win-control="WinJS.UI.ListView"
    class="win-listview"
    data-win-options=
    "{ itemDataSource: Data.items.dataSource,
    itemTemplate: select('#listViewTemplate'),
    selectionMode: 'single'}">
  </div>
</div>

圖 4 中含有兩個 <div> 元素,一個表示範本,ID 為 listViewTemplate,另一個表示 ListView 自身,名為 listView。 listViewTemplate 元素中含有子項目,後者表示清單或網格中每項的不同欄位,如 eventTitle 或 eventDate。 查看圖 4 中的 ListView 發現 itemDataSource 屬性被設置為 Data.items.dataSource,表示 Data 是一個命名空間,而 items 是一個填充了資料的 WinJS.Binding.List 物件。 由於 JavaScript 使用鬆散類型的資料,因為只需向 List 建構函式填入一個物件陣列,然後它即可綁定到 ListView 控制項,類似于下面這段代碼:

var items = [
  { eventTitle: "Rachel's Birthday", 
    eventDate: new Date(2014, 1, 13) },
  { eventTitle: "Rachel's BFF's Birthday", 
    eventDate: new Date(2013, 5, 29) }
];
var list = new WinJS.UI.list(events);

此外,可使用 push 方法將項推送到 List 物件上,而非將一個陣列傳遞給 List 的建構函式。管理 ListView 中資料的最佳方法是通過 AppBar 控制項公開相關選項(添加、刪除等)。

AppBars and Commands

內容在版式上方是一個重要的 Microsoft 設計原則。AppBar 是此設計原則的一個組成部分,因為它們保持在視線之外,等待在需要它們時展示其選項。在代碼中,AppBar 就是一個 <div>,其中含有一個或多個 <button> 元素(稱為「應用欄命令」),其 data-win-control 特性設置為 WinJS.UI.AppBarCommand。個別 AppBar 命令之間有區別的功能在於 data-win-options,正如您可能猜到的那樣。

檢查每個 AppBar 命令在圖 5 中的 data-win-options 可發現每個命令的 id、label、icon 和 section。可將 AppBar 按鈕分配給 AppBar 的 global 部分(顯示在應用程式螢幕的右下角),或將 section 選項設置為「selection」(以顯示在左下角)。將 AppBar 命令的 section 選項設置為「selection」使這些命令與上下文相關,在使用者通過輕掃或按一下而選擇 ListView 中的某項時,可使用這些命令。

圖 5:生成 AppBar

<!-- HTML -->
<div id="appbar" class="win-appbar" 
       data-win-control="WinJS.UI.AppBar">
<button data-win-control="WinJS.UI.AppBarCommand"
   data-win-options="{id:'deleteButton', 
    label:'Delete',
    icon:'delete', section:'selection'}" 
    type="button"></button>
<button data-win-control="WinJS.UI.AppBarCommand"
   data-win-options="{id:'addButton', 
    label:'Add', icon:'add',
    section:'global'}" 
    type="button"></button>
<button 
   data-win-control="WinJS.UI.AppBarCommand"
   data-win-options="{id:'refreshButton',
   label:'Refresh',
   icon:'refresh', 
   section:'global'}" 
   type="button"></button>
</div>
// JavaScript
document.getElementById("addButton").addEventListener(
  "click", this.addButtonClick);
document.getElementById("deleteButton").addEventListener(
  "click", this.deleteButtonClick);
document.getElementById("refreshButton").addEventListener(
  "click", this.refreshButtonClick);

在 HTML 頁相關的 JavaScript 檔中,向 AppBar 按鈕附加事件攔截器,如同對任何其他 HTML 元素所做的一樣。 不需要出現 AppBar 自身的攔截器,因為它根據使用者命令自動顯示和隱藏自身,但也可以程式設計方式調用它。 圖 5 中的示例展示一個完整的 AppBar,其中含有添加、刪除和刷新資料的按鈕。

在方案需要時,可編寫代碼以顯示、隱藏、啟用和禁用 AppBar 按鈕。

浮出控制項

由於觸控式螢幕是頭等大事,因此可能已注意到當 UI 元素和對話方塊顯示其自身時,只需點擊或按一下螢幕上除對話方塊自身之外的任何部分,即可輕鬆地使其消失。 這種隱含關閉對話方塊的理念稱為「輕量解除」,並且它是 Windows 8 中 MessageDialog 和 PopupMenu 的預設行為,因為對於使用者而言,輕量解除遠比處理關閉按鈕容易得多。

正如以前的控制項一樣,浮出控制項使用 data-­win-control 特性指定它實際上是 WinJS.UI.Flyout 控制項。 浮出控制項 <div> 元素的子項目在浮出控制項內呈現。 例如,可在浮出控制項中放置 HTML 表單,以使使用者可填寫即將召開的活動的標題和日期,如圖 6 中的代碼所示,產生圖 7 中的內容。

圖 6:用 WinJS 控制項收集資訊的輕量解除浮出控制項

<!-- HTML  -->
<div id="eventFlyoutPanel" data-win-control="WinJS.UI.Flyout">
  <table width="100%" height="100%">    
    <tr><td>Event Title:</td><td><input type="text"
 id="eventTitle"/></td></tr>
    <tr><td>Event Date:</td><td id="eventDate"
       data-win-control="WinJS.UI.DatePicker"></td></tr>        
    <tr><td> </td><td align="right">
    <input type="button" id="confirmButton" value="Submit" /></td></tr>
    </table>
</div>
// JavaScript
addButtonClick: function () {
  document.getElementById("eventFlyoutPanel").winControl.show(
  "addButton", "top");
}


圖 7:收集資訊的浮出控制項

注意,圖 7 中的浮出控制項就是一個 HTML 表單。當使用者點擊或按一下「Add」(添加)AppBar 命令時,將顯示該浮出控制項,如圖 6 中的 addButtonClick 函數指示的那樣。浮出控制項在螢幕上顯示的位置與其他控制項有關,因此當調用 winControl.show 方法時,即傳遞控制項定位元素的名稱以及在何處放置控制項,即定位控制項的頂邊還是底邊。

使用者從浮出控制項中點擊或按一下任何地方即可離開以使其消失,因為它是輕量接觸控制項。您將注意到 Windows 應用商店應用中明顯缺少模態對話方塊,而這正是 Microsoft 設計哲學的一部分。設計圈的人對模態對話方塊感到不悅確有理由 — 任何打擾使用者或阻止其自由移動的情況均被視為不好的設計。

另一種浮出控制項為 SettingsFlyout,它與 Windows 早期版本中的應用程式管理使用者首選設置的方式大相徑庭。

應用程式設定

Windows 使用者對典型的「工具」|「選項」或「説明」|「關於」功能表選項都不陌生,這些選項將啟動充滿錯綜複雜的設置的對話方塊。幸運的是,在 Windows 應用商店應用中取代這些對話方塊的功能對於使用者更加直觀。設置和關於頁面均顯示為較高的垂直浮出控制項,當使用者從 Windows 超級按鈕中選擇「設置」圖示時調用這些控制項 (bit.ly/146cniM)。

「設置」對於 Windows 應用商店應用均有效。當使用者調用「設置」超級按鈕時,無論運行的是什麼應用程式,均在右側顯示同樣的 SettingsFlyout。隱私權原則、使用者首選設置、説明等內容的連結歸入 SettingsFlyout。創建隱私或選項頁面的連結只需在通常位於 /js/default.js 中的 app.onactivated 事件中編寫幾行代碼即可:

// In default.js, app.onactivated

WinJS.Application.onsettings = function (e) {

  e.detail.applicationcommands =
   { "privacypolicy": { title: "Privacy Policy",
 href: "privacy.html" } };

    WinJS.UI.SettingsFlyout.populateSettings(e);

};

當使用者點擊或按一下某個「設置」連結後,即顯示其對應的浮出控制項。 圖 8 包含 SettingsFlyout 的 HTML,其中含有隱私權原則資訊(在 Windows 應用商店進行發佈時隱私權原則必須簡潔明瞭)。

圖 8:SettingsFlyout 的 HTML(包含隱私權原則資訊)

<div id="settingsFlyout" 
  data-win-control="WinJS.UI.SettingsFlyout"
  data-win-options="{settingsCommandId:'privacypolicy', width:'narrow'}">
  <div class="win-header" style="background-color:#312e2e">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
       class="win-backbutton"></button>
    <div class="win-label">Privacy Policy</div>
  </div>
  <div class="win-content">
    <div class="win-settings-section">
      <p>This application does not collect any personal information.</p>
      <p>Internet access is only used to retrieve data from the web,<div id="settingsFlyout" 
  data-win-control="WinJS.UI.SettingsFlyout"
  data-win-options="{settingsCommandId:'privacypolicy', width:'narrow'}">
  <div class="win-header" style="background-color:#312e2e">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
       class="win-backbutton"></button>
    <div class="win-label">Privacy Policy</div>
  </div>
  <div class="win-content">
    <div class="win-settings-section">
      <p>This application does not collect any personal information.</p>
      <p>Internet access is only used to retrieve data from the web,
         or to allow you to contact the developer:</p>
          <p>
            <a href="mailto:rachel@rachelappel.com">Email Rachel Appel </a>
 <br />
            <a href="http://rachelappel.com/privacy-policy"
             target="_blank">View privacy statement online</a>
          </p>
      </div>
  </div>
</div>

         or to allow you to contact the developer:</p>
          <p>
            <a href="mailto:rachel@rachelappel.com">Email Rachel Appel </a>
 <br />
            <a href="http://rachelappel.com/privacy-policy"
             target="_blank">View privacy statement online</a>
          </p>
      </div>
  </div>
</div>

不要忘記使隱私權原則設置檔的名稱與用於註冊浮出控制項的 href 參數相同(見圖 8)。

在「設置」中不僅可放置隱私權原則。 SettingsFlyout 可包含任何有效的 HTML,並且通常是 ToggleSwitche、CheckBox 和 DropDown 以及函數的宿主,正如「工具」|「選項」對話方塊現在這樣。 但是,正如前述內容,SettingsFlyout 是輕量解除控制項,因此只需在其他地方點擊一下即可使其消失,剛好與模態對話方塊相反。 Windows 應用商店應用開發中另一個簡單的新範例是 SemanticZoom 控制項,這是一個方便的導航説明器。

語義式縮放

某些應用程式需要處理大量資料。 在這些應用程式中導航可能比較困難,尤其是在其處理大量資料時。 而這正是語義式縮放大展身手之處。 通過語義式縮放,可表達兩種模式的資料視覺化:放大和縮小。 預設是放大模式,顯示所有資料,而使用者必須平移或滾動資料。 縮小模式通常形成資料的聚合表現形式,使使用者可輕鬆導航到某個資料區域,然後放大到某個具體資料項目。

SemanticZoom 是三個控制項一組:宿主控制項和兩個縮放控制項,如圖 9 所示。 子控制項必須實現 IZoomable 才能參與語義式縮放,因此對於 WinJS 應用程式,只有 ListView 可發揮作用。

圖 9:SemanticZoom 控制項的代碼

<div id="semanticZoomDiv" data-win-control="WinJS.UI.SemanticZoom">            
  <!-- The zoomed-in view.
-->   
  <div id="zoomedInListView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{ itemDataSource:
      myData.groupedItemsList.dataSource,
     itemTemplate: select('#mediumListIconTextTemplate'),
     groupHeaderTemplate: select('#headerTemplate'),
     groupDataSource: myData.groupedItemsList.groups.dataSource,
	 selectionMode: 'none',
	 tapBehavior: 'none',
	 swipeBehavior: 'none' }">  </div>
  <!-- The zoomed-out view.
-->
  <div id="zoomedOutListView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{ itemDataSource:
     myData.groupedItemsList.groups.dataSource, itemTemplate:
     select('#semanticZoomTemplate'), selectionMode: 'none',
     tapBehavior: 'invoke', swipeBehavior: 'none' }">
  </div>
</div>

正如您可見,語義式縮放只是在兩個 ListView 之間切換,這樣使其成為使用者轉移的良好替代模式 — 開發人員也易於實現。

更多控制項

還有更多控制項,如進度條、FlipView、彈出功能表、MessageDialog 和 Ratings,所有這些都是 Windows 新體驗的一部分,但這裡沒有篇幅再談論所有這些控制項。HTML5 和 ECMAScript 5 (ES5) 等開放標準是 WinJS 所有功能的基礎,因此從 Web 裝訂到定位和輸入再到 HTML5 音訊和視頻,所有這些都作為 Windows 應用商店應用開發平臺的一部分運行良好。

Rachel Appel* 是一名顧問、作家、導師和前 Microsoft 員工,在 IT 行業有 20 多年的經驗。她常在 Visual Studio Live!、DevConnections、MIX 等頂級行業大會上發言。她的專業是開發側重于 Microsoft 系列開發技術和開放式 Web 並且符合業務和技術需要的解決方案。有關 Appel 的詳細資訊,請訪問她的網站 rachelappel.com。*

衷心感謝以下技術專家對本文的審閱:Keith Boyd (Microsoft)