构建个性化互动体验
本指南概述了高度个性化的交互选项,可集成到 AMP 页面中。每个网站都是独一无二的,就像雪花和变量名称一样,而 AMP 的现成组件库可能无法满足您的所有需求。相反,AMP 提供了可适应的组件,这些组件可以为复杂的交互需求提供个性化解决方案。使用这些组件来构建选择界面、显示小部件和处理自定义逻辑。
使用 amp-selector 管理选择状态
许多常见的网络体验包括向用户展示选项并对他们的选择做出响应。使用 amp-selector
组件,您可以构建选项菜单、指定表单输入行为并实现选项卡。
amp-selector 提供两个核心功能
- 根据用户选择更新 UI。
- 管理单选或多选状态。
通过允许单选或多选选项来定义用户在进行选择时元素的行为。您可以根据用户交互禁用或突出显示选择器选项,并且它公开选择事件,从而可以与其他 AMP 组件进行交互。
<amp-selector layout="container"
class="sample-selector"
multiple>
<amp-img src="/static/samples/img/landscape_sea_300x199.jpg"
width="90"
height="60"
option="1"
alt="Photo of a sea landscape"></amp-img>
<amp-img src="/static/samples/img/landscape_desert_300x200.jpg"
width="90"
height="60"
option="2"
selected
alt="Photo of a desert landscape"></amp-img>
<amp-img src="/static/samples/img/landscape_ship_300x200.jpg"
width="90"
height="60"
option="3"
alt="Photo of a water landscape with ship"></amp-img>
<amp-img src="/static/samples/img/landscape_village_300x200.jpg"
width="90"
height="60"
option="4"
disabled
alt="Photo of a village landscape"></amp-img>
</amp-selector>
以下是一个示例,其中我们将 amp-selector
与 SVG 结合使用以创建交互式图表。
<head>
<style amp-custom>
.bar[option][selected] {
fill: red;
outline: none;
}
</style>
</head>
<body>
<amp-selector>
<svg class="chart" width="420" height="150" aria-labelledby="title desc" role="img">
<title id="title">A bar chart showing information</title>
<desc id="desc">4 apples; 8 bananas; 15 kiwis; 16 oranges; 23 lemons</desc>
<g class="bar" option>
<rect width="40" height="19"></rect>
<text x="45" y="9.5" dy=".35em">4 apples</text>
</g>
<g class="bar" option>
<rect width="80" height="19" y="20"></rect>
<text x="85" y="28" dy=".35em">8 bananas</text>
</g>
<g class="bar" option>
<rect width="150" height="19" y="40"></rect>
<text x="150" y="48" dy=".35em">15 kiwis</text>
</g>
<g class="bar" option selected>
<rect width="160" height="19" y="60"></rect>
<text x="161" y="68" dy=".35em">16 oranges</text>
</g>
<g class="bar" option>
<rect width="230" height="19" y="80"></rect>
<text x="235" y="88" dy=".35em">23 lemons</text>
</g>
</svg>
</amp-selector>
</body>
使用 amp-bind 实现简单的交互和数据绑定
用户希望现代网络对他们的交互做出反应并反映他们所做的更改。amp-bind
组件支持状态设置、读取、UI 更改,并且可以处理用户输入和简单的逻辑。
<amp-state id="foo">
<script type="application/json">
{
"bar": "State is set."
}
</script>
</amp-state>
<p [text]="foo.bar">No state is set</p>
<button on="tap:AMP.setState({})">Set State</button>
amp-bind
组件在页面加载时不执行任何评估,但与 amp-list 结合使用除外。
相反,它会等到用户触发与 amp-bind 交互的操作。这通过不执行会减慢页面加载速度的计算来支持核心网络指标,并且不允许页面布局发生变化,从而提高首次用户交互的速度。
amp-bind
使用其自己的语法来构建交互性和绑定元素。它利用了三个主要概念:状态、表达式和绑定。
绑定
绑定是将元素的属性链接到表达式的特殊属性,它将所有内容联系在一起。绑定是形式为 [property]
的特殊属性。这将元素的属性链接到状态。使用绑定来更新文本、更改图像大小或允许用户指定外观。
在此处阅读有关 绑定的更多信息,并查看 AMP 组件 和 HTML 元素 的可绑定属性的完整列表。
状态
每个使用 amp-bind
的 AMP 页面都有自己的作用域、可变 JSON 数据,大小限制为 100kb。此数据是状态。
<amp-state id="todos">
<script type="application/json">
[
"Learn AMP"
]
</script>
</amp-state>
<input id="todoInput" type="text" on="input-throttled:AMP.setState({
newTodo: event.value
})">
<button on="tap:AMP.setState({
todos: todos.concat(newTodo)
})">
Add Todo
</button>
<amp-list [src]="todos" src="amp-state:todos" height="20" items="." [is-layout-container]=true>
<template type="amp-mustache">
<li>{{.}}</li>
</template> </amp-list>
amp-bind
支持预定义状态、用户交互后的状态初始化以及对状态的更新。你可以使用表达式、绑定、操作和事件来引用、添加或更改任何定义为键值对的变量。
有多种声明和使用状态的方法。在 amp-bind 文档 中阅读有关状态的更多信息。
表达式
amp-bind
组件使用类似 JavaScript 的表达式对来自用户输入和状态变量的数据执行操作。
<p [text]="myExpressionsState.foo"></p>
<!-- 1 + '1'; // 11 -->
<button on="tap:AMP.setState({myExpressionsState: {foo: 1 + '1'}})">
foo: 1 + "1"
</button>
<!-- 1 + +'1'; // 2 -->
<button on="tap:AMP.setState({myExpressionsState: {foo: 1 + + '1'}})">
foo: 1 + + "1"
</button>
<!-- !0; // true -->
<button on="tap:AMP.setState({myExpressionsState: {foo: !0}})">foo: !0</button>
<!-- null || 'default'; // 'default' -->
<button on="tap:AMP.setState({myExpressionsState: {foo: null || 'default'}})">
null || "default"
</button>
<!-- [1, 2, 3].map(x => x + 1); // 2,3,4 -->
<button
on="tap:AMP.setState({myExpressionsState: {foo: [1, 2, 3].map(x => x + 1)}})"
>
[1, 2, 3].map(x => x + 1)
</button>
这些表达式具有 允许列出的支持函数,与经典 JavaScript 相比有一些轻微的 差异和限制。在此处阅读有关 表达式的更多信息。
定义表达式宏
你可以通过定义一个 amp-bind-macro 来重复使用一个 amp-bind 表达式片段。amp-bind-macro
元素允许一个表达式,该表达式可以接受零个或多个参数并引用当前状态。像调用一个函数一样调用 amp-bind-macro
,从文档中的任何地方引用 id
属性值。
<amp-bind-macro
id="circleArea"
arguments="radius"
expression="3.14 * radius * radius"
></amp-bind-macro>
<p>
Input a radius value
</p>
<input
type="number"
min="0"
max="100"
value="0"
on="input-throttled:AMP.setState({myCircle:{radius: event.value}})"
/>
<p>
The circle has an area of
<span [text]="circleArea(myCircle.radius)">0</span>.
</p>
一个宏还可以调用它自己之前定义的其他宏。一个宏不能递归调用自身。
使用 amp-script 实现复杂的交互
有些体验需要带有自定义逻辑的高度复杂的解决方案。在这些情况下,使用 amp-script
组件将功能嵌入到你的 AMP 页面中。你可以编写原生 JavaScript,或导入一个库,如 Preact,所有这些都不会牺牲性能。使用它来操作 DOM 或导入个性化小组件。
amp-script
在每个页面上都有 150 千字节的自定义 JavaScript 限制,在 <amp-script>
的每个实例之间共享。它有一个 允许的 API 列表 和一些 安全功能 需要注意。
构建自定义小部件
我们相信网络应该是令人愉悦的、身临其境的和独一无二的。独特的网站需要与其品牌相符的功能和风格。使用 amp-script,你可以在页面的任何位置导入自定义小组件。使用这些小组件来创建漂亮的界面,这些界面运行在用原生 JavaScript、Preact 或任何你需要的东西编写的复杂逻辑上。在此处查看 Worker DOM Preact 演示。
使用状态管理复杂的交互
你可能需要执行复杂的计算或从改变 DOM 的基础逻辑中检索和处理信息。你可以通过将整个页面包装在 amp-script 元素中来管理此逻辑,但这样做会失去一些 AMP 的好处。为了保留这些好处,你可以将复杂的计算卸载到 amp-script,然后将其与 amp-bind 结合起来更新和反映新状态。
在 amp-script 中实现所有交互
在某些情况下,将整个页面包装在 <amp-script>
中是使用 AMP 创建高度互动体验的最佳方式。
虽然此解决方案让你对页面拥有绝对控制权,但它确实会移除 AMP 提供的一些好处。例如创建新的 AMP 组件。amp-script 组件可以将任何 HTML 元素添加到页面 DOM,但仅限于 amp-layout
和 amp-img
组件。
结合 amp-script 和 amp-bind
amp-script 组件让你可以实现复杂的域逻辑,这会导致 amp-bind 表达式变得过于复杂。不要将整个页面包装在 <amp-script>
标记中,而是将逻辑卸载到 amp-script,并使用 amp-bind
使用结果更新页面状态。有一个警告,用户必须与触发计算的元素进行交互。但是,一旦处理完信息,amp-script
就可以通过调用 AMP.setState
自行更新页面的状态。amp-bind
的功能将处理其余部分以更新 DOM。
<head>
<meta
name="amp-script-src"
content="sha384-qdYQLoj2SRKXBu33BwIoyRKorw0b0nQ8UPIoIMc9wL8KVLcKODSAK52yNGQNS_vN"
/>
<style amp-custom>
.clickedButton {
border: 5px solid green;
}
</style>
</head>
<body>
<amp-script width="200" height="100" script="hello-world" [class]="scriptStyle">
<button>Hello amp-script!</button>
</amp-script>
<script id="hello-world" type="text/plain" target="amp-script">
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
document.body.textContent = 'Hello World!';
AMP.setState({ scriptStyle: "clickedButton" })
});
</script>
</body>
-
由 @CrystalOnScript 撰写
由 @sbenz 提供帮助