AMP

在 AMP 頁面中使用自訂 JavaScript

重要事項:本文件不適用於您目前選取的格式 ads

amp-script 可讓您撰寫並執行自己的 JavaScript,同時維持 AMP 的效能保證。大多數 AMP 組件透過自身的邏輯啟用常見的網路互動,讓您可以快速建置頁面,而無需撰寫 JavaScript 或匯入第三方函式庫。透過使用 amp-script,您可以採用針對特定使用案例或獨特需求的自訂邏輯,而不會失去 AMP 的優點。

本指南提供關於此組件的背景資訊及其使用最佳實務。

Web workers (網頁工作者)

過多的 JavaScript 可能會使網站速度變慢且反應遲鈍。為了控制 AMP 頁面載入的 JavaScript 及其執行時間,AMP 的驗證規則禁止開發人員透過 <script> 標籤在網頁中執行 JavaScript。

Web workers (網頁工作者) 提供更安全地執行 JavaScript 的方法。一般來說,所有 JavaScript 都在單一執行緒中執行,但每個 worker (工作者) 都在自己的執行緒中執行。這是可行的,因為它們無法存取 DOM 或 window 物件,而且每個 worker (工作者) 都在自己的全域範圍中執行。因此,它們不會互相干擾工作,也不會干擾主要執行緒中程式碼引起的變動。它們只能透過包含物件的訊息與主要執行緒和彼此之間進行通訊。Workers (工作者) 提供通往多執行緒網路的途徑,一種將 JavaScript 封裝在沙箱中的方法,使其不會阻擋 UI。

Workers (工作者) 無法存取 DOM。為了填補這個缺口,AMP 團隊建立了一個名為 WorkerDOM 的開放原始碼函式庫。WorkerDOM 將 DOM 複製到虛擬 DOM,並使副本可供 worker (工作者) 使用。WorkerDOM 也重新建立標準 DOM API 的子集。當 worker (工作者) 變更虛擬 DOM 時,WorkerDOM 會在真實 DOM 中重新建立這些變更。這讓 worker (工作者) 可以使用標準技術來操作 DOM 並在頁面上進行變更。DOM 同步僅以單向進行。如果主要執行緒修改 DOM,則沒有機制可以讓 worker (工作者) 知道。

amp-script 是 WorkerDOM 的包裝器,使 WorkerDOM 可以在 AMP 中使用,提供與 AMP 功能的連線、建立開發人員 API,並引入保護使用者體驗的限制。WorkerDOM 提供 amp-script 功能的核心。

amp-script 概觀

JavaScript 語言在 worker (工作者) 中的運作方式與在瀏覽器中其他地方相同。因此,在 amp-script 中,您可以使用 JavaScript 提供的所有常用結構。WorkerDOM 也重新建立許多常用的 DOM API,並使其可供您使用。它支援常見的 Web API,例如 FetchCanvas,並讓您可以存取選定的全域物件,例如 navigatorlocalStorage。您可以透過常用的方式為瀏覽器事件指派處理常式。

但是,amp-script 不支援完整的 DOM API 或 Web API,因為這會使其自身的 JavaScript 變得過大且笨重。請參閱文件以取得詳細資訊,並參考這些範例以查看 amp-script 的使用情況。

amp-script 使用傳回 Promise 的替代方案,取代少數同步 DOM API 方法。例如,您可以使用 getBoundingClientRectAsync() 取代 getBoundingClientRect()。有時,這對於提供同步存取已計算版面配置的 DOM API 是必要的,有時則為了讓 amp-script 可以呼叫原生瀏覽器方法並等待回應。

為了維持 AMP 的效能和版面配置穩定性保證,amp-script 具有一些限制。如果 amp-script 容器的大小不是固定的,則您的程式碼只有在使用者互動觸發時才能進行變動。您無法將樣式表或額外的腳本新增至 DOM,且不支援 importScripts()。請參閱文件以取得詳細資訊。

使用 JavaScript 框架

由於 DOM API 未完全支援,因此在 amp-script 中操作 DOM 的最佳方法是什麼?以下是兩種可能性。

1) 了解支援的項目。 了解豐富的支援 API 集。您需要以不同的方式思考 DOM API - 不要將其視為多年開發的大量屬性和方法集,而應將其視為簡潔的工具集。

2) 使用 Preact。 React 不僅是建置網站的熱門方式,而且它還使用 DOM API 的子集來變動 DOM。amp-script 可以完全支援 API 的這一部分,因此完全支援 React。也就是說,React 套件通常會超過 amp-script150K 限制。因此,建議您使用 Preact,這是 React 的輕量級替代方案。Preact 旨在從 React 進行直接移轉。使用 Preact,您應該能夠建置精細的互動,而無需太擔心支援的項目。

團隊已針對 VueAngularAurelialit-html 等框架測試過 amp-script,但測試範圍較小。如果您發現任何缺口,請提交問題 - 或者,更好的做法是提交提取請求

由於 amp-script 無法詳盡地支援 DOM API,因此只是將 jQuery 等函式庫複製到 <amp-script> 組件中將無法運作。

使用案例

amp-script 擴展了 AMP 網頁功能的範圍。由於它支援 DOM 和 Web API 的子集,並且由於它的使用帶有限制,因此它不是通用的 JavaScript 解決方案。任何大量的現有 JavaScript 可能都需要修改才能在 amp-script 環境中運作。

但是,amp-script 提供了一種很好的方法來處理現有 AMP 組件未提供的邏輯和互動。以下是一些絕佳的使用案例。

建立新的互動

amp-script 為您提供 JavaScript 和 DOM API 的強大功能。它可讓您建立其他 AMP 組件無法建立的互動,開啟通往完整網路創造力的大門。

也就是說,在轉向使用 amp-script 來建立新的互動之前,請檢查是否有 AMP 組件或組件組合可以執行相同的操作。利用現有的 AMP 組件最終會使您的程式碼更小且更易於維護。如果組件可以達到與您想要的效果類似的效果,您或許可以使用 amp-script 自訂其行為

如果您使用 amp-script 建立其他開發人員可能感興趣的互動,請考慮建議或貢獻新的組件。

新增進階邏輯

當您的邏輯無法簡潔地放入簡潔的表達式中時,amp-script 是最佳選擇。amp-bind 可讓您將邏輯引入使用者互動中,但您的 JavaScript 需要放入單一表達式中。由於程式碼封裝在 HTML 屬性中,因此它不會在您的 IDE 中獲得語法醒目提示的優點,您無法設定中斷點,而且偵錯可能會是一項挑戰。在這種情況下,amp-script 可讓您遵循最佳程式設計實務。

強化 AMP 組件

amp-script 可以存取 AMP 狀態變數以及 AMP.getState()AMP.setState() 方法。這提供了一條使用您自己的邏輯來強化現有 AMP 組件的路徑。它也可以影響 <amp-script> 組件本身以外的 DOM。請參閱此處此處以取得範例。

取代 amp-bind 和 amp-list

如果您是 AMP 的新手,並且熟悉 JavaScript,則可能會很想將 amp-script 用於每個瀏覽器互動。但是,對於較簡單的互動,您可能會想要學習使用 amp-bind 和 AMP 的動作和事件系統。對於更精細的互動,或對於需要更多邏輯和複雜狀態變數操作的情況,amp-script 可能會更容易

處理伺服器資料

AMP 可讓您使用 amp-list 擷取伺服器資料,並使用 amp-mustache 格式化資料。在 mustache 範本不足的情況下,amp-script 可以擷取資料、格式化資料,並將格式化的資料注入 DOM。如果您需要在將伺服器資料傳送至 amp-mustache 之前先行處理,則 amp-script 函式可以是 amp-list 的資料來源。請參閱文件以取得詳細資訊和程式碼範例。

引入新功能

您可以使用 amp-script 來利用 Web API 和 DOM API 中目前 AMP 組件無法存取的區域,或以 AMP 組件不支援的方式使用這些 API。例如,amp-script 支援 WebSockets (範例)、localStorageCanvas。它支援各種瀏覽器事件,因此您可以監聽超出 AMP 傳遞給傳統組件的事件以外的事件。而且由於 amp-script 提供對 navigator 物件的存取權,因此您可以擷取有關使用者的瀏覽器偏好語言的資訊。

何時取代 amp-bind 和 amp-list

對於熟悉 JavaScript 的 AMP 新手開發人員來說,似乎總是使用 amp-script 比學習 amp-bindamp-list 更容易。但是,在某些情況下,amp-bindamp-list 更適合。

amp-bind 通常對於基本互動更直接,其與 HTML 標籤的緊密整合非常吸引人。在此範例中,按下按鈕會變更文字片段。AMP 的資料繫結使此操作直接且易於閱讀

<p [text]="name">Rajesh</p>
<button on="tap:AMP.setState({name: 'Priya'})">I am Priya</button>

同樣地,當使用您控制輸出的 API 時,您或許可以在伺服器上實作業務邏輯。您可以格式化 API 輸出的資料,使其順利地放入 amp-mustache 範本中。amp-list 在這種情況下非常適合。

amp-bind 也提供了一種直接的機制來在 AMP 組件之間進行通訊。在此範例中,點擊 <amp-selector> 中的圖片會將狀態變數 selectedSlide 設定為 0,這反過來會使 <amp-carousel> 移動到其第一個滑動。

<amp-carousel slide="selectedSlide">
...
</amp-carousel>

<amp-selector>
  <amp-img on="tap:AMP.setState({selectedSlide: 0})"/>
</amp-selector>

傳統的互動式 AMP 組件也可能更適合跨越網頁大部分區域的互動 - 因為您可能不希望將 DOM 的大部分內容包裝在 <amp-script> 中。amp-listamp-bind 與 AMP 的其餘部分緊密整合,使其可以方便地在網頁上的任何位置使用繫結。

但是,在涉及更複雜的狀態變數或多個互動的頁面上,使用 amp-script 將產生更簡單且更易於維護的程式碼。以 AMP Camp 電子商務示範網站 中的這個範例為例

<amp-selector
  name="color"
  layout="container"
  [selected]="product.selectedColor"
  on="select:AMP.setState({
      product: 
        {
          selectedSlide: product[event.targetOption].option - 1,
          selectedColor: event.targetOption,
          selectedSize: product[event.targetOption].sizes[product.selectedSize] != null ?
                        product.selectedSize : 
                        product[event.targetOption].defaultSize,
          selectedQuantity: 1
        }
      })"
></amp-selector>

此示範是在 amp-script 發布之前建立的。但是,這種邏輯將更容易在 JavaScript 中撰寫和偵錯。對於具有更多業務邏輯的頁面,使用 amp-script 將可讓您避免混淆並遵循更好的程式設計實務。

在許多情況下,您會想要在同一個頁面上同時使用 amp-scriptamp-bind。針對較簡單的互動部署 amp-bind,當您需要更多邏輯或結構時,再轉向使用 amp-script。此外,雖然 amp-script 只能對其 DOM 子項進行變動,但如上所述,它可以透過變動狀態變數來影響頁面的其餘部分。amp-bind 會完成其餘工作,如 此範例 所示。

雖然當您的程式碼變更它可以存取的虛擬 DOM 時,WorkerDOM 會變更真實 DOM,但沒有機制可以反向同步。因此,不建議使用 amp-bind 或其他方法來修改 <amp-script> 的子項。請將頁面的該區域保留給您的 amp-script JavaScript。

amp-script 貢獻

amp-script 總是在不斷發展,就像 AMP 一樣。您可以透過參與來協助改進它。思考其他開發人員可能也需要的新功能、提交問題,當然還有建議和貢獻新功能