AMP 的進階互動功能

Accelerated Mobile Pages (AMP) 是一項開放原始碼計劃,有助製作快速、精美且成效卓越的網站和廣告。

如果您剛開始使用 AMP,建議您瀏覽下列資源快速介紹:

動機

AMP 支援使用使用者介面元件 (例如圖片輪轉介面燈箱) 來豐富動態內容。AMP 也支援透過 AMP 動作,讓元件在另一個元件中觸發動作。

但是:

  • 要自訂 AMP 元件嗎?
  • 例如,顯示自訂標籤,顯示目前輪轉介面中的投影片以及投影片總數。
  • 要新增有狀態的行為嗎?
  • 舉例來說,如果使用者選擇的產品數量超過目前供應情形,則停用「加入購物車」按鈕。

在過去,由於使用者介面元件缺少穩固的通訊管道,而且無法使用可變動的共用狀態,因此在 AMP 中實作這類功能並不容易。為瞭解決這些用途,我們在 AMP 中打造了強大的新元件。

<amp-bind>

<amp-bind> 是新的 AMP 元件,可透過資料繫結和 JS 式運算式提供自訂互動功能。本程式碼研究室將逐步引導您使用 <amp-bind> 建立內容豐富的自訂網頁。

建構目標

在這個程式碼研究室中,您將建立電子商務產品詳細資料頁面:

  • 使用 AMP HTML 和 AMP 元件建立網頁,為使用者提供快速又豐富的使用者體驗
  • 使用<amp-bind>來新增跨元素互動
  • 運用 <amp-state> 視需要擷取其他產品資料

您將會瞭解的內容

  • 如何使用 <amp-bind> 建立資料繫結和運算式,打造精彩的互動式 AMP 網頁!

軟硬體需求

  • 您選擇的瀏覽器
  • 您選擇的文字編輯器
  • Node.js 和 NPM
  • 範例程式碼
  • HTML、CSS 和 JavaScript 基礎知識

下載程式碼

首先,取得 ZIP 檔案的下載程式碼:

下載

或透過 git:

git clone https://github.com/googlecodelabs/advanced-interactivity-in-amp.git

安裝依附元件

視需要解壓縮封存檔案,並瀏覽至該目錄。執行 npm install 以安裝依附元件。

cd advanced-interactivity-in-amp-codelab
npm install

執行開發伺服器

使用 node.js 啟動開發伺服器:

node app.js

在網路瀏覽器中瀏覽至 http://localhost:3000,即可查看 AMP 網頁執行成功!

AMP 公式更新

AMP 網頁是 HTML 網頁,其中有一些限制的穩定性。AMP 網頁含有一些特殊標記,可視為 Google 搜尋中的 AMP 網頁。

大腦 AMP 網頁看起來如下:

<!doctype html>
<html amp>
 <head>
   <meta charset="utf-8">
   <link rel="canonical" href="hello-world.html">
   <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
   <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
   <script async src="https://cdn.ampproject.org/v0.js"></script>
 </head>
 <body>Hello World!</body>
</html>

AMP 元件

我們的範例程式碼 (static/index.html) 以巴基斯坦的 AMP 網頁為基礎,呈現出網頁內容 (圖片、文字等) 以及一些 AMP 元件

<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.1.js"></script>
<script async custom-element="amp-form" src="https://cdn.ampproject.org/v0/amp-form-0.1.js"></script>
<script async custom-element="amp-selector" src="https://cdn.ampproject.org/v0/amp-selector-0.1.js"></script>

AMP 元件提供更多功能和 UI 元件,為 AMP 網頁增添豐富的互動功能。範例程式碼使用以下 AMP 元件:

  • <amp-carousel>
  • 顯示多項產品視圖的圖片圖片輪轉介面。
  • <amp-mustache>
  • 用於轉譯 amp 表單伺服器回應的範本系統。
  • <amp-form>
  • 為 AMP 網頁所需的 <form> 元素新增特殊功能。
  • <amp-selector>
  • 提供語意化方法,可選取一組元素中的一或多個元素。可做為 amp 格式的輸入來源。

基本互動功能

範例程式碼提供了一些基本互動方式:

  • 圖片輪轉介面 (<amp-carousel>) 會顯示多項產品檢視畫面。
  • 如想將產品加入使用者的購物車 (透過 <amp-form>),請輕觸頁面底部的 [新增至購物車] 按鈕。

請試著滑動圖片輪轉介面,然後輕觸 [加入購物車] 按鈕。

改善體驗

範例程式碼為使用者體驗提供極佳體驗。有幾種方法可以改善這個問題:

  • 新增顯示目前投影片和投影片總數的指標。
  • 當使用者選取其他襯衫顏色時,可以將圖片輪轉介面改為所選圖片的襯衫。

在導入 <amp-bind> 元件之前,您無法新增這類功能。讓我們來實際體驗 <amp-bind> 功能,並將這些新功能加入我們的程式碼範例中!

安裝<amp-bind>擴充功能

<amp-bind> 是新的 AMP 元件,可透過資料繫結和 JS 式運算式提供自訂互動功能。如要使用 <amp-bind>,您必須在網頁中安裝。

開啟 static/index.html 檔案,並將下列指令碼加到 AMP 元件清單中 (位於網頁的 <head> 部分):

<script async custom-element="amp-bind"
    src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>

新增投影片指標

<amp-bind> 的運作方式是將元素屬性繫結至自訂運算式。這些運算式可以參照「狀態」(JSON 資料可變動)。我們可以透過包含 <amp-bind><amp-state> 元件來初始化此狀態。

我們來初始化狀態變數,以追蹤圖片輪轉介面中目前顯示的投影片的索引。開啟 static/index.html,然後將以下內容加到網頁的 <body> 頂端 (在標頭之前):

<amp-state id="selected">
  <script type="application/json">
    {
      "slide": 0
    }
  </script>
</amp-state>

<amp-state> 元素的資料可透過相關聯的 ID 存取。舉例來說,我們可以使用下列運算式片段來參照這個變數:

selected.slide // Evaluates to 0.

然後,當使用者在輪轉介面上變更投影片時,只要新增「on-amp-carousel>」元素,即可更新這個變數。

<amp-carousel type="slides" layout="fixed-height" height=250 id="carousel"
    on="slideChange:AMP.setState({selected: {slide: event.index}})">

現在,只要 <amp-carousel> 的投影片變更,系統將使用以下引數呼叫 AMP.setState 動作:

{
  selected: {
    slide: event.index
  }
}

event.index 運算式會評估新的投影片索引,而 AMP.setState() 動作會將此物件常值合併為目前狀態。這會將目前的值 selected.slide 替換為 event.index 的值。

接著,我們來利用這個狀態變數來追蹤目前顯示的投影片,並建立投影片指標。找到投影片指標元素 (尋找 <!-- TODO: "Add a slide indicator" -->) 並將下列繫結新增至子項:

<!-- TODO: "Add a slide indicator" -->
<p class="dots">
  <!-- The <span> element corresponding to the current displayed slide
       will have the 'current' CSS class. -->
  <span [class]="selected.slide == 0 ? 'current' : ''" class="current"></span>
  <span [class]="selected.slide == 1 ? 'current' : ''"></span>
  <span [class]="selected.slide == 2 ? 'current' : ''"></span>
</p>

[class] 是會變更 class 屬性的繫結,可讓您利用這項屬性為任何元素新增或移除 CSS 類別。

現在,請重新整理頁面,然後試試看吧!只要變更輪轉介面上的投影片,就能:

  1. 觸發 slideChange 事件...
  2. 哪些操作會呼叫 AMP.setState...
  3. 這會更新狀態變數 selected.slide...
  4. 這會更新指標 <span> 元素的 [class] 繫結!

太好了!現在,我們加入了投影片投影片指標。

我們可以在更改所選顏色時看到不同襯衫顏色的圖片。透過 amp-bind,我們可以對 <amp-carousel> 中的 <amp-img> 元素繫結 [src],以執行此動作。

不過,我們需要先使用各個 T 恤的圖片來源網址初始化狀態資料。讓我們使用新的 <amp-state> 元素來執行這個動作:

<!-- Available shirts. Maps unique string identifier to color and image URL string. -->
<amp-state id="shirts">
  <script type="application/json">
    {
      "1001": {
        "color": "black",
        "image": "./shirts/black.jpg"
      },
      "1002": {
        "color": "blue",
        "image": "./shirts/blue.jpg"
      },
      "1010": {
        "color": "brown",
        "image": "./shirts/brown.jpg"
      },
      "1014": {
        "color": "dark green",
        "image": "./shirts/dark-green.jpg"
      },
      "1015": {
        "color": "gray",
        "image": "./shirts/gray.jpg"
      },
      "1016": {
        "color": "light gray",
        "image": "./shirts/light-gray.jpg"
      },
      "1021": {
        "color": "navy",
        "image": "./shirts/navy.jpg"
      },
      "1030": {
        "color": "wine",
        "image": "./shirts/wine.jpg"
      }
    }
  </script>
</amp-state>

這個 <amp-state> 元素包含 JSON 物件,能夠將襯衫識別碼 (例如 SKU) 對應至對應的襯衫顏色和圖片網址。JSON 陣列也可在這裡運作,但使用物件能讓我們執行一些很快就會看到的操作。

現在,我們可以透過襯衫 ID 存取圖片網址。舉例來說,shirts['10014'].color 會評估為 "dark green",而 shirts['10030'].image 會傳回「wine」襯衫顏色的圖片網址。

如果我們加入了另一個可追蹤所選 SKU 的州變數,我們可以將運算式繫結至 <amp-img> 元素,以在所選 SKU 變更時更新其 src 屬性。在現有 amp-state#selected 元素的 JSON 中新增 sku 金鑰:

<amp-state id="selected">
  <script type="application/json">
    {
      "slide": 0,
      "sku": "1001"
    }
  </script>
</amp-state>

將「加入」動作加入 <amp-selector>,以便在選取新顏色時更新 selected.sku 變數:

<amp-selector name="color" 
    on="select:AMP.setState({selected: {sku: event.targetOption}})">

然後,為 <amp-carousel> 中的 <amp-img> 元素新增繫結 (尋找 <!-- TODO: "Changing images in amp-carousel-->"):

<!-- Update the `src` of each <amp-img> when the `selected.sku` variable changes. -->
<amp-img width=200 height=250 src="./shirts/black.jpg"
    [src]="shirts[selected.sku].image"></amp-img>
<amp-img width=300 height=375 src="./shirts/black.jpg"
    [src]="shirts[selected.sku].image"></amp-img>
<amp-img width=400 height=500 src="./shirts/black.jpg"
    [src]="shirts[selected.sku].image"></amp-img>

注意:實際上,輪轉介面中的每個圖片都可能有不同的 src。只要將單一圖片換成圖片陣列即可。為求簡單,這個程式碼研究室使用單一圖片,不同尺寸。

現在,請重新整理頁面,並為襯衫選取其他顏色。系統隨即更新輪轉介面,以顯示所選顏色的襯衫。

如果可繫結的資料過大,或是無法於載入網頁時擷取,該怎麼辦?或者,如果每個 SKU 的價格都需要較長時間,該怎麼辦?針對非檢視項目 SKU 查詢價格是浪費的做法。

正在擷取襯衫的可用尺寸

讓我們能擷取遠端資料,在程式碼研究室樣本中查詢 SKU 價格。位於 app.js 的 Express.js 開發伺服器已有端點 /shirts/sizes?shirt=<sku>,這個端點會按襯衫 SKU 傳回每個尺寸的可用尺寸與價格。這個模型會以人工延遲時間 (一秒) 傳送回應,模擬網路延遲時間。

要求

回應

GET /shirts/sizesAndPrices?sku=1001

{"1001: {"sizes": {"XS": 8.99, "S" 9.99}}}

<amp-state> 元素中的 JSON 資料類似,從這些擷取作業傳回的遠端資料會合併到元素,並放在元素的 id 屬性底下。例如,可從運算式存取上述範例回應傳回的資料:

運算式

結果

shirts['1001'].sizes['XS']

8.99

現在,讓我們把此範例套用到我們的電子商務範例。首先,選取新 SKU 時,系統會擷取這個襯衫資料。將 [src] 繫結新增至我們的 amp-state#shirts 元素:

<!-- When `selected.sku` changes, update the `src` attribute and fetch
     JSON at the new URL. Then, merge that data under `id` ("shirts"). -->
<amp-state id="shirts" [src]="'/shirts/sizesAndPrices?sku=' + selected.sku">

接著,就讓特定 SKU 清楚標示無法使用的大小。"unavailable" CSS 類別透過元素新增對角線。我們可以對 amp-selector[name="size"] 中的對應大小沒有對應的對角線:

<amp-selector name="size">
  <table>
    <tr>
      <!-- If 'XS' size is available for selected SKU, return empty string.
           Otherwise, return 'unavailable'. -->
      <td [class]="shirts[selected.sku].sizes['XS'] ? '' : 'unavailable'">
        <div option="XS">XS</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['S'] ? '' : 'unavailable'">
        <div option="S">S</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['M'] ? '' : 'unavailable'">
        <div option="M">M</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['L'] ? '' : 'unavailable'">
        <div option="L">L</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['XL'] ? '' : 'unavailable'">
        <div option="XL">XL</div>
      </td>
    </tr>
  </table>
</amp-selector>

現在重新載入頁面並再試一次。選取新的 SKU (襯衫顏色) 會導致無法完整檢視尺寸不足的延遲情形 (經過一小段時間後)。

不過,這其實是個小問題:那是黑色襯衫呢,預設顏色為何?我們必須將黑色襯衫尺寸和價格資料新增到「amp-state#shirts」...

<amp-state id="shirts" [src]="'/shirts/sizesAndPrices?sku=' + selected.sku">
  <script type="application/json">
    {
      "1001": {
        "color": "black",
        "image": "./shirts/black.jpg",
        "sizes": {
          "XS": 8.99,
          "S": 9.99
        }
      },
<!-- ... -->

...以及更新相關元素的預設狀態。

<amp-selector name="size">
  <table>
    <tr>
      <!-- If 'XS' size is available for selected SKU, return empty string.
           Otherwise, return 'unavailable'. -->
      <td [class]="shirts[selected.sku].sizes['XS'] ? '' : 'unavailable'">
        <div option="XS">XS</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['S'] ? '' : 'unavailable'">
        <div option="S">S</div>
      </td>
      <!-- Add the ‘unavailable' class to the next three <td> elements
           to be consistent with the available sizes of the default SKU. -->
      <td class="unavailable" 
          [class]="shirts[selected.sku].sizes['M'] ? '' : 'unavailable'">
        <div option="M">M</div>
      </td>
      <td class="unavailable" 
          [class]="shirts[selected.sku].sizes['L'] ? '' : 'unavailable'">
        <div option="L">L</div>
      </td>
      <td class="unavailable" 
          [class]="shirts[selected.sku].sizes['XL'] ? '' : 'unavailable'">
        <div option="XL">XL</div>
      </td>
    </tr>
  </table>
</amp-selector>

可變動的襯衫價格

正確顯示可用尺寸後,請確認價格也正確無誤。

我們的 AMPPAREL 商店有特別的特點,就是 T 恤價格同時適用於顏色和尺寸。這表示我們需要一個新變數來追蹤使用者選取的大小。將新動作新增至大小 <amp-selector> 元素:

<!-- When an element is selected, set the `selectedSize` variable to the
     value of the "option" attribute of the selected element.  -->
<amp-selector name="size" 
    on="select:AMP.setState({selectedSize: event.targetOption})">

請注意,我們不會透過 amp-state#selected 元素初始化 selectedSize 的值。因為我們刻意沒有提供預設選取的尺寸,而想要強制使用者選擇大小。

新增新的 <span> 元素,納入價格標籤,並將預設文字變更為「---」符號 (因為沒有預設大小)。

<h6>PRICE :
  <!-- Display the price of the selected shirt in the selected size if available.
       Otherwise, display the placeholder text '---'. -->
  <span [text]="shirts[selected.sku].sizes[selectedSize] || '---'">---</span>
</h6>

此外,我們也有正確的價格!試試看。

有條件啟用的按鈕

就快完成了!現在,當所選大小無法使用時,請停用「加入購物車」按鈕:

<!-- Disable the "ADD TO CART" button when:
     1. There is no selected size, OR
     2. The available sizes for the selected SKU haven't been fetched yet
-->
<input type="submit" value="ADD TO CART" disabled
    class="mdl-button mdl-button--raised mdl-button--accent"
    [disabled]="!selectedSize || !shirts[selected.sku].sizes[selectedSize]">

我們有互動式電子商務產品詳細資料頁面,其中包含每個 SKU 的變動大小和價格,可從遠端 JSON 端點擷取以隨選取得。

如果遇到問題,請參閱 static/final.html 以取得完整解決方案。

希望這個程式碼研究室可展現您運用 <amp-bind> 建立互動式 AMP 網頁的強大功能和彈性。如需更多資訊,請參閱 <amp-bind> 說明文件

我們十分願意提供寶貴意見,請將您的功能要求、建議或錯誤報告傳送給我們。如果您想要對實際的使用者測試 <amp-bind>,建議您提出來源試用

我們非常期待能在 <amp-bind> 上推出這項工具,並看看大家可以使用哪些功能建構而成!