AMP

构建个性化互动体验

本指南概述了高度个性化的交互选项,可集成到 AMP 页面中。每个网站都是独一无二的,就像雪花和变量名称一样,而 AMP 的现成组件库可能无法满足您的所有需求。相反,AMP 提供了可适应的组件,这些组件可以为复杂的交互需求提供个性化解决方案。使用这些组件来构建选择界面、显示小部件和处理自定义逻辑。

使用 amp-selector 管理选择状态

许多常见的网络体验包括向用户展示选项并对他们的选择做出响应。使用 amp-selector 组件,您可以构建选项菜单、指定表单输入行为并实现选项卡。

amp-selector 提供两个核心功能

  1. 根据用户选择更新 UI。
  2. 管理单选或多选状态。

通过允许单选或多选选项来定义用户在进行选择时元素的行为。您可以根据用户交互禁用或突出显示选择器选项,并且它公开选择事件,从而可以与其他 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 中的客户端渲染 中阅读更多关于使用 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-action-macro 来封装通用逻辑。

定义表达式宏

你可以通过定义一个 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-layoutamp-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>
在游乐场中打开此代码段