AMP
  • 網站

收藏按鈕

簡介

此範例示範如何在 AMP 中實作收藏/讚/書籤按鈕。我們的實作方式

  • 會根據使用者是否已喜歡某項目來顯示正確的圖示。這在 AMP 從 AMP 快取或原始來源提供時皆可運作。
  • 在非同步載入目前狀態時顯示預留位置。
  • 若請求失敗(例如使用者離線時),則會回復至原始狀態並顯示錯誤訊息。

設定

我們使用 `amp-list` 元件來動態呈現收藏按鈕的初始狀態。

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

`amp-list` 需要 mustache 元件。

<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js"></script>

我們需要 `amp-form` 來提交收藏請求。

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

當我們提交表單時,`amp-bind` 讓我們能夠動態變更按鈕狀態。

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

管理狀態

我們使用 `amp-state` 從 JSON 端點初始化按鈕狀態。由於我們使用 Cookie 來識別使用者,因此需要新增 `credentials="include"` 屬性。

<amp-state id="favorite" credentials="include" src="https://amp.dev.org.tw/documentation/examples/interactivity-dynamic-content/favorite_button/favorite">
</amp-state>

簡易收藏按鈕

按鈕嵌入在 `amp-list` 內,這讓我們能夠根據使用者是否已喜歡某項目來動態呈現按鈕。在範本內,我們使用 mustache 的隱含迭代器 `.` 來存取我們的 `/favorite` 端點傳回的布林值:`{{#.}}heart-fill{{/.}}`。

我們也在 `amp-list` 內使用 `placeholder` 屬性宣告預留位置圖示,該圖示會在 `amp-list` 載入時顯示。

當使用者按下收藏按鈕時,會發生幾件事

  • 當使用者按下按鈕時,表單會傳送切換請求。
  • 我們實作了樂觀的 UX,會在按下按鈕時立即更新按鈕狀態。
  • 如果表單提交失敗 (`submit-error: ...`),我們會將收藏狀態回復為原始版本,並顯示錯誤訊息 (`favorite-failed-message.show`)。
  • 我們會隱藏任何現有的錯誤訊息 (`favorite-failed-message.hide`)。
<form class="favorite-button" method="post" action-xhr="https://amp.dev.org.tw/documentation/examples/interactivity-dynamic-content/favorite_button/favorite" target="_top" on="submit:AMP.setState({
                    favorite: !favorite
                 }),
                 favorite-failed-message.hide;
          submit-error:AMP.setState({
                    favorite: !favorite
                 }),
                 favorite-failed-message.show">
  <amp-list width="56" height="56" credentials="include" items="." single-item src="https://amp.dev.org.tw/documentation/examples/interactivity-dynamic-content/favorite_button/favorite" binding="always">
    <template type="amp-mustache">
      <input type="submit" class="{{#.}}heart-fill{{/.}}{{^.}}heart-border{{/.}}" [class]="favorite ? 'heart-fill' : 'heart-border'" value aria-label="Favorite Toggle">
    </template>
    <div placeholder>
      <input type="submit" disabled class="heart-loading" value aria-label="favorite placeholder">
    </div>
  </amp-list>
</form>

表單提交失敗時顯示的簡易 snackbar。

<div id="favorite-failed-message" hidden>Error: Could not favorite.
  <div on="tap:favorite-failed-message.hide" tabindex="0" role="button">CLOSE</div>
</div>

具計數器的收藏按鈕

這是前一個範例的更精緻版本,其中也包含收藏數。我們的 JSON 端點 會傳回兩個值:`value` 和 `count`。

<amp-state id="favoriteWithCount" credentials="include" src="https://amp.dev.org.tw/documentation/examples/interactivity-dynamic-content/favorite_button/favorite-with-count">
</amp-state>

實作方式與前一個範例類似,但也會在按一下按鈕時更新計數

AMP.setState({
  ...,
  count: favoriteWithCount.count + (favoriteWithCount.value ? -1 : 1)
})

我們使用暫時變數 `previousFavoriteWithCount` 來儲存先前的值,以便在表單提交失敗時能夠回復按鈕狀態。

0
<form class="favorite-button" method="post" action-xhr="https://amp.dev.org.tw/documentation/examples/interactivity-dynamic-content/favorite_button/favorite-with-count" target="_top" on="submit:AMP.setState({
               previousFavoriteWithCount: favoriteWithCount,
               favoriteWithCount: {
                 value: !favoriteWithCount.value,
                 count: favoriteWithCount.count + (favoriteWithCount.value ? -1 : 1),
               }
             }),
             favorite-failed-message.hide;
         submit-error:AMP.setState({
               value: !favoriteWithCount.value,
               favoriteWithCount: previousFavoriteWithCount.count
             }),
             favorite-failed-message.show">
  <amp-list width="200" height="56" credentials="include" items="." single-item noloading src="https://amp.dev.org.tw/documentation/examples/interactivity-dynamic-content/favorite_button/favorite-with-count" binding="always">
    <template type="amp-mustache">
      <div class="favorite-container">
        <input type="submit" class="{{#value}}heart-fill{{/value}}{{^value}}heart-border{{/value}}" [class]="favoriteWithCount.value ? 'heart-fill' : 'heart-border'" value aria-label="Favorite Toggle">
        <div class="favorite-count" [text]="favoriteWithCount.count ? favoriteWithCount.count : ''">{{count}}</div>
      </div>
    </template>
    <div placeholder>
      <div class="favorite-container">
        <input type="submit" disabled class="heart-loading" value aria-label="favorite placeholder">
        <div class="favorite-count loading">0</div>
      </div>
    </div>
  </amp-list>
</form>
需要更多說明嗎?

如果此頁面上的說明未涵蓋您的所有問題,請隨時與其他 AMP 使用者聯繫,討論您的確切使用案例。

前往 Stack Overflow
未說明的特色功能?

AMP 專案大力鼓勵您的參與和貢獻!我們希望您能成為我們開放原始碼社群的長期參與者,但我們也歡迎您針對您特別熱衷的問題做出一次性貢獻。

在 GitHub 上編輯範例