requestAutocomplete

拿走我的钱,不要浪费我的时间

Jake Archibald
Jake Archibald

简介

我喜欢网页版。总的来说,我认为这是一个不错的主意。因此,我经常参与 Web 与原生应用的争论。对方很快就开始谈论通过原生系统付款的便捷性。我通常的回应是扔下烟雾弹,然后疯狂地笑着跑出房间,因为这不是我能赢的争论。移动网站上的购物车放弃率可能高达 97%。想象一下现实世界中的情况。想像一下,超市中 97% 的人,推着满满一购物车他们想买的东西,突然把它们掀翻,然后走出超市。 现在,有些人只是查看商品价格,从来没有购买意向,但糟糕的网购体验是导致这种情况的一个重要原因。我们在向用户收取精神健康税。 想想您在网络上(尤其是在移动设备上)获得过的愉快付款体验。这是应用商店,对吗?或者至少是已拥有您的付款信息的类似封闭式系统。这是一个问题。它要求网站使用用户必须已拥有账号并已登录的特定付款服务提供商,或者使用要求用户登录特定付款服务提供商的平台(例如要求您仅为该平台编写代码的应用商店)。如果您不执行上述任一操作,用户就只能不断点按屏幕或键盘,直到手指皮肤磨损殆尽或放弃为止。 我们需要解决这个问题。

requestAutocomplete

在 WebGL、WebRTC 和其他以“Web”开头的花哨 Web API 的时代,requestAutocomplete 显得并不起眼。不过,它是穿着米色衣服的超级英雄。一个小而无聊的 API,可以刺穿 Web 支付时间吸血鬼的心脏。

不像一些网站依赖特定的支付提供商,该 API 可向浏览器请求付款详细信息,由浏览器代表用户存储这些信息。 Chrome 版本的 requestAutocomplete() 还与 Google 钱包集成,但目前仅适用于美国用户在我们的测试网站上试用

form.requestAutocomplete

表单元素带有一个新方法:requestAutocomplete,用于请求浏览器填充表单。浏览器会向用户显示一个对话框,请求授予权限,并允许用户选择要提供哪些详细信息。您不能随时调用此方法,需要在执行特定互动事件(例如鼠标按下/松开、点击、按键和触摸事件)期间调用此方法。这是出于安全考虑而采取的一项限制措施。

button.addEventListener('click', function(event) {
  form.requestAutocomplete();
  event.preventDefault();
});

// TODO: listen for autocomplete events on the form

在查看事件之前,我们需要确保浏览器能够理解您的表单字段…

表单要求

在互联网还是黑白时代时,Internet Explorer 5 在表单输入元素上采用了新属性 autocomplete。您可以将其设置为“关闭”,以停止浏览器提供建议,仅此而已。此 API 已扩展,因此您无需修改“name”属性即可指定字段的预期内容,而 requestAutocomplete 正是使用此属性将表单字段与用户数据相关联。

<input name="fullname" autocomplete="name">

作为一项规范,requestAutocomplete 并非仅适用于付款,但 Chrome 目前的实现几乎仅适用于付款。未来,浏览器有望能够处理其他类型的数据,希望包括登录详情和密码生成器、护照信息,甚至上传头像。

目前,Chrome 中的 requestAutocomplete 可识别以下内容:

付款

  • 电子邮件
  • cc-name - 持卡人姓名
  • cc-number - 卡号
  • cc-exp-month - 卡到期月份(两位数)
  • cc-exp-year - 卡的到期年份(以四位数表示)
  • cc-csc - 3 到 4 位数的卡安全码
<input type="email" autocomplete="email" name="email">
<input type="text" autocomplete="cc-name" name="card-name">
<input type="text" autocomplete="cc-number" name="card-num">
<input type="text" autocomplete="cc-exp-month" name="card-exp-month">
<input type="text" autocomplete="cc-exp-year" name="card-exp-year">
<input type="text" autocomplete="cc-csc" name="card-csc">

我上面使用的“name”属性只是示例,您无需使用特定值。如果您打算将此表单用于不具备 requestAutocomplete 的用户(这是理想情况),则需要添加标签、布局和基本 HTML5 验证。

您也不局限于输入元素,可以使用任何表单输入类型。例如,您可以为卡片到期日期字段使用 <select>

详细的控制台消息。
详细控制台消息

地址

  • 姓名 - 全名。将全名作为单个字段要比使用多个字段好得多。使用多个字段(例如名字和姓氏)会偏向于西方文化,对其他文化来说可能没有意义,而且在单个字段中输入内容更为方便

  • tel - 包括国家/地区代码的完整电话号码,也可以拆分为

    • tel-country-code - 例如 +44
    • tel-national - 其余
  • street-address - 完整地址,各组成部分以英文逗号分隔,可细分为

    • address-line1
    • address-line2 - 可以为空
  • 地点 - 城市/城镇

  • 地区 - 州代码、郡或州

  • postal-code - 邮政编码

  • country

上述属性应与以下属性结合使用: - 结算 - 配送

<input type="text" autocomplete="billing name" required name="billing-name">
<input type="tel" autocomplete="billing tel" required name="billling-tel">
<input type="text" autocomplete="billing address-line1" required name="billing-address1">
<input type="text" autocomplete="billing address-line2" required name="billing-address2">
<input type="text" autocomplete="billing locality" required name="billing-locality">
<input type="text" autocomplete="billing region" required name="billing-region">
<input type="text" autocomplete="billing postal-code" required name="billing-postal-code">
<select autocomplete="billing country" required name="billing-country">
  <option value="US">United States</option>
  …
</select>

<input type="text" autocomplete="shipping name" name="shipping-name">
…

再次提醒一下,名称属性只是示例,您可以使用任何名称。显然,并非所有表单都应请求提供送货地址,例如,请勿询问我希望将酒店客房送到哪里,因为酒店客房的当前位置通常是卖点。 好的,我们已经有了表单,也知道如何请求 autocompletion。但是…

何时应调用 requestAutocomplete?

理想情况下,您会希望显示 requestAutocomplete 对话框,而不是加载显示结账表单的页面。如果一切顺利,用户应该完全看不到表单。

付款流程

常见的模式是,购物车页面上有一个“结账”按钮,可将您定向至付款详情表单。在这种情况下,您希望在购物车页面上加载结算表单,但要将其隐藏起来,并在用户点击“结账”按钮时对其调用 requestAutocomplete。请注意,您需要通过 SSL 提供购物车页面,以免出现 Skeletor 警告。首先,我们应隐藏结账按钮,以便在准备就绪之前用户无法点击该按钮,但我们只想对使用 JavaScript 的用户执行此操作。因此,在网页的标头中:

<script>document.documentElement.className += ' js';</script>

在 CSS 中:

.js #checkout-button,
#checkout-form.for-autocomplete {
  display: none;
}

我们需要在购物车页面上添加结算表单。此代码可以放在任何位置,上面的 CSS 可确保用户看不到它。

<form id="checkout-form" class="for-autocomplete" action="/checkout" method="post">
  …fields for payment, billing address &amp; shipping if relevant…
</form>

现在,我们的 JavaScript 可以开始设置所有内容:

function enhanceForm() {
  var button = document.getElementById('checkout-button');
  var form = document.getElementById('checkout-form');

  // show the checkout button
  button.style.display = 'block';

  // exit early if there's no requestAutocomplete support
  if (!form.requestAutocomplete) {
    // be sure to show the checkout button so users can
    // access the basic payment form!
    return;
  }

  button.addEventListener('click', function(event) {
    form.requestAutocomplete();
    event.preventDefault();
  });

  // TODO: listen for autocomplete events on the form
}

您可以在购物车页面上调用 enhanceForm,在结账表单和按钮之后的某个时间。支持 requestAutocomplete 的浏览器将获得全新的快速体验,其他浏览器将回退到常规付款表单。 如需获得额外积分,您可能需要在 enhanceForm 中通过 XHR 加载表单 HTML。这意味着,您只能在支持 requestAutocomplete 的浏览器中加载该表单,并且无需记得将该表单添加到可能调用 enhanceForm 的每个网页中。演示网站就是这样运作的。

您已调用 requestAutocomplete,接下来该怎么做?

自动补全流程是异步的,requestAutocomplete 会立即返回。为了了解具体情况,我们会监听几个新事件:

form.addEventListener('autocomplete', function() {
  // hurrah! You got all the data you needed
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    // the form was populated, but it failed html5 validation
    // eg, the data didn't match one of your pattern attributes
  }
  else if (event.reason == 'cancel') {
    // the user aborted the process
  }
  else if (event.reason == 'disabled') {
    // the browser supports requestAutocomplete, but it's not
    // available at this time. Eg, it wasn't called from an
    // interaction event or the page is insecure
  }
});

如果一切顺利,您可以对数据执行任何操作,最简单的做法就是提交表单。然后,服务器可以验证数据,并向用户显示包含运费的确认页面。 如果数据无效,您可以显示表单,并突出显示用户需要修改的字段。或者,您也可以直接提交表单,让常规的服务器端验证接管。 如果用户取消了该流程,您实际上无需执行任何操作。如果该功能已停用,请将用户定向至常规表单。因此,在大多数情况下,监听器会如下所示:

form.addEventListener('autocomplete', function() {
  form.submit();
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    form.submit();
  }
  else if (event.reason != 'cancel') {
    window.location = '/checkout-page/';
  }
});

浏览器会将我的数据存储在哪里?

该规范不会规定数据的存储位置,从而让浏览器能够进行创新。如果您已登录 Chrome,则可以选择将详细信息存储在 Google 钱包中,以便在您已登录的其他设备上访问这些信息。如果您将详细信息存储在 Google 钱包中,requestAutocomplete 将不会处理您的真实卡号,从而提高安全性。如果您未登录 Chrome 或选择不使用 Google 钱包,系统会选择性地将您的详细信息存储在浏览器本地以供重复使用。 目前就是这样,但未来 Chrome 和其他浏览器可能会采用其他付款服务提供商。

轻松付款

每次用户想要购买商品时,都必须反复输入付款信息,这有点荒唐。网站存储您的付款详情会让事情变得更简单,但我有点担心有多少网站存储了我的银行卡详细信息。这正是 Web 标准可以解决的问题。requestAutocomplete 可为整个网络带来一键式付款,无需绑定服务或平台,而且也该是时候了!

额外补充:处理多页表单

最好调用一次 requestAutocomplete 并收集所需的所有数据。如果您无法修改服务器以一次接收所有这些数据,也没关系,您可以从已填写的表单中提取数据,然后使用最适合您的方式提交。 您可以使用以下小巧实用的函数,将当前支持的所有数据作为一个简单的对象捕获,而无需自行创建表单。获取数据后,您可以将其转换为服务器所需的任何格式,并分步发布。

checkoutButton.addEventListener('click', function() {
  requestUserData({
    billing: true,
    shipping: true
  }, function(response) {
    if (response.err == 'cancel') {
      // exit silently
      return;
    }
    if (response.err) {
      // fall back to normal form
      window.location.href = '/normal-checkout-form/';
      return;
    }

    // the rest is just made-up pseudo code as an example
    postToServer(data.shipping).then(function() {
      return postToServer(data.billing);
    }).then(function() {
      return postToServer(data.cc);
    }).catch(function() {
      // handle error
    });
  });
});