地点自动补全

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。
选择平台Android iOS JavaScript Web 服务

简介

自动补全是 Maps JavaScript API 中地点库的一项功能。借助自动补全,您可以让自己的应用具有 Google 地图搜索字段的“即输即找”功能。自动补全服务可以根据完整字词和子字符串进行匹配,从而解析地点名称、地址和 Plus Codes。这样,应用就可以在用户输入内容时发送查询,从而即时进行地点预测。

开始使用

在使用 Maps JavaScript API 中的地点库之前,请先确保在 Google Cloud 控制台中针对您为 Maps JavaScript API 设置的同一项目启用了 Places API。

若要查看已启用的 API 列表,请按以下步骤操作:

  1. 前往 Google Cloud 控制台
  2. 点击选择项目按钮,选择您为 Maps JavaScript API 设置的同一项目,然后点击打开
  3. 信息中心上的 API 列表中,查找 Places API
  4. 如果您在列表中看到该 API,就说明一切就绪。如果其中未列出该 API,请执行以下操作将其启用:
    1. 在页面顶部,选择启用 API 以显示标签页。或者,您也可以从左侧菜单中选择
    2. 搜索 Places API,然后从结果列表中选择它。
    3. 选择启用。该过程完成后,Places API 即会显示在信息中心上的 API 列表中。

加载该库

地点服务是一个独立于 Maps JavaScript API 主代码的自足库。如需使用此库中包含的功能,您必须先在 Maps API 引导程序网址中使用 libraries 参数加载该库。

<script async
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap">
</script>

如需了解详情,请参阅库概览

类摘要

此 API 提供了两种自动补全 widget,您可以分别通过 AutocompleteSearchBox 类添加它们。此外,您还可以使用 AutocompleteService 类以编程方式检索自动补全结果(请参阅 Maps JavaScript API 参考文档中的 AutocompleteService 类)。

下面对可用的类进行了简要介绍:

  • Autocomplete 用于向网页中添加一个文本输入字段,并监控该字段中是否输入了字符。随着用户输入文本,Autocomplete 会以一个下拉选择列表的形式返回地点预测结果。当用户从该列表中选择某个地点后,系统会将该地点的相关信息返回给 Autocomplete 对象,以供您的应用检索。如需了解详情,请参阅下文
    一个带选择列表的自动补全文本字段,随着用户输入搜索查询,此列表中会自动提供地点预测结果。
    图 1:自动补全文本字段和选择列表
    一个已填写完毕的地址表单。
    图 2:已填写完毕的地址表单
  • SearchBox 会向您的网页添加文本输入字段,添加方式与 Autocomplete 大致相同。具体区别如下:
    • 主要区别在于选择列表中所显示的结果。SearchBox 会提供更长的预测结果列表,其中可能包括地点(Places API 所定义的地点)以及建议的搜索字词。例如,如果用户输入“北京烤”,选择列表中可能包含词组“北京烤鸭”,以及各种烤鸭店的名称。
    • SearchBox 提供的用于限制搜索范围的选项少于 Autocomplete。对于前者,您可以使搜索偏向于给定的 LatLngBounds。对于后者,您可以将搜索范围限定在特定国家/地区和特定类型的地点,并设置边界。如需了解详情,请参阅下文
    一个已填写完毕的地址表单。
    图 3:SearchBox 显示了一些搜索字词和地点预测结果。
    如需了解详情,请参阅下文
  • 您可以创建一个 AutocompleteService 对象,以编程方式检索预测结果。调用 getPlacePredictions() 可检索匹配的地点,也可调用 getQueryPredictions() 来检索匹配的地点以及建议的搜索字词。注意:AutocompleteService 不会添加任何界面控件。相反,上述方法将返回一个包含预测对象的数组。每个预测对象均包含预测结果的文本、参考信息以及有关该结果如何与用户输入的内容相匹配的详细信息。如需了解详情,请参阅下文

添加 Autocomplete widget

Autocomplete widget 会在网页上创建一个文本输入字段,在界面选择列表中提供地点预测,并返回位置详细信息以响应 getPlace() 请求。选择列表中的每个条目都对应于一个地点(由 Places API 定义)。

Autocomplete 构造函数有两个参数:

  • 一个是 text 类型的 HTML input 元素。自动补全服务将监控这个输入字段,并向该字段附加其搜索结果。
  • 另一个是 AutocompleteOptions 参数(可选),它可能包含以下属性:
    • 一个由数据 fields 构成的数组,该数组要包含在用户所选的 PlaceResultPlace Details 响应中。如果未设置该属性或者传入的是 ['ALL'],系统会返回所有可用字段并据此计费(不建议用于生产环境中的部署)。如需查看字段列表,请参阅 PlaceResult
    • 一个由 types 构成的数组,用于指定某种明确的类型或某个类型集合,具体见支持的类型中所列的类型。如果未指定任何类型,系统将返回所有类型。
    • bounds 是一个 google.maps.LatLngBounds 对象,用于指定搜索地点的区域范围。结果偏向于(但不限于)这些边界中包含的地点。
    • strictBounds 是一个 boolean,用于指定 API 是否只能返回严格位于由指定 bounds 定义的区域内的地点。此 API 不会返回该区域以外的结果,即使结果与用户输入匹配也是如此。
    • componentRestrictions 可用于将结果限制在特定群组。目前,您可以使用 componentRestrictions 按国家/地区(最多 5 个)进行过滤。国家/地区必须以兼容 ISO 3166-1 Alpha-2 的双字符国家/地区代码形式传递。您必须以国家/地区代码列表的形式传递多个国家/地区。

      注意:如果您使用国家/地区代码传递国家/地区时收到意外结果,请确认您使用的代码是否包含您要定位的国家/地区、附属地区以及特殊地理位置区域。如需了解代码相关信息,请参阅维基百科:ISO 3166 国家/地区代码列表或访问 ISO 在线浏览平台

    • placeIdOnly 可用于指示 Autocomplete widget 仅检索地点 ID。针对 Autocomplete 对象调用 getPlace() 时,提供的 PlaceResult 将仅设置 place idtypesname 属性。您可以使用返回的地点 ID 调用地点、地理编码、路线或距离矩阵服务。

限制自动补全预测结果

默认情况下,地点自动补全服务会显示所有地点类型(偏向于用户所在位置附近的预测结果),并提取用户所选地点的所有可用数据字段。设置地点自动补全选项,以根据您的用例提供更相关的预测结果。

在构建时设置选项

Autocomplete 构造函数接受 AutocompleteOptions 参数,以便在创建 widget 时设置限制条件。以下示例设置了 boundscomponentRestrictionstypes 选项来请求 establishment 类型地点,除了偏向于显示指定地理区域内的地点,还会将预测结果限制为美国境内的地点。设置 fields 选项可指定返回哪些与用户所选地点相关的信息。

调用 setOptions() 以更改现有 widget 的选项值。

TypeScript

const center = { lat: 50.064192, lng: -130.605469 };
// Create a bounding box with sides ~10km away from the center point
const defaultBounds = {
  north: center.lat + 0.1,
  south: center.lat - 0.1,
  east: center.lng + 0.1,
  west: center.lng - 0.1,
};
const input = document.getElementById("pac-input") as HTMLInputElement;
const options = {
  bounds: defaultBounds,
  componentRestrictions: { country: "us" },
  fields: ["address_components", "geometry", "icon", "name"],
  strictBounds: false,
  types: ["establishment"],
};

const autocomplete = new google.maps.places.Autocomplete(input, options);

JavaScript

const center = { lat: 50.064192, lng: -130.605469 };
// Create a bounding box with sides ~10km away from the center point
const defaultBounds = {
  north: center.lat + 0.1,
  south: center.lat - 0.1,
  east: center.lng + 0.1,
  west: center.lng - 0.1,
};
const input = document.getElementById("pac-input");
const options = {
  bounds: defaultBounds,
  componentRestrictions: { country: "us" },
  fields: ["address_components", "geometry", "icon", "name"],
  strictBounds: false,
  types: ["establishment"],
};
const autocomplete = new google.maps.places.Autocomplete(input, options);

指定数据字段

指定数据字段,以免为不需要的地点数据 SKU 付费。在传递给 widget 构造函数的 AutocompleteOptions 中添加 fields 属性(如上例所示),或对现有的 Autocomplete 对象调用 setFields()

autocomplete.setFields(["place_id", "geometry", "name"]);

定义自动补全功能的偏向和搜索区域边界

您可以通过以下几种方式使自动补全结果偏向于某个大致位置或区域:

  • 在创建 Autocomplete 对象时设置边界。
  • 更改现有 Autocomplete 的边界。
  • 将边界设置为地图的视口。
  • 将搜索范围限制在边界内。
  • 将搜索范围限制在特定国家/地区内。

上面的示例展示了如何在创建时设置边界。以下示例展示了其他自定义调整技巧。

更改现有 Autocomplete 的边界

调用 setBounds() 以将现有 Autocomplete 的搜索区域更改为矩形边界。

TypeScript

const southwest = { lat: 5.6108, lng: 136.589326 };
const northeast = { lat: 61.179287, lng: 2.64325 };
const newBounds = new google.maps.LatLngBounds(southwest, northeast);

autocomplete.setBounds(newBounds);

JavaScript

const southwest = { lat: 5.6108, lng: 136.589326 };
const northeast = { lat: 61.179287, lng: 2.64325 };
const newBounds = new google.maps.LatLngBounds(southwest, northeast);

autocomplete.setBounds(newBounds);
将边界设置为地图的视口

使用 bindTo() 可以使结果偏向于地图的视口,即使该视口发生变化也是如此。

TypeScript

autocomplete.bindTo("bounds", map);

JavaScript

autocomplete.bindTo("bounds", map);

使用 unbind() 可将解除自动补全预测结果与地图视口的绑定。

TypeScript

autocomplete.unbind("bounds");
autocomplete.setBounds({ east: 180, west: -180, north: 90, south: -90 });

JavaScript

autocomplete.unbind("bounds");
autocomplete.setBounds({ east: 180, west: -180, north: 90, south: -90 });

查看示例

将搜索范围限制在当前边界内

设置 strictBounds 选项即可将结果范围限制在当前边界内,无论是基于地图视口还是矩形边界。

autocomplete.setOptions({ strictBounds: true });
将预测结果限制在特定国家/地区内

使用 componentRestrictions 选项或调用 setComponentRestrictions(),即可将自动补全搜索范围限制在特定的国家/地区(最多五个)组合内。

TypeScript

autocomplete.setComponentRestrictions({
  country: ["us", "pr", "vi", "gu", "mp"],
});

JavaScript

autocomplete.setComponentRestrictions({
  country: ["us", "pr", "vi", "gu", "mp"],
});

查看示例

限制地点类型

使用 types 选项或调用 setTypes() 即可将预测结果限制为特定地点类型。此限制条件会指定某个类型或类型集合,如地点类型中所列。如果未指定任何限制条件,系统将返回所有类型。

对于 types 选项的值或传递给 setTypes() 的值,您可以指定以下任何一项:

  • 一个数组,最多可包含地点类型一文中表 1表 2 中的五个值。例如:

    types: ['hospital', 'pharmacy', 'bakery', 'country']

    或者:

    autocomplete.setTypes(['hospital', 'pharmacy', 'bakery', 'country']);
  • 地点类型一文中表 3 中的任意一个过滤条件。您只能指定表 3 中的一个值。

如果出现以下情况,该请求将被拒绝:

  • 指定了超过五种类型。
  • 指定了任何无法识别的类型。
  • 表 1表 2 中的任意类型与表 3 中的任意过滤条件搭配使用。

地点自动补全演示展示了不同地点类型在预测结果方面的差异。

查看演示

获取地点信息

当用户从附加到自动补全文本字段的预测结果中选择某个地点时,该服务会触发 place_changed 事件。如需获取地点详情,请执行以下操作:

  1. place_changed 事件创建事件处理脚本,并针对 Autocomplete 对象调用 addListener() 以添加该处理脚本。
  2. 针对 Autocomplete 对象调用 Autocomplete.getPlace(),以检索 PlaceResult 对象,然后可以使用该对象获取有关所选地点的更多信息。

默认情况下,当用户选择某个地点时,自动补全功能会返回所选地点的所有可用数据字段,系统将根据情况计费。使用 Autocomplete.setFields() 指定要返回的地点数据字段。详细了解 PlaceResult 对象,包括您可以请求的地点数据字段列表。为了避免为不需要的数据付费,请务必使用 Autocomplete.setFields() 以仅指定您要使用的地点数据。

name 属性包含地点自动补全预测结果中的 description。如需详细了解 description,请参阅地点自动补全文档

对于地址表单,获取结构化格式的地址会很有用。若要返回所选地点的结构化地址,请调用 Autocomplete.setFields() 并指定 address_components 字段。

以下示例使用自动补全功能来填写地址表单中的字段。

TypeScript

function fillInAddress() {
  // Get the place details from the autocomplete object.
  const place = autocomplete.getPlace();
  let address1 = "";
  let postcode = "";

  // Get each component of the address from the place details,
  // and then fill-in the corresponding field on the form.
  // place.address_components are google.maps.GeocoderAddressComponent objects
  // which are documented at http://goo.gle/3l5i5Mr
  for (const component of place.address_components as google.maps.GeocoderAddressComponent[]) {
    // @ts-ignore remove once typings fixed
    const componentType = component.types[0];

    switch (componentType) {
      case "street_number": {
        address1 = `${component.long_name} ${address1}`;
        break;
      }

      case "route": {
        address1 += component.short_name;
        break;
      }

      case "postal_code": {
        postcode = `${component.long_name}${postcode}`;
        break;
      }

      case "postal_code_suffix": {
        postcode = `${postcode}-${component.long_name}`;
        break;
      }

      case "locality":
        (document.querySelector("#locality") as HTMLInputElement).value =
          component.long_name;
        break;

      case "administrative_area_level_1": {
        (document.querySelector("#state") as HTMLInputElement).value =
          component.short_name;
        break;
      }

      case "country":
        (document.querySelector("#country") as HTMLInputElement).value =
          component.long_name;
        break;
    }
  }

  address1Field.value = address1;
  postalField.value = postcode;

  // After filling the form with address components from the Autocomplete
  // prediction, set cursor focus on the second address line to encourage
  // entry of subpremise information such as apartment, unit, or floor number.
  address2Field.focus();
}

JavaScript

function fillInAddress() {
  // Get the place details from the autocomplete object.
  const place = autocomplete.getPlace();
  let address1 = "";
  let postcode = "";

  // Get each component of the address from the place details,
  // and then fill-in the corresponding field on the form.
  // place.address_components are google.maps.GeocoderAddressComponent objects
  // which are documented at http://goo.gle/3l5i5Mr
  for (const component of place.address_components) {
    // @ts-ignore remove once typings fixed
    const componentType = component.types[0];

    switch (componentType) {
      case "street_number": {
        address1 = `${component.long_name} ${address1}`;
        break;
      }

      case "route": {
        address1 += component.short_name;
        break;
      }

      case "postal_code": {
        postcode = `${component.long_name}${postcode}`;
        break;
      }

      case "postal_code_suffix": {
        postcode = `${postcode}-${component.long_name}`;
        break;
      }
      case "locality":
        document.querySelector("#locality").value = component.long_name;
        break;
      case "administrative_area_level_1": {
        document.querySelector("#state").value = component.short_name;
        break;
      }
      case "country":
        document.querySelector("#country").value = component.long_name;
        break;
    }
  }

  address1Field.value = address1;
  postalField.value = postcode;
  // After filling the form with address components from the Autocomplete
  // prediction, set cursor focus on the second address line to encourage
  // entry of subpremise information such as apartment, unit, or floor number.
  address2Field.focus();
}

window.initAutocomplete = initAutocomplete;

查看示例

自定义占位符文本

默认情况下,由自动补全服务创建的文本字段包含标准的占位符文本。如需修改文本,请在 input 元素上设置 placeholder 属性:

<input id="searchTextField" type="text" size="50" placeholder="Anything you want!">

请注意:默认的占位符文本会自动本地化。如果您指定自己的占位值,则必须在应用中对该值进行本地化处理。如需了解 Google Maps JavaScript API 如何选择要使用的语言,请参阅有关本地化的文档。

如需自定义 widget 的外观,请参阅设置 Autocomplete 和 SearchBox widget 的样式

SearchBox 允许用户执行基于文本的地理位置搜索,例如“北京烤鸭”或“王府井百货”。您可以将 SearchBox 附加到某个文本字段,当用户输入文本时,该服务将通过下拉选择列表的形式返回预测结果。

SearchBox 会提供一个详细的预测结果列表,其中可能包括地点(如 Places API 所定义)以及建议的搜索字词。例如,如果用户输入“北京烤”,选择列表中可能包含词组“北京烤鸭”,以及各种烤鸭店的名称。当用户从该列表中选择某个地点后,系统会将该地点的相关信息将返回给搜索框对象,以供您的应用检索。

SearchBox 构造函数有两个参数:

  • 一个是 text 类型的 HTML input 元素。SearchBox 服务将监视这个输入字段,并向其附加搜索结果。
  • 另一个是 options 参数,其中包含 bounds 属性:bounds 是一个 google.maps.LatLngBounds 对象,用于指定要在其中搜索地点的区域范围。结果偏向于(但不限于)这些边界中包含的地点。

以下代码使用 bounds 参数将结果偏向于通过纬度/经度坐标指定的特定地理区域内的地点。

var defaultBounds = new google.maps.LatLngBounds(
  new google.maps.LatLng(-33.8902, 151.1759),
  new google.maps.LatLng(-33.8474, 151.2631));

var input = document.getElementById('searchTextField');

var searchBox = new google.maps.places.SearchBox(input, {
  bounds: defaultBounds
});

更改 SearchBox 的搜索区域

如需更改现有 SearchBox 的搜索区域,请针对 SearchBox 对象调用 setBounds(),并传递相关的 LatLngBounds 对象。

查看示例

获取地点信息

当用户从附加到搜索框的预测结果中选择某一项时,该服务会触发 places_changed 事件。您可以针对 SearchBox 对象调用 getPlaces(),以检索包含多个预测结果的数组,其中每个预测结果都是一个 PlaceResult 对象。

如需详细了解 PlaceResult 对象,请参阅有关地点详情结果的文档。

TypeScript

// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener("places_changed", () => {
  const places = searchBox.getPlaces();

  if (places.length == 0) {
    return;
  }

  // Clear out the old markers.
  markers.forEach((marker) => {
    marker.setMap(null);
  });
  markers = [];

  // For each place, get the icon, name and location.
  const bounds = new google.maps.LatLngBounds();

  places.forEach((place) => {
    if (!place.geometry || !place.geometry.location) {
      console.log("Returned place contains no geometry");
      return;
    }

    const icon = {
      url: place.icon as string,
      size: new google.maps.Size(71, 71),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(17, 34),
      scaledSize: new google.maps.Size(25, 25),
    };

    // Create a marker for each place.
    markers.push(
      new google.maps.Marker({
        map,
        icon,
        title: place.name,
        position: place.geometry.location,
      })
    );

    if (place.geometry.viewport) {
      // Only geocodes have viewport.
      bounds.union(place.geometry.viewport);
    } else {
      bounds.extend(place.geometry.location);
    }
  });
  map.fitBounds(bounds);
});

JavaScript

// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener("places_changed", () => {
  const places = searchBox.getPlaces();

  if (places.length == 0) {
    return;
  }

  // Clear out the old markers.
  markers.forEach((marker) => {
    marker.setMap(null);
  });
  markers = [];

  // For each place, get the icon, name and location.
  const bounds = new google.maps.LatLngBounds();

  places.forEach((place) => {
    if (!place.geometry || !place.geometry.location) {
      console.log("Returned place contains no geometry");
      return;
    }

    const icon = {
      url: place.icon,
      size: new google.maps.Size(71, 71),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(17, 34),
      scaledSize: new google.maps.Size(25, 25),
    };

    // Create a marker for each place.
    markers.push(
      new google.maps.Marker({
        map,
        icon,
        title: place.name,
        position: place.geometry.location,
      })
    );
    if (place.geometry.viewport) {
      // Only geocodes have viewport.
      bounds.union(place.geometry.viewport);
    } else {
      bounds.extend(place.geometry.location);
    }
  });
  map.fitBounds(bounds);
});

查看示例

如需自定义 widget 的外观,请参阅设置 Autocomplete 和 SearchBox widget 的样式

以程序化方式检索地点自动补全服务预测结果

若要以程序化方式检索预测结果,请使用 AutocompleteService 类。AutocompleteService 不会添加任何界面控件。相反,它将返回一个包含预测对象的数组,每个对象均包含预测文本、参考信息以及结果如何与用户输入相匹配的详细信息。与上述 AutocompleteSearchBox 提供的界面控制方法相比,通过此方法可以更有效地控制界面。

AutocompleteService 提供了以下方法:

  • getPlacePredictions() 会返回地点预测。注意:如 Places API 所定义,“地点”可以是某个场所、地理位置或重要的地图注点。
  • getQueryPredictions() 会返回一个详细的预测结果列表,其中可能包括地点(如 Places API 所定义)以及建议的搜索字词。例如,如果用户输入“北京烤”,选择列表中可能包含词组“北京烤鸭”,以及各种烤鸭店的名称。

上述两种方法会通过下列形式返回一个包含预测对象的数组:

  • description 是指匹配的预测结果。
  • distance_meters 是指地点与指定的 AutocompletionRequest.origin 之间的距离(以米为单位)。
  • matched_substrings 在说明中包含一组子字符串,这些子字符串与用户输入中的元素相匹配。这对于在您的应用中突出显示这些子字符串非常有用。在很多情况下,查询会以说明字段的子字符串形式显示。
    • length 是指子字符串的长度。
    • offset 是指从说明字符串的开头(即匹配的子字符串出现的位置)测量的字符偏移量。
  • place_id 是指用于唯一标识地点的文本标识符。如需检索地点的相关信息,请在“地点详情”请求placeId 字段中传递此标识符。详细了解如何通过地点 ID 引用地点
  • terms 是指包含查询元素的数组。对于地点,每个元素通常都构成地址的一部分。
    • offset 是指从说明字符串的开头(即匹配的子字符串出现的位置)测量的字符偏移量。
    • value 是指匹配字词。

以下示例针对词组“北京烤”执行了一次预测请求,并在列表中显示结果。

TypeScript

// This example retrieves autocomplete predictions programmatically from the
// autocomplete service, and displays them as an HTML list.
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initService(): void {
  const displaySuggestions = function (
    predictions: google.maps.places.QueryAutocompletePrediction[] | null,
    status: google.maps.places.PlacesServiceStatus
  ) {
    if (status != google.maps.places.PlacesServiceStatus.OK || !predictions) {
      alert(status);
      return;
    }

    predictions.forEach((prediction) => {
      const li = document.createElement("li");

      li.appendChild(document.createTextNode(prediction.description));
      (document.getElementById("results") as HTMLUListElement).appendChild(li);
    });
  };

  const service = new google.maps.places.AutocompleteService();

  service.getQueryPredictions({ input: "pizza near Syd" }, displaySuggestions);
}

declare global {
  interface Window {
    initService: () => void;
  }
}
window.initService = initService;

JavaScript

// This example retrieves autocomplete predictions programmatically from the
// autocomplete service, and displays them as an HTML list.
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initService() {
  const displaySuggestions = function (predictions, status) {
    if (status != google.maps.places.PlacesServiceStatus.OK || !predictions) {
      alert(status);
      return;
    }

    predictions.forEach((prediction) => {
      const li = document.createElement("li");

      li.appendChild(document.createTextNode(prediction.description));
      document.getElementById("results").appendChild(li);
    });
  };

  const service = new google.maps.places.AutocompleteService();

  service.getQueryPredictions({ input: "pizza near Syd" }, displaySuggestions);
}

window.initService = initService;

CSS

HTML

<html>
  <head>
    <title>Retrieving Autocomplete Predictions</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <p>Query suggestions for 'pizza near Syd':</p>
    <ul id="results"></ul>
    <!-- Replace Powered By Google image src with self hosted image. https://developers.google.com/maps/documentation/places/web-service/policies#other_attribution_requirements -->
    <img
      class="powered-by-google"
      src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png"
      alt="Powered by Google"
    />

    <!-- 
     The `defer` attribute causes the callback to execute after the full HTML
     document has been parsed. For non-blocking uses, avoiding race conditions,
     and consistent behavior across browsers, consider loading using Promises
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initService&libraries=places&v=weekly"
      defer
    ></script>
  </body>
</html>

试用示例

查看示例

会话令牌

AutocompleteService.getPlacePredictions() 使用会话令牌将“自动补全”请求组合到一起,以便进行结算。会话令牌将用户自动补全搜索的查询和选择阶段归入不同的会话,以便进行结算。会话在用户开始输入查询内容时开始,并在用户选择地点时结束。在每个会话中,用户可以输入多项查询内容,并最终选择一个地点。会话结束后,令牌将失效。您的应用必须为每个会话生成一个新的令牌。我们建议您针对所有自动补全会话使用会话令牌。如果您省略 sessionToken 参数或重复使用会话令牌,系统会按未提供会话令牌的情况为会话计费(每个请求均单独结算)。

您可以使用同一会话令牌,针对调用 AutocompleteService.getPlacePredictions() 所获得的地点发出单个地点详情请求。在这种情况下,“自动补全”请求会与“地点详情”请求合并,系统会将调用作为常规“地点详情”请求进行计费。您无需为“自动补全”请求付费。

请务必为每个新会话传递唯一的会话令牌。如果对多个自动补全会话使用同一令牌,这些自动补全会话将会失效,对于无效会话中的所有“自动补全”请求,系统会使用“自动补全 - 按请求结算”SKU 单独计费。详细了解会话令牌

以下示例展示了如何创建会话令牌,然后将其传入 AutocompleteService(为简单起见,省略了 displaySuggestions() 函数):

// Create a new session token.
var sessionToken = new google.maps.places.AutocompleteSessionToken();

// Pass the token to the autocomplete service.
var autocompleteService = new google.maps.places.AutocompleteService();
autocompleteService.getPlacePredictions({
  input: 'pizza near Syd',
  sessionToken: sessionToken
},
displaySuggestions);

请务必为每个新会话传递唯一的会话令牌。针对多个会话使用同一令牌会导致每个请求被单独计费。

详细了解会话令牌

设置 Autocomplete 和 SearchBox widget 的样式

默认情况下,AutocompleteSearchBox 提供的界面元素会经过样式设置,以便纳入 Google 地图。您可能需要调整样式,使其适合自己的网站。您可以使用以下 CSS 类。下面列出的所有类均适用于 AutocompleteSearchBox widget。

适用于 Autocomplete 和 SearchBox widget 的 CSS 类的图解说明
适用于自动补全和搜索框微件的 CSS 类
CSS 类 说明
pac-container 包含由地点自动补全服务返回的预测结果列表的视觉元素。此列表通过下拉列表的形式显示在 AutocompleteSearchBox widget 下方。
pac-icon 预测结果列表中每个条目左侧显示的图标。
pac-item AutocompleteSearchBox widget 提供的预测结果列表中的条目。
pac-item:hover 用户将鼠标指针悬停在其上方的条目。
pac-item-selected 用户通过键盘选中的条目。注意:所选条目将会是此类和 pac-item 类的成员。
pac-item-query pac-item 内的跨度,它是预测结果的主要组成部分。对于地理位置,它包含了地点名称(例如“上海”)或街道名称和门牌号(例如“长安大街 10 号”)。对于基于文本的搜索(例如“北京烤鸭”),它包含了查询的完整文本。默认情况下,pac-item-query 显示为黑色。如果 pac-item 中有任何附加文本,该文本将位于 pac-item-query 之外,并且继承 pac-item 的样式。默认情况下,此类文本会显示为灰色。附加文本通常为地址。
pac-matched 返回的预测结果中与用户输入的内容相匹配的部分。默认情况下,匹配的文本以粗体突出显示。请注意,匹配的文本可能位于 pac-item 中的任何位置。它不一定是 pac-item-query 的一部分,并且有可能一部分位于 pac-item-query 中,同时还有一部分在 pac-item 的剩余文本中。

地点自动补全优化

本部分介绍了帮助您充分利用地点自动补全服务的最佳实践。

下面列出了一些一般准则:

  • 若要开发可正常运行的界面,最快的方式是使用 Maps JavaScript API Autocomplete widget、Places SDK for Android Autocomplete widget 或 Places SDK for iOS 自动补全界面控件
  • 从一开始就了解重要的地点自动补全数据字段
  • 位置自定义调整和位置限制字段是可选的,但可能会对自动补全性能产生重大影响。
  • 使用错误处理可确保您的应用在 API 返回错误时妥善降级。
  • 请确保您的应用可以处理没有选择任何内容的情况,并能够让用户继续操作。

费用优化最佳实践

基本费用优化

为了优化地点自动补全服务的使用费用,请在地点详情和地点自动补全 widget 中使用字段掩码,以便仅返回所需的地点数据字段

高级费用优化

请考虑通过程序化方式实现地点自动补全,以便采用“按请求”定价模式,并请求关于所选地点(而不是地点详情)的 Geocoding API 结果。如果同时满足以下两个条件,与采用“按会话”(基于会话)定价模式相比,将“按请求”定价模式与 Geocoding API 搭配使用的性价比更高:

  • 如果您只需要用户所选地点的纬度/经度或地址,那么采用 Geocoding API 提供此类信息所需的费用会低于调用地点详情。
  • 如果用户平均在不超过四次自动补全预测请求之内选择自动补全预测结果,那么“按请求”定价模式可能会比“按会话”定价模式的性价比更高。
如果在选择符合您需求的地点自动补全实现方面需要帮助,请选择与以下问题的答案相对应的标签页。

除了所选预测结果的地址和纬度/经度外,您的应用是否需要任何其他信息?

是,需要更多详细信息

将基于会话的地点自动补全与地点详情搭配使用
由于您的应用需要地点名称、商家状态或营业时间等地点详情,因此您的地点自动补全实现应使用会话令牌(以程序化方式构建,或内置到 JavaScriptAndroidiOS widget 中),总费用为每次会话 0.017 美元,外加相应的地点数据 SKU 费用(具体取决于您申请的地点数据字段)。1

widget 实现
会话管理功能自动内置于 JavaScriptAndroidiOS widget 中。这包括针对所选预测结果的“地点自动补全”请求和“地点详情”请求。请务必指定 fields 参数,以确保您只请求所需的地点数据字段

程序化实现
在“地点自动补全”请求中使用会话令牌。在请求关于所选预测结果的地点详情时,添加以下参数:

  1. “地点自动补全”响应中的地点 ID
  2. “地点自动补全”请求中使用的会话令牌
  3. fields 参数,用于指定您所需的地点数据字段

否,只需要地址和位置信息

对于您的应用,Geocoding API 可能比地点详情性价比更高,具体取决于您使用地点自动补全的性能。每个应用的自动补全效率各有不同,具体取决于用户输入的内容、使用应用所在的位置,以及是否遵循了性能优化最佳实践

为了回答以下问题,请分析用户在您的应用中选择地点自动补全预测结果之前平均会输入多少个字符。

平均而言,用户是否能够在不超过四次请求之内选择地点自动补全预测结果?

在不使用会话令牌的情况下以程序化方式实现地点自动补全,并针对所选的地点预测调用 Geocoding API。
Geocoding API 提供地址和纬度/经度坐标,价格为每个请求 0.005 美元。发出四次地点自动补全 - 按请求结算请求的费用为 0.01132 美元,因此四次请求加上针对所选地点预测调用 Geocoding API 的总费用将为 0.01632 美元,低于按会话结算的自动补全价格(即每次会话 0.017 美元)。1

您可以考虑采用性能最佳实践,帮助用户以更少的字符找到所需的预测结果。

将基于会话的地点自动补全与地点详情搭配使用
由于您预计在用户选择地点自动补全预测结果之前应用发出的平均请求次数较多,所需费用会超过“按会话”定价模式的费用,因此建议您在实现地点自动补全时,针对“地点自动补全”请求和关联的“地点详情”请求使用会话令牌,总费用为每次会话 0.017 美元。1

widget 实现
会话管理功能自动内置于 JavaScriptAndroidiOS widget 中。这包括针对所选预测结果的“地点自动补全”请求和“地点详情”请求。请务必指定 fields 参数,以确保您只请求基本数据字段。

程序化实现
在“地点自动补全”请求中使用会话令牌。在请求关于所选预测结果的地点详情时,添加以下参数:

  1. “地点自动补全”响应中的地点 ID
  2. “地点自动补全”请求中使用的会话令牌
  3. fields 参数,用于指定地址和几何图形等基本数据字段

考虑延迟“地点自动补全”请求
您可以采取一些策略,例如延迟“地点自动补全”请求,直到用户输入前三个或四个字符,从而减少应用发出的请求数量。例如,在用户输入第三个字符后针对每个字符发出“地点自动补全”请求,也就是说,如果用户输入七个字符,然后选择了您发出一次 Geocoding API 请求所获得的预测结果,总费用将为:0.01632 美元(4 * 0.00283 美元 [自动补全 - 按请求结算] + 0.005 美元 [地理编码])。1

如果延迟请求会导致平均程序化请求次数低于四次,您可以按照使用 Geocoding API 提高地点自动补全性能的实现指南操作。请注意,如果用户希望每次输入新的字符后都能看到预测结果,可能会将延迟请求视为时间上的延迟。

您可以考虑采用性能最佳实践,帮助用户以较少的字符找到所需的预测结果。


  1. 此处所列的费用以美元为单位。如需了解完整的定价信息,请参阅 Google Maps Platform 结算页面。

性能最佳实践

下面的指南介绍了优化地点自动补全性能的方式:

  • 向地点自动补全实现添加国家/地区限制、位置自定义调整和语言偏好设置(适用于程序化实现)。您无需为 widget 进行语言偏好设置,因为它们会从用户的浏览器或移动设备中选择语言偏好设置。
  • 如果地点自动补全附有地图,您可以根据地图视口来设置位置偏向。
  • 如果用户未选择任一自动补全预测结果,通常是因为这些预测结果都不是所需的结果地址,您可以重复使用原始用户输入来尝试获取更相关的结果: 适合回退到 Geocoding API 的其他场景包括:
    • 用户输入澳大利亚、新西兰或加拿大以外的国家/地区的 subpremise 地址。例如,自动补全功能不支持美国地址“123 Bowdoin St #456, Boston MA, USA”(自动补全功能仅支持澳大利亚、新西兰和加拿大的 subpremise 地址。这三个国家/地区支持的地址格式包括“9/321 Pitt Street, Sydney, New South Wales, Australia”“14/19 Langana Avenue, Browns Bay, Auckland, New Zealand”或“145-112 Renfrew Dr, Markham, Ontario, Canada”)。
    • 用户在输入地址时,需要输入路段前缀,例如纽约的“23-30 29th St, Queens”或夏威夷考爱岛“47-380 Kamehameha Hwy, Kaneohe”。

用量限额和政策

配额

如需了解配额和定价信息,请参阅 Places API 的用量和结算文档

政策

使用 Maps JavaScript API 地点库时,必须遵守适用于 Places API 的政策