使用自定义 JavaScript 创建 UI 小部件
在本教程中,您将学习如何使用 <amp-script>
,该组件允许开发者在 AMP 中编写自定义 JavaScript。您将使用它构建一个小部件,该小部件检查密码输入字段的内容,仅在满足特定要求时才允许提交。AMP 已通过 <amp-form>
提供此功能,但 <amp-script>
将使您能够创建自定义体验。
您需要什么
- 一个现代网络浏览器
- HTML、CSS 和 JavaScript 的基本知识
- 任一
- 本地网络服务器和代码编辑器,如 SublimeText 或 VSCode
- 或 CodePen、Glitch 或类似的在线游乐场
背景
AMP 的目标是让网站对用户来说更快速、更稳定。过多的 JavaScript 会让网页变慢。但有时你需要创建 AMP 组件不提供的功能。在这种情况下,你可以使用 <amp-script>
组件编写自定义 JavaScript。
让我们开始吧!
开始
要获取入门代码,请下载或克隆 此 github 存储库。完成此操作后,将 cd
到你创建的目录中。你将看到两个目录:starter_code
和 finished_code
。finished_code
包含你在本教程中创建的内容。所以我们现在先不要看它。相反,将 cd
到 starter_code
。其中包含一个网页,该网页仅使用 <amp-form>
实现我们的表单,而无需 <amp-script>
的帮助。
要进行此练习,你需要在你的计算机上运行一个 Web 服务器。如果你已经在这样做,那么你已经准备好了!如果是这样,根据你的设置,你将能够通过在浏览器中输入类似 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/
你还可以自由地使用在线游乐场,如 Glitch 或 CodePen。 此 内容包含与 github 存储库相同的代码,如果你愿意,也可以从那里开始!
完成此操作后,你将看到我们的入门网页
在你的首选代码编辑器中打开 starter_code/index.html
。查看此表单的 HTML。请注意,密码 <input>
包含此属性
on="tap:rules.show; input-debounced:rules.show"
这告诉 AMP 在用户点击或单击密码 <input>
时以及在他们输入任何字符后显示规则 <div>
。我们更愿意使用 focus
事件,该事件还将涵盖用户切换到输入的情况。至少在本教程编写时,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 可以进行更多更改。它还允许在用户交互后进行更实质性的更改。您可以在 参考文档 中找到详细信息。对于本教程,只需知道我们指定了一个不是 container
的 layout
类型,并且我们使用了 HTML 属性来锁定组件的大小。这意味着任何 DOM 操作都限制在页面的特定区域。
如果您正在使用 AMP 验证器 Chrome 扩展程序,您现在将看到一条错误消息
#development=1
附加到您的 URL,AMP 会将验证错误输出到您的控制台。 这是什么意思?如果您的 <amp-script>
从外部文件加载其 JavaScript,则 AMP 要求您指定一个绝对 URL。我们可以使用 https://127.0.0.1/js/validate.js
来解决此问题。但 AMP 还要求使用 HTTPS。因此,我们仍然会收到验证错误,并且在本教程的范围内不包括在本地 Web 服务器上设置 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 DevTools 中,打开“Sources”选项卡。在底部,您将看到一个很长的十六进制字符串,如下所示。展开它,然后展开“无域”区域,您将看到您的脚本
添加我们的 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。这些 API 为我们提供了足够的工具来涵盖大多数用例。但需要注意的是,仅支持 DOM API 的一个子集。否则,包含在 <amp-script>
中的 JavaScript 将非常庞大,从而抵消了 AMP 的性能优势!
我们需要将这些 ID 添加到两个元素中。打开 index.html
,找到密码 <input>
和提交 <button>
,并添加 ID。还要向提交 <button>
添加一个 disabled
属性,以防止用户在我们需要他们之前单击它。
<input type=password
id="passwordBox"
...
<button type="submit" id="submitButton" tabindex="3" disabled>Submit</button>
重新加载页面。你可以通过在控制台中进行检查来验证这些全局变量是否设置正确,就像使用非工作线程 JavaScript 一样
我们还将向 <div id="rules">
中的每个 <li>
添加 ID。其中每个都包含一条我们希望控制其颜色的单独规则。我们将删除每个 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");
};
};
让我们使那些 valid
和 invalid
类实际上将文本变为绿色或红色。返回到 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");
}
};
此函数执行以下操作
- 获取密码
<input>
的内容。 - 创建一个名为
failed
的标志,将其初始化为false
。 - 遍历我们的每个正则表达式,并针对密码测试每个正则表达式
- 如果密码未通过测试,则调用
checkFail()
将相应的规则变为红色。此外,将failed
设置为true
。 - 如果密码通过测试,则调用
checkPass()
将相应的规则变为绿色。
- 如果密码未通过测试,则调用
- 最后,如果没有规则失败,则密码有效,我们启用提交按钮。
现在我们只需要几个事件监听器。还记得我们如何在 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>
的更多信息,请查看 参考文档。