迁移到新版地点自动补全

地点自动补全是 Maps JavaScript API 中地点库的一项功能。您可以使用自动补全功能让您的应用具有 Google 地图搜索字段的提前键入搜索行为。

本页介绍了旧版和新版地点自动补全功能之间的差异。在这两个版本中,集成自动补全功能有两种常规方法:

自动补全程序化接口

下表列出了在使用程序化地点自动补全功能时,地点自动补全服务(旧版)Autocomplete Data API(新版)之间的一些主要区别:

PlacesService(旧版) Place(新)
地点自动补全服务参考文档 自动补全数据(新)参考文档
AutocompletionRequest AutocompleteRequest
AutocompleteService.getPlacePredictions AutocompleteSuggestion.fetchAutocompleteSuggestions
AutocompletePrediction PlacePrediction
方法需要使用回调来处理结果对象和 PlacesServiceStatus 响应。 使用 Promise,并以异步方式运行。
方法需要进行 PlacesServiceStatus 检查。 无需状态检查,可以使用标准错误处理。
创建 Autocomplete 实例时,地点数据字段会设置为选项。 地点数据字段会在稍后调用 fetchFields() 时设置。
支持查询预测(仅限 SearchBox)。 Autocomplete 类不提供查询预测。
仅限于一组固定的地点类型地点数据字段 使用更多地点类型地点数据字段

旧版和新版 Autocomplete API 都使用以下内容:

代码比较(程序化)

本部分比较了自动补全的代码,以说明程序化接口的 Google 地图服务和地点类之间的区别。

检索自动补全联想查询(旧版)

借助旧版地点服务,您可以通过编程方式检索自动补全预测结果,从而比 Autocomplete 类提供的更强大的用户界面控制功能。在以下示例中,系统会针对“par”发出单个请求,其中 AutocompletionRequest 由输入值和一组用于偏向预测的边界组成。该示例会返回 AutocompletePrediction 实例的列表,并显示每个实例的说明。示例函数还会创建一个会话令牌并将其应用于请求。

function init() {
  const placeInfo = document.getElementById("prediction");
  const service = new google.maps.places.AutocompleteService();
  const placesService = new google.maps.places.PlacesService(placeInfo);
  var sessionToken = new google.maps.places.AutocompleteSessionToken();

  // Define request options.
  let request = {
    input: "par",
    sessionToken: sessionToken,
    bounds: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
  }

  // Display the query string.
  const title = document.getElementById("title");
  title.appendChild(
    document.createTextNode('Place predictions for "' + request.input + '":'),
  );

  // Perform the query and display the results.
  const displaySuggestions = function (predictions, status) {
    // Check the status of the Places Service.
    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 placeRequest = {
      placeId: predictions[0].place_id,
      fields: ["name", "formatted_address"],
    };

    placesService.getDetails(placeRequest, (place, status) => {
      if (status == google.maps.places.PlacesServiceStatus.OK && place) {
        placeInfo.textContent = `
          First predicted place: ${place.name} at ${place.formatted_address}`
      }
    });

  };

  // Show the results of the query.
  service.getPlacePredictions(request, displaySuggestions);
}

检索自动补全联想查询(新)

借助新的地点类,您还可以通过编程方式检索自动补全预测结果,从而比 PlaceAutocompleteElement 类提供的更强大的用户界面控制功能。在以下示例中,系统会针对“par”发出单个请求,其中 AutocompleteRequest 由输入值和一组用于偏向预测的边界组成。该示例会返回 placePrediction 实例的列表,并显示每个实例的说明。示例函数还会创建一个会话令牌并将其应用于请求。

async function init() {
  let sessionToken = new google.maps.places.AutocompleteSessionToken();

  // Define request options.
  let request = {
    input: "par",
    sessionToken: sessionToken,
    locationBias: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
  };

  // Display the query string.
  const title = document.getElementById("title");
  title.appendChild(
    document.createTextNode('Place predictions for "' + request.input + '":'),
  );

  // Perform the query and display the results.
  const { suggestions } =
    await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

  const resultsElement = document.getElementById("results");

  for (let suggestion of suggestions) {
    const placePrediction = suggestion.placePrediction;
    const listItem = document.createElement("li");

    listItem.appendChild(
      document.createTextNode(placePrediction.text.text),
    );

    resultsElement.appendChild(listItem);
  }

  // Show the first predicted place.
  let place = suggestions[0].placePrediction.toPlace();

  await place.fetchFields({
    fields: ["displayName", "formattedAddress"],
  });

  const placeInfo = document.getElementById("prediction");

  placeInfo.textContent = `
    First predicted place: ${place.displayName} at ${place.formattedAddress}`
}

地点自动补全 widget

下表列出了使用地点服务(旧版)和地点类(新版)自动补全 widget 的一些主要区别:

地点服务(旧版) 地点(新)
用于地点预测的 Autocomplete 类。 用于地点预测的 PlaceAutocompleteElement 类。
用于查询预测的 SearchBox
Autocomplete 类不提供查询预测。
只有默认的输入占位符文本会本地化。 文本输入占位符、预测列表徽标和地点预测均支持区域本地化。
Widget 使用 setBounds()autocomplete.bindTo() 将搜索范围限制(偏向)到指定边界,并使用 strictBounds 将结果限制到指定边界。 微件使用 locationBias 属性自定义调整结果,将其限定在指定边界内,并使用 locationRestriction 属性将搜索范围限制在指定边界内。
只能使用标准 HTML 输入元素集成 widget。 您可以使用标准 HTML 输入元素或 gmp-place-autocomplete 元素集成微件。
使用该 widget 时,用户可能会请求可能无效的内容(例如“bisneyland”);必须明确处理这种情况。 该 widget 只会针对所提供的建议返回结果,无法针对任意值发出请求;因此,无需处理可能无效的请求。
返回旧版 PlaceResult 实例。 返回 Place 实例。
地点数据字段被设置为 Autocomplete 对象的选项。 当用户进行选择并调用 fetchFields() 时,系统会设置地点数据字段。
仅限于一组固定的地点类型地点数据字段 使用更多地点类型地点数据字段

代码比较(微件)

本部分比较了自动补全功能的代码,以说明旧版地点自动补全微件与新版地点自动补全元素之间的区别。

地点自动补全 widget(旧版)

地点服务提供了两种自动补全 widget,您可以使用 AutocompleteSearchBox 类添加它们。每种类型的 widget 都可以作为地图控件添加到地图中,也可以直接嵌入到网页中。以下代码示例展示了如何将 Autocomplete 微件作为地图控件嵌入。

  • Autocomplete widget 构造函数有两个参数:
    • 一个是 text 类型的 HTML input 元素。这是自动补全服务将监控并将其结果附于其中的输入字段。
    • 一个可选的 AutocompleteOptions 参数,您可以在其中指定用于约束查询的其他选项。
  • 如需设置边界,可以通过调用 autocomplete.bindTo()Autocomplete 实例显式绑定到地图。
  • 在自动补全选项中指定地点数据字段。
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.749933, lng: -73.98633 },
    zoom: 13,
    mapTypeControl: false,
  });
  const card = document.getElementById("pac-card");
  const input = document.getElementById("pac-input");
  const options = {
    fields: ["formatted_address", "geometry", "name"],
    strictBounds: false,
  };

  map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

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

  // Bind the map's bounds (viewport) property to the autocomplete object,
  // so that the autocomplete requests use the current map bounds for the
  // bounds option in the request.
  autocomplete.bindTo("bounds", map);

  const infowindow = new google.maps.InfoWindow();
  const infowindowContent = document.getElementById("infowindow-content");

  infowindow.setContent(infowindowContent);

  const marker = new google.maps.Marker({
    map,
    anchorPoint: new google.maps.Point(0, -29),
  });

  autocomplete.addListener("place_changed", () => {
    infowindow.close();
    marker.setVisible(false);

    const place = autocomplete.getPlace();

    if (!place.geometry || !place.geometry.location) {
      // User entered the name of a Place that was not suggested and
      // pressed the Enter key, or the Place Details request failed.
      window.alert("No details available for input: '" + place.name + "'");
      return;
    }

    // If the place has a geometry, then present it on a map.
    if (place.geometry.viewport) {
      map.fitBounds(place.geometry.viewport);
    } else {
      map.setCenter(place.geometry.location);
      map.setZoom(17);
    }

    marker.setPosition(place.geometry.location);
    marker.setVisible(true);
    infowindowContent.children["place-name"].textContent = place.name;
    infowindowContent.children["place-address"].textContent =
      place.formatted_address;
    infowindow.open(map, marker);
  });
}

地点自动补全 widget(新)

Place 类提供了 PlaceAutocompleteElement,这是一个 HTMLElement 子类,提供的界面组件可作为地图控件添加到地图中,或直接嵌入到网页中。以下代码示例展示了如何将 PlaceAutocompleteElement 微件嵌入为地图控件。

地点自动补全微件在以下方面得到了改进:

  • Autocomplete widget 界面针对文本输入占位符、预测列表徽标和地点预测支持区域本地化(包括 RTL 语言)。
  • 增强了无障碍功能,包括对屏幕阅读器和键盘互动的支持。
  • Autocomplete widget 会返回新的 Place 类,以简化对返回对象的处理。
  • 为移动设备和小屏幕设备提供更好的支持。
  • 更出色的性能和改进的图形外观。

主要实现差异包括:

  • Autocomplete 类不支持查询预测。
  • PlaceAutocompleteElement 是使用 PlaceAutocompleteElementOptions 构造的。
  • 地点数据字段是在选择时(调用 fetchFields() 时)指定的。
  • 使用 locationBoundslocationRestriction 选项设置边界。
  • 使用 id 属性(从 HTMLElement 继承)将 PlaceAutocompleteElement 与 HTML 文本输入元素相关联。
let map;
let marker;
let infoWindow;

async function initMap() {
  // Request needed libraries.
  const [{ Map }, { AdvancedMarkerElement }] = await Promise.all([
    google.maps.importLibrary("marker"),
    google.maps.importLibrary("places"),
  ]);

  // Initialize the map.
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.749933, lng: -73.98633 },
    zoom: 13,
    mapId: "4504f8b37365c3d0",
    mapTypeControl: false,
  });

  const placeAutocomplete =
    new google.maps.places.PlaceAutocompleteElement({
      locationRestriction: map.getBounds(),
    });

  placeAutocomplete.id = "place-autocomplete-input";
  const card = document.getElementById("place-autocomplete-card");

  card.appendChild(placeAutocomplete);
  map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

  // Create the marker and infowindow.
  marker = new google.maps.marker.AdvancedMarkerElement({
    map,
  });
  infoWindow = new google.maps.InfoWindow({});

  // Add the gmp-placeselect listener, and display the results on the map.
  placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => {
    await place.fetchFields({
      fields: ["displayName", "formattedAddress", "location"],
    });
    // If the place has a geometry, then present it on a map.
    if (place.viewport) {
      map.fitBounds(place.viewport);
    } else {
      map.setCenter(place.location);
      map.setZoom(17);
    }

    let content =
      '<div id="infowindow-content">' +
      '<span id="place-displayname" class="title">' +
      place.displayName +
      '</span><br />' +
      '<span id="place-address">' +
      place.formattedAddress +
      '</span>' +
      '</div>';

    updateInfoWindow(content, place.location);
    marker.position = place.location;
  });
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
  infoWindow.setContent(content);
  infoWindow.setPosition(center);
  infoWindow.open({
    map,
    anchor: marker,
    shouldFocus: false,
  });
}