遷移至新版 Place Autocomplete

Place Autocomplete 是 Maps JavaScript API Places Library 的功能。您可以運用這項功能,在應用程式中提供 Google 地圖搜尋欄位的預先輸入搜尋功能。

本頁面說明舊版和新版 Place Autocomplete 功能的差異。在兩個版本中,整合自動完成功能的方法有兩種:

自動完成程式輔助介面

下表列出 Places Autocomplete 服務 (舊版)Autocomplete Data API (新版) 之間,使用程式輔助 Place Autocomplete 時的主要差異:

PlacesService (舊版) Place (新版)
Places Autocomplete 服務參考資料 Autocomplete Data (new) 參考資料
AutocompletionRequest AutocompleteRequest
AutocompleteService.getPlacePredictions AutocompleteSuggestion.fetchAutocompleteSuggestions
AutocompletePrediction PlacePrediction
方法必須使用回呼來處理結果物件和 PlacesServiceStatus 回應。 使用 Promise,並以非同步方式運作。
方法需要 PlacesServiceStatus 檢查。 不需要進行狀態檢查,可以使用標準錯誤處理。
建立 Autocomplete 執行個體時,系統會將地點資料欄位設為選項。 地點資料欄位會在稍後呼叫 fetchFields() 時設定。
支援查詢預測功能 (僅限 SearchBox)。 Autocomplete 類別不支援查詢預測功能。
僅限於固定的地點類型地點資料欄位 可存取更多地點類型地點資料欄位

下列項目適用於舊版和新版 Autocomplete API:

程式碼比較 (程式輔助)

本節將比較自動完成功能的程式碼,說明程式介面中 Place 服務和 Place 類別的差異。

擷取自動完成預測結果 (舊版)

舊版 Places 服務可讓您以程式輔助方式擷取自動完成預測結果,藉此進一步控管使用者介面,而非透過 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}`
}

Place 自動完成小工具

下表列出 Places 服務 (舊版) 和 Place 類別 (新版) 之間,使用自動完成小工具時的主要差異:

地點服務 (舊版) 地點 (新版)
Autocomplete 類別,用於地點預測。 PlaceAutocompleteElement 類別,用於地點預測。
SearchBox 類別
:用於查詢預測。
Autocomplete 類別不支援查詢預測功能。
只有預設輸入預留位置文字會本地化。 文字輸入預留位置、預測結果清單標誌和地點預測結果都支援區域本地化。
小工具會使用 setBounds()autocomplete.bindTo() 將搜尋範圍限制 (偏向) 在指定的邊界內,並使用 strictBounds 將結果限制在指定的邊界內。 小工具會使用 locationBias 屬性將結果偏向指定範圍,並使用 locationRestriction 屬性將搜尋範圍限制在指定範圍內。
您只能使用標準 HTML 輸入元素整合小工具。 您可以使用標準 HTML 輸入元素或 gmp-place-autocomplete 元素整合小工具。
使用小工具時,使用者可能會要求無效的內容 (例如「bisneyland」);此情況必須明確處理。 小工具只會傳回提供建議的結果,無法針對任意值發出要求;因此,您不需要處理可能無效的要求。
傳回舊版 PlaceResult 例項。 傳回 Place 例項。
地點資料欄位會設為 Autocomplete 物件的選項。 當使用者選取項目並呼叫 fetchFields() 時,系統會設定地點資料欄位。
僅限於固定的地點類型地點資料欄位 可存取更多地點類型地點資料欄位

程式碼比較 (小工具)

本節將比較自動完成功能的程式碼,說明舊版 Place Autocomplete 小工具和新版 Place Autocomplete 元素之間的差異。

Place Autocomplete 小工具 (舊版)

Places 服務提供兩種 Autocomplete 小工具,您可以使用 AutocompleteSearchBox 類別新增。每種小工具都可以做為地圖控制項加入地圖,或直接嵌入網頁。以下程式碼範例說明如何將 Autocomplete 小工具嵌入為地圖控制項。

  • Autocomplete 小工具建構函式會採用兩個引數:
    • 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 Autocomplete 小工具 (新版)

Place 類別提供 PlaceAutocompleteElement,這是一個 HTMLElement 子類別,可提供可新增至地圖做為地圖控制項,或直接嵌入網頁的 UI 元件。以下程式碼範例說明如何將 PlaceAutocompleteElement 小工具做為地圖控制項嵌入。

Place Autocomplete 小工具包含下列改善項目:

  • Autocomplete 小工具 UI 支援區域本地化 (包括 RTL 語言),適用於文字輸入預留位置、預測結果清單標誌和地點預測結果。
  • 進階無障礙功能,包括支援螢幕閱讀器和鍵盤互動。
  • Autocomplete 小工具會傳回新的 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,
  });
}