AMP

将 AMP 用作 PWA 的数据源

如果您已投资于 AMP 但尚未构建渐进式网络应用,那么您的 AMP 页面可以极大地简化您对渐进式网络应用的开发。在本指南中,您将了解如何在渐进式网络应用中使用 AMP,并将您现有的 AMP 页面用作数据源。

从 JSON 到 AMP

在最常见的场景中,渐进式网络应用程序是一个通过 Ajax 连接到 JSON API 的单页应用程序。然后,此 JSON API 返回数据集来驱动导航,以及用于呈现文章的实际内容。

然后,您将继续进行并将原始内容转换为可用的 HTML,并在客户端上呈现它。此过程成本高昂,且通常难以维护。相反,您可以将已有的 AMP 页面重新用作内容源。最棒的是,AMP 使得只需几行代码即可轻松做到这一点。

在您的渐进式网络应用中包含“影子 AMP”

第一步是在您的渐进式网络应用程序中包含一个我们称为“Shadow AMP”的 AMP 特殊版本。是的,没错 - 您在顶级页面中加载 AMP 库,但它实际上不会控制顶级内容。它只会“放大”您告诉它的页面部分。

在页面的头部中包含 Shadow AMP,如下所示

<!-- Asynchronously load the AMP-with-Shadow-DOM runtime library. -->
<script async src="https://cdn.ampproject.org/shadow-v0.js"></script>

您如何知道影子 AMP API 何时可以使用?

我们建议您使用 async 属性加载 Shadow AMP 库。但是,这意味着您需要使用某种方法来了解库何时完全加载并准备好使用。

要观察的正确信号是全局 AMP 变量的可用性,而 Shadow AMP 使用“异步函数加载方法”来帮助实现这一点。考虑以下代码

(window.AMP = window.AMP || []).push(function(AMP) {
  // AMP is now available.
});

此代码将起作用,并且以这种方式添加的任何数量的回调都将在 AMP 可用时触发,但为什么?

此代码转换为

  1. “如果 window.AMP 不存在,创建一个空数组来代替它”
  2. “然后将一个回调函数推送到数组中,该回调函数应在 AMP 准备就绪时执行”

它之所以起作用,是因为 Shadow AMP 库在实际加载时会意识到 window.AMP 下已经有一个回调数组,然后处理整个队列。如果您稍后再次执行相同的功能,它仍然有效,因为 Shadow AMP 会用它自己和一个自定义的 push 方法替换 window.AMP,该方法只需立即触发回调。

提示 – 为了使上述代码示例实用,我们建议您将其包装到 Promise 中,然后在使用 AMP API 之前始终使用该 Promise。查看我们的 React 演示代码 以获取示例。

在您的渐进式网络应用中处理导航

您仍需要手动执行此步骤。毕竟,由您决定如何导航概念中内容的链接。一些列表?一堆卡片?

在常见场景中,您会获取一些 JSON,它会返回带有某些元数据的已排序 URL。最后,您应该会得到一个函数回调,该回调会在用户点击其中一个链接时触发,并且该回调应包括所请求 AMP 页面的 URL。如果您有此信息,则已准备好执行最后一步。

使用影子 AMP API 内联呈现页面

最后,当您想在用户操作后显示内容时,是时候获取相关的 AMP 文档并让 Shadow AMP 接管了。首先,实现一个函数来获取页面,类似于此函数

function fetchDocument(url) {

  // unfortunately fetch() does not support retrieving documents,
  // so we have to resort to good old XMLHttpRequest.
  var xhr = new XMLHttpRequest();

  return new Promise(function(resolve, reject) {
    xhr.open('GET', url, true);
    xhr.responseType = 'document';
    xhr.setRequestHeader('Accept', 'text/html');
    xhr.onload = function() {
      // .responseXML contains a ready-to-use Document object
      resolve(xhr.responseXML);
    };
    xhr.send();
  });
}

重要提示 – 为了简化上述代码示例,我们跳过了错误处理。您应始终确保以优雅的方式捕获和处理错误。

现在我们有了可用的 Document 对象,是时候让 AMP 接管并渲染它了。获取充当 AMP 文档容器的 DOM 元素的引用,然后调用 AMP.attachShadowDoc(),如下所示

// This can be any DOM element
var container = document.getElementById('container');

// The AMP page you want to display
var url = "https://my-domain/amp/an-article.html";

// Use our fetchDocument method to get the doc
fetchDocument(url).then(function(doc) {
  // Let AMP take over and render the page
  var ampedDoc = AMP.attachShadowDoc(container, doc, url);
});

提示 – 在实际将文档移交给 AMP 之前,正是移除在独立显示 AMP 页面时有意义但不在嵌入模式中有意义的页面元素的最佳时机:例如页脚和页眉。

就是这样!您的 AMP 页面将作为您的整体渐进式网络应用的子项进行渲染。

清理自己

您的用户很可能会在您的渐进式网络应用中从 AMP 导航到 AMP。在放弃先前渲染的 AMP 页面时,请务必告知 AMP,如下所示

// ampedDoc is the reference returned from AMP.attachShadowDoc
ampedDoc.close();

这将告知 AMP 您不再使用此文档,并将释放内存和 CPU 开销。

立即查看

您可以在我们构建的 React 示例 中看到“PWA 中的 AMP”模式的实际应用。它展示了导航期间的平滑过渡,并附带一个简单的 React 组件,该组件封装了上述步骤。它融合了两全其美——渐进式网络应用中的灵活自定义 JavaScript,以及用于驱动内容的 AMP。

您还可以使用 Polymer 框架查看 PWA 和 AMP 样本。该样本使用 amp-viewer 嵌入 AMP 页面。