AMP

使用自訂 JavaScript 建立 UI 小工具

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

在本教學課程中,您將學習如何使用 <amp-script> 這個元件,讓開發人員可以在 AMP 中編寫自訂 JavaScript。您將使用它來建立一個小工具,檢查密碼輸入欄位的內容,只允許在符合特定要求時提交。AMP 已經透過 <amp-form> 提供此功能,但 <amp-script> 將讓您能夠建立自訂體驗。

您需要的東西

  • 現代網路瀏覽器
  • HTML、CSS 和 JavaScript 的基本知識
  • 擇一

背景

AMP 的目標是讓網站對使用者來說更快、更穩定。過多的 JavaScript 可能會使網頁變慢。但有時您需要建立 AMP 元件未提供的功能。在這種情況下,您可以使用 <amp-script> 元件來編寫自訂 JavaScript。

讓我們開始吧!

開始使用

若要取得起始程式碼,請下載或複製 這個 github 儲存庫。完成後,cd 進入您建立的目錄。您會看到兩個目錄:starter_codefinished_codefinished_code 包含您在本教學課程中將建立的內容。所以我們先別看那個。相反地,cd 進入 starter_code。這包含一個網頁,使用 <amp-form> 單獨實作我們的表單,而沒有 <amp-script> 的協助。

若要進行此練習,您需要在電腦上執行網路伺服器。如果您已經在這樣做了,那就萬事俱備了!如果是這樣,根據您的設定,您將可以透過在瀏覽器中輸入類似 https://127.0.0.1/amp-script-tutorial/starter_code/index.html 的 URL 來存取起始網頁。

或者,您可以使用類似 serve 這樣的工具來設定快速的本機伺服器,這是一個基於 Node.js 的靜態內容伺服器。如果您尚未安裝 Node.js,請從這裡下載。安裝 Node 後,在命令列輸入 npx serve。然後您可以在這裡存取您的網站

https://127.0.0.1:5000/

您也可以自由使用線上遊樂場,例如 GlitchCodePen這個包含與 github 儲存庫相同的程式碼,如果您願意,可以從這裡開始!

完成後,您會看到我們的起始網頁

在您最愛的程式碼編輯器中開啟 starter_code/index.html。看看這個表單的 HTML。請注意,密碼 <input> 包含這個屬性

on="tap:rules.show; input-debounced:rules.show"

這告訴 AMP 在使用者點擊或按一下密碼 <input> 時,以及在他們在那裡輸入任何字元後,顯示規則 <div>。我們更喜歡使用 focus 事件,這也涵蓋使用者 Tab 鍵輸入的情況。至少在本教學課程撰寫時,AMP 沒有傳遞此事件,所以我們沒有這個選項。別擔心。我們即將使用 <amp-script> 來修正這個問題!

密碼 <input> 包含另一個有趣的屬性

pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-z\d]).{8,}$"

這個正規表示式結合了一組較小的正規表示式,每個表示式都表達了我們的一個驗證規則。AMP 在輸入的內容符合之前,不會讓表單被提交。如果使用者嘗試提交,他們會看到一個錯誤訊息,但提供的細節很少

由於我們提供的程式碼不包含處理表單提交的網路服務,因此提交表單不會執行任何有用的操作。當然,歡迎您將此功能新增到您自己的程式碼中!

這種體驗是可以接受的 - 但遺憾的是,AMP 無法解釋我們的哪個驗證規則失敗。它無法知道,因為我們必須將規則壓縮成單一正規表示式。

現在,讓我們使用 <amp-script> 來建構更友善的使用者體驗!

使用 <amp-script> 重新建構

若要使用 <amp-script>,我們需要匯入它自己的 JavaScript。開啟 index.html 並將以下內容新增到 <head>

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

<amp-script> 讓我們可以將自己的 JavaScript 寫入內嵌或外部檔案中。在本練習中,我們將編寫足夠的程式碼來建立一個單獨的檔案。建立一個名為 js 的新目錄,並在其中新增一個名為 validate.js 的新檔案。

<amp-script> 允許您的 JavaScript 操縱其 DOM 子元素 - 元件封閉的元素。它將這些 DOM 子元素複製到虛擬 DOM 中,並讓您的程式碼存取此虛擬 DOM。在本練習中,我們希望我們的 JavaScript 控制我們的 <form> 及其內容。因此,我們將把 <form> 包裹在 <amp-script> 元件中,如下所示

<amp-script src="js/validate.js" layout="fixed" sandbox="allow-forms" height="500" width="750">
  <form method="post" action-xhr="#" target="_top" class="card">
    ...
  </form>
</amp-script>

我們的 <amp-script> 包含屬性 sandbox="allow-forms"。這告訴 AMP 腳本修改表單內容是可以的。

由於 AMP 的目標是保證快速、視覺穩定的使用者體驗,因此它不會讓我們的 JavaScript 在任何時候都對 DOM 進行無限制的變更。如果 <amp-script> 元件的大小無法變更,您的 JavaScript 可以進行更多變更。在使用者互動後,它也允許更實質的變更。您可以在 參考文件中找到詳細資訊。對於本教學課程,知道我們已指定一個不是 containerlayout 類型,並且我們已使用 HTML 屬性來鎖定元件的大小就足夠了。這表示任何 DOM 操作都僅限於頁面的特定區域。

如果您正在使用 AMP 驗證器 Chrome 擴充功能,您現在會看到錯誤訊息

如果您沒有這個擴充功能,請將 #development=1 附加到您的 URL,AMP 會將驗證錯誤輸出到您的 Console。

這是什麼意思?如果您的 <amp-script> 從外部檔案載入其 JavaScript,AMP 要求您指定絕對 URL。我們可以透過使用 https://127.0.0.1/js/validate.js 來修正這個問題。但 AMP 也要求使用 HTTPS。因此,我們仍然會收到驗證錯誤,並且在本機網路伺服器上設定 SSL 超出本教學課程的範圍。如果您想這樣做,您可以按照 這篇文章中的指示進行。

接下來,我們可以從表單中移除 pattern 屬性及其正規表示式:我們不再需要它了!

我們也將移除目前用於告訴 AMP 顯示密碼規則的 on 屬性。如上所述,我們將改用 <amp-script> 來擷取瀏覽器的 focus 事件。

pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-z\d]).{8,}$"
on="tap:rules.show; input-debounced:rules.show"

現在讓我們確保我們的 <amp-script> 正在運作。開啟您建立的 validate.js 檔案並新增偵錯訊息

console.log("Hello, amp-script!");

前往您的瀏覽器,開啟主控台,然後重新載入頁面。確保您看到您的訊息!

我的 JavaScript 在哪裡?

<amp-script> 在 Web Worker 中執行您的 JavaScript。Web Worker 無法直接存取 DOM,因此 <amp-script> 讓 Worker 存取 DOM 的虛擬副本,並使其與真實 DOM 保持同步。<amp-script> 提供許多常見 DOM API 的模擬,您幾乎可以在 JavaScript 中以通常的方式使用所有這些模擬。

如果在任何時候您需要偵錯您的腳本,您可以像對待任何 JavaScript 一樣,在 Web Worker 中的 JavaScript 中設定中斷點。您只需要知道在哪裡找到它。

在 Chrome DevTools 中,開啟「來源」標籤。在底部,您會看到一個長十六進位字串,如下所示。展開它,然後展開「無網域」區域,您就會看到您的腳本

新增我們的 JavaScript

現在我們知道我們的 <amp-script> 正在運作,讓我們編寫一些 JavaScript!

我們要做的第一件事是抓取我們將使用的 DOM 元素,並將它們存放在全域變數中。我們的程式碼將使用密碼輸入、提交按鈕和顯示密碼規則的區域。將這三個宣告新增到 validate.js

const passwordBox = document.getElementById("passwordBox");
const submitButton = document.getElementById("submitButton");
const rulesArea = document.getElementById("rules");

請注意,我們能夠使用正規 DOM API 方法,例如 getElementById()。雖然我們的程式碼在 Worker 中執行,而 Worker 缺乏對 DOM 的直接存取權,但 <amp-script> 提供了 DOM 的虛擬副本,並模擬了一些常見的 API,此處列出。這些 API 為我們提供了足夠的工具來涵蓋大多數使用案例。但重要的是要注意,僅支援 DOM API 的子集。否則,<amp-script> 隨附的 JavaScript 將會非常龐大,從而抵消 AMP 的效能優勢!

我們需要將這些 ID 新增到兩個元素。開啟 index.html,找到密碼 <input> 和提交 <button>,並新增 ID。同時將 disabled 屬性新增到提交 <button>,以防止使用者在我們想要他們點擊之前點擊它。

<input type=password
       id="passwordBox"

...

<button type="submit" id="submitButton" tabindex="3" disabled>Submit</button>

重新載入頁面。您可以透過在主控台中檢查來驗證這些全域變數是否已正確設定,就像您可以使用非 Worker JavaScript 一樣

我們還將 ID 新增到 <div id="rules"> 中的每個 <li>。這些每個都包含一個個別規則,我們將想要控制其顏色。我們將移除 class="invalid" 的每個實例。我們新的 JavaScript 將在需要時新增它!

<ul>
  <li id="lower">Lowercase letter</li>
  <li id="upper">Capital letter</li>
  <li id="digit">Digit</li>
  <li id="special">Special character (@$!%*?&)</li>
  <li id="eight">At least 8 characters long</li>
</ul>

在 JavaScript 中實作我們的密碼檢查

接下來,我們將從我們的 pattern 屬性中解壓縮正規表示式。每個正規表示式都代表我們的一個規則。讓我們在 validate.js 的底部新增一個物件地圖,將每個規則與它檢查的條件相關聯。

const checkRegexes = {
  lower: /[a-z]/,
  upper: /[A-Z]/,
  digit: /\d/,
  special: /[^a-zA-Z\d]/i,
  eight: /.{8}/
};

設定這些全域變數後,我們就可以編寫檢查密碼並相應調整 UI 的邏輯了。我們將把我們的邏輯放在一個名為 initCheckPassword 的函式中,該函式接受單一引數 - 密碼 <input> 的 DOM 元素。這種方法方便地將 DOM 元素存放在閉包中。

function initCheckPassword(element) {

}

接下來,讓我們用我們需要的函式和事件監聽器指派來填入 initCheckPassword。首先,新增一個小函式,如果規則通過,則將個別規則 <li> 變成綠色 - 另一個函式在規則失敗時將其變成紅色。

function initCheckPassword(el) {
  const checkPass = (el) => {
    el.classList.remove("invalid");
    el.classList.add("valid");
  };

  const checkFail = (el) => {
    el.classList.remove("valid");
    el.classList.add("invalid");
  };
};

讓我們讓這些 validinvalid 類別實際將文字變成綠色或紅色。回到 index.html,並將這兩個規則新增到 <style amp-custom> 標籤

li.valid {
  color: #2d7b1f;
}

li.invalid {
  color:#c11136;
}

現在我們準備好新增邏輯,檢查密碼 <input> 的內容是否符合我們的規則。在 initCheckPassword() 中新增一個名為 checkPassword() 的新函式,就在右大括號之前

const checkPassword = () => {
  const password = element.value;
  let failed = false;

  for (const check in checkRegexes) {
    let li = document.getElementById(check);

    if (password.match(checkRegexes[check])) {
      checkPass(li);
    } else {
      checkFail(li);
      failed = true;
    }
  }

  if (!failed) {
    submitButton.removeAttribute("disabled");
  }
};

此函式執行以下操作

  1. 抓取密碼 <input> 的內容。
  2. 建立一個名為 failed 的旗標,初始化為 false
  3. 迭代我們的每個正規表示式,並針對密碼測試每個正規表示式
    • 如果密碼測試失敗,則呼叫 checkFail() 將對應的規則變成紅色。此外,將 failed 設定為 true
    • 如果密碼測試通過,則呼叫 checkPass() 將對應的規則變成綠色。
  4. 最後,如果沒有規則失敗,則密碼有效,並且我們啟用「提交」按鈕。

我們現在只需要幾個事件監聽器。還記得我們如何在 AMP 中無法使用 focus 事件嗎?在 <amp-script> 中,我們可以。每當密碼 <input> 收到 focus 事件時,我們都會顯示規則。每當使用者在該輸入中按下按鍵時,我們都會呼叫 checkPassword()

將這兩個事件監聽器新增到 initCheckPassword() 的底部,直接在大括號之前

element.addEventListener("focus", () => rulesArea.removeAttribute("hidden"));
element.addEventListener("keyup", checkPassword);

最後,在 validate.js 的最末端,新增一行,使用密碼 <input> DOM 元素初始化 initCheckPassword

initCheckPassword(passwordBox);

我們的邏輯現在已完成!當密碼符合我們所有的條件時,所有規則都將變成綠色,並且我們的提交按鈕將被啟用。您現在應該能夠進行像這樣的互動

如果您遇到困難,您可以隨時參考 finished_code 目錄中的工作程式碼。

恭喜!

您已學習如何使用 <amp-script> 在 AMP 中編寫自己的 JavaScript。您已成功使用自己的自訂邏輯和 UI 功能增強了 <amp-form> 元件!隨時為您的新頁面新增更多功能!並且,若要深入瞭解 <amp-script>,請查看 參考文件