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> 的協助。

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

或者,您可以使用類似 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 會將驗證錯誤輸出到您的主控台。

這是什麼意思?如果您的 <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 中以通常的方式使用所有這些 API。

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

在 Chrome 開發人員工具中,開啟「來源」標籤。在底部,您會看到一個長十六進位字串,如下所示。展開該字串,然後展開「無網域」區域,您就會看到您的指令碼

加入我們的 JavaScript

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

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

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

請注意,我們能夠使用像 getElementById() 這樣的常規 DOM API 方法。雖然我們的程式碼在 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>,請查看 參考文件