迁移到新版地点自动补全

欧洲经济区 (EEA) 开发者

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

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

自动补全编程接口

下表列出了一些主要差异,这些差异涉及在 地点自动补全服务(旧版)自动补全 数据 API(新版)之间使用编程方式实现地点自动补全功能:

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

新旧版自动补全 API 均使用以下内容:

代码比较(程序化)

本部分比较了自动补全代码,以说明地点服务和 Place 类(适用于程序化接口)之间的差异。

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

借助旧版地点服务,您可以通过编程方式检索自动补全预测结果,从而比 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

下表列出了一些主要差异,这些差异涉及在地点服务(旧版)和 Place 类(新版)之间使用自动补全微件:

地点服务(旧版) 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)

本部分比较了自动补全代码,以说明旧版地点自动补全 widget 和新版地点自动补全元素之间的差异。

地点自动补全 widget(旧版)

地点服务提供了两种自动补全 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);
  });
}

地点自动补全 widget(新版)

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

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

  • Autocomplete 微件界面针对文本输入占位符、预测列表徽标和地点预测支持区域本地化(包括 RTL 语言)。
  • 增强了无障碍功能,包括对屏幕阅读器和键盘互动的支持。
  • Autocomplete 微件会返回新的 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 ( place ) => {
    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,
  });
}