
该 amp-list 组件最近添加了对在页面加载时呈现 AMP 状态的支持。这可以在简化某些用例的 AMP 页面组装的同时提供更好的用户体验。
示例用例:搜索结果
考虑用户执行搜索后的搜索结果页面。搜索结果通常具有按钮(或类似按钮)来更改结果的排序顺序(例如,从 A 到 Z 与从 Z 到 A)或对当前搜索结果集应用其他筛选约束(例如,仅显示“小”项目)。
在 AMP 中实现此功能的一种常见方法是使用一个 amp-list 组件,其中“[src]”属性是从 AMP 状态构建的 URL。单击按钮会更新 AMP 状态,从而导致 URL 更新,进而触发 amp-list 更新。
<amp-state id="filter">
<script type="application/json">
{
"order": "atoz",
"size": "small"
}
</script>
</amp-state>
<button on="tap:AMP.setState({filter: {order: 'atoz'})">Increasing</button>
<button on="tap:AMP.setState({filter: {order: 'ztoa'})">Decreasing</button>
<amp-list
...
[src]="'/api/search?order=' + filter.order + '&size=' + filter.size"
...>
Code language: HTML, XML (xml)
AMP 列表页面加载闪烁
通常,这可以很好地工作,因为按钮会更新 AMP 状态,而 AMP 框架会协调页面的其余更新。
但是,存在一个负面影响。第一个页面加载将显示没有 amp-list 结果的页面,直到使用“src”属性中的 URL 对后端进行 API 调用。然后页面将使用结果进行更新。
<amp-list
src="/api/search?order=atoz&size=small"
[src]="'/api/search?order=' + filter.order + '&size=' + filter.size"
...>
Code language: HTML, XML (xml)
如果“src”URL 响应时间过长,这会导致页面闪烁,这是一种不可取的用户体验。
页面闪烁的解决方法
在 AMP 中存在一些现有的技术来解决此问题。例如,可以将一个 div 元素放在页面上,并使用 API 结果在服务器端进行渲染,以获得第一个页面。最初,div 是可见的,而 amp-list 是隐藏的。一旦用户单击按钮,div 将更新为隐藏,而 amp-list 将变为可见。
<div
hidden="false"
[hidden]="filter.changesMade"
>
... server side rendered content ...
</div>
<amp-list
hidden="true"
[hidden]="!filter.changesMade"
src="/api/search?order=atoz&size=small"
[src]="'/api/search?order=' + filter.order + '&size=' + filter.size"
...>
Code language: HTML, XML (xml)
虽然这种方法有效,但它也有一些缺点,例如需要维护额外的 AMP 状态,并且您还需要在服务器和浏览器中以相同的方式渲染内容的额外复杂性。
介绍 amp-state 前缀
但是,AMP 中现在提供了一种更简单的解决方案,它利用了 amp-list 对基于 AMP 状态而不是进行 API 调用渲染内容的支持。进行 API 调用时,会更新 AMP 状态,而不是直接更新 amp-list。
<amp-list
src="amp-state:searchResponse"
[src]="searchResponse.items"
...>
Code language: HTML, XML (xml)
“amp-state:”前缀(AMP 的最新添加)允许从 AMP 状态初始化初始 amp-list 渲染,而无需进行 API 调用。请注意,“src”和“[src]”属性都引用了相同的“searchResponse”AMP 状态,以确保一致性。这与一个 amp-state 元素一起使用,该元素可以使用 JSON 内容进行初始化,然后通过“[src]”属性通过 API 调用进行更新。
<amp-state
id="searchResponse"
[src]="'/api/search?order=' + filter.order + '&size=' + filter.size"
>
<script type="application/json">
... server side injected initial AMP state goes here ...
</script>
</amp-state>
Code language: HTML, XML (xml)
也就是说,在页面加载时,AMP 状态将从嵌入在页面中的 JSON 初始化。然后,amp-list 使用 Mustache 模板渲染此状态。初始 AMP 状态是服务器端注入到页面中的。许多编程语言都支持 JSON,这简化了注入过程。(AMP Mustache 库仅在 JavaScript 中可用,因此更难集成,例如,如果您使用 PHP 进行服务器端渲染。)
在此示例中,在初始页面渲染后,如果按下按钮,它将更新“filter.order”或“filter.size”。这将触发 amp-state 组件对 API 进行调用以刷新“searchResponse”AMP 状态。这反过来将触发 amp-list 组件使用 Mustache 模板渲染更新后的响应。
最终结果是,amp-list 可以通过将 JSON 注入返回的页面来初始化,而无需进行单独的 API 调用来执行初始渲染。它还有助于区分不同按钮和组件的职责。用户界面控件会更新状态。然后,AMP 会执行一系列更新和 API 调用,以适当地刷新页面。
它还避免了将 AMP 页面 mustache 模板与服务器端渲染逻辑保持同步的维护挑战。
使用状态设计页面
以上讨论重点介绍了新“amp-state:”前缀的工作原理的技术方面,但关于一个良好且可维护的页面应该是什么样子还有另一个问题。AMP 支持复杂的绑定表达式,但将这些表达式推向极限最终会导致过于复杂的页面,难以维护。
例如,模型/视图/控制器 (MVC) 模式鼓励将捕获底层数据结构(模型)与将内容渲染到页面上的代码(视图)分离。然后,控制器会修改模型,触发视图更新。
相同的模式与 AMP 页面相关。AMP 状态是模型,amp-list 和绑定表达式是您定义“视图”的方式,然后“on”属性实现控制器逻辑,amp-script 可用于更复杂的控制器逻辑。也就是说,避免将过于复杂的逻辑放入视图逻辑(绑定表达式)是一个好的设计。相反,设计模型使其易于渲染,并将任何复杂逻辑(如果需要)移到计算新状态的代码中。
结论
总之,amp-list 元素的“src”属性中的新“amp-state:”前缀可以避免在页面加载时进行额外的 API 调用。这将提高初始页面渲染时间,并且在使用 amp-list 时可以避免页面闪烁。
它还简化了以前使用“hidden”属性隐藏和显示 div 和 amp-list 元素的解决方法。它不仅消除了对 div 元素的需求,而且还意味着服务器只需要服务器端渲染 JSON,而不是通常由 amp-list Mustache 模板生成的完整 HTML 标记。这避免了代码冗余。
最终模型通常也会导致更简单的 AMP 标记,因为 AMP 页面中存在良好的关注点分离。按钮只负责更新 AMP 状态,amp-list 始终从 AMP 状态读取,AMP 会协调一系列更新,等等。
与往常一样,如果您在渲染 AMP 中的动态内容时遇到任何问题或功能请求,请告诉我们!
作者:Alan Kent,Google 开发者倡导者