在 AMP 頁面中使用自訂 JavaScript
重要事項:本文件不適用於您目前選取的格式 電子郵件!
amp-script
可讓您編寫並執行自己的 JavaScript,同時維持 AMP 的效能保證。大多數 AMP 元件透過自身的邏輯啟用常見的網路互動,讓您無需編寫 JavaScript 或匯入第三方程式庫,即可快速建構網頁。透過使用 amp-script
,您可以針對特定使用案例或獨特需求採用自訂邏輯,同時保有 AMP 的優點。
本指南提供此元件的背景資訊,以及其使用最佳做法。
Web workers
過多的 JavaScript 可能會使網站速度變慢且反應遲鈍。為了控制 AMP 頁面載入的 JavaScript 及其執行時機,AMP 的驗證規則禁止開發人員透過 <script>
標記在網頁中執行 JavaScript。
Web Worker 提供更安全執行 JavaScript 的方式。一般來說,所有 JavaScript 都在單一執行緒中執行,但每個 Worker 都在自己的執行緒中執行。之所以可行,是因為 Worker 無法存取 DOM 或 window
物件,而且每個 Worker 都在自己的全域範圍中執行。因此,它們不會互相干擾工作,也不會干擾主要執行緒中程式碼造成的變動。它們只能透過包含物件的訊息與主要執行緒以及彼此通訊。Worker 提供多執行緒網路的路徑,也就是將 JavaScript 封裝在沙箱中的方法,使其無法封鎖 UI。
Worker 無法存取 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,例如 Fetch
和 Canvas
,並讓您可以使用選定的全域物件,例如 navigator
和 localStorage
。您可以像平常一樣指派瀏覽器事件的處理常式。
但是,amp-script
不支援完整的 DOM API 或 Web API,因為這會使其自身的 JavaScript 過於龐大且笨重。如需詳細資訊,請參閱文件,並參閱這些範例,以查看 amp-script
的使用情況。
amp-script
將少數同步 DOM API 方法取代為傳回 Promise 的替代方法。例如,您可以使用 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-script
的 150K 限制。因此,建議您使用 Preact,它是 React 的輕量級替代方案。Preact 專為從 React 輕鬆移轉而設計。使用 Preact,您應該能夠建構精巧的互動,而無需過於擔心支援的內容。
團隊已使用 Vue、Angular、Aurelia 和 lit-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
(範例)、localStorage
和 Canvas
。它支援各種瀏覽器事件,因此您可以監聽超出 AMP 傳遞至傳統元件的事件。由於 amp-script
提供對 navigator
物件的存取權,因此您可以擷取有關使用者瀏覽器或偏好語言的資訊。
何時該取代 amp-bind 和 amp-list
對於熟悉 JavaScript 的 AMP 新手開發人員來說,似乎總是使用 amp-script
會比學習 amp-bind
和 amp-list
更容易。但是,在某些情況下,amp-bind
和 amp-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-list
和 amp-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-script
和 amp-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 一樣,始終在不斷發展。您可以透過參與來協助改進它。思考其他開發人員可能也需要的新功能、提交問題,當然還有建議並貢獻新功能!
-
作者: @morss
貢獻者: @CrystalOnScript 和 @fstanis