迁移到新版地点自动补全

欧洲经济区 (EEA) 开发者

地点自动补全是 Maps JavaScript API 中地点库的一项功能。借助自动补全,您可以让自己的应用具有 Google 地图搜索字段的“即输即找”功能。

本页介绍了旧版和新版地点自动补全功能之间的区别。在这两个版本中,集成自动补全功能的方式大致有两种:

自动补全编程接口

下表列出了 Places Autocomplete Service (旧版)Autocomplete Data API(新版)在使用 编程方式的地点自动补全功能时的一些主要区别:

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

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

代码比较(编程方式)

本部分比较了自动补全的代码,以说明 Places Service 和 Place 类(适用于编程接口)之间的区别。

检索自动补全预测结果(旧版)

借助旧版 Places Service,您可以通过编程方式检索自动补全预测结果,从而更好地控制用户界面,而不是像 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);
}

检索自动补全预测结果(新版)

借助新版 Place 类,您也可以通过编程方式检索自动补全预测结果,从而更好地控制用户界面,而不是像 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

下表列出了 Places Service(旧版)和 Place 类(新版)在使用自动补全 widget 时的一些主要区别:

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

代码比较(widget)

本部分比较了地点自动补全的代码,以说明旧版 Place Autocomplete Widget 和新版 Place Autocomplete 元素之间的区别。

地点自动补全微件(旧版)

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

  • 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);
  });
}

地点自动补全微件(新版)

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

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

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

主要实现区别包括:

  • PlaceAutocompleteElement 提供自己的输入字段,并使用 HTML 或 JavaScript 直接插入到页面中(而不是提供现有的输入元素)。
  • Autocomplete 类中没有查询预测。
  • PlaceAutocompleteElement 是使用 PlaceAutocompleteElementOptions 构建的。
    • 地点数据字段是在选择时(调用 fetchFields() 时)指定的。
  • 使用 locationBoundslocationRestriction 选项设置边界。
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-select listener, and display the results on the map.
  placeAutocomplete.addEventListener("gmp-select", async ( event ) => {
    const place = event.placePrediction.toPlace();
    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,
  });
}