欢迎使用经过改进的全新“地点自动补全”功能的实验性版本。自动补全是 Maps JavaScript API 中地点库的一项功能。借助自动补全,您可以让自己的应用具有 Google 地图搜索字段的“即输即找”功能。自动补全服务可以根据完整字词和子字符串进行匹配,从而解析地点名称、地址和 Plus Codes。这样,应用就可以在用户输入内容时发送查询,从而即时进行地点预测。
前提条件
欢迎使用新版地点自动补全(实验阶段)。若要使用文本搜索(预览版),您必须在 Google Cloud 项目中启用“Places API”,并在您的引导程序加载器中指定 Alpha 渠道 (v: "alpha"
)。如需了解详情,请参阅开始使用。
新变化
地点自动补全(实验阶段)在以下方面得到了改进:
- Autocomplete widget 界面针对文本输入占位符、预测列表徽标和地点预测支持区域本地化(包括 RTL 语言)。
- 增强了无障碍功能,包括对屏幕阅读器和键盘互动的支持。
- Autocomplete widget 会返回新的 Place 类,以简化对返回对象的处理。
- 为移动设备和小屏幕设备提供更好的支持。
- 更出色的性能和改进的图形外观。
添加 Autocomplete widget
您可以为网页或 Google 地图添加 Autocomplete widget。Autocomplete widget 会创建文本输入字段,在界面选择列表中提供地点预测结果,并通过 gmp-placeselect
监听器返回地点详情以响应用户点击。本部分介绍了如何向网页或 Google 地图添加 Autocomplete widget。
向网页添加 Autocomplete widget
如要向网页添加 Autocomplete widget,请创建一个新的 input
元素,然后使用该元素创建新的 google.maps.places.PlaceAutocompleteElement
,并将其附加到页面,如以下示例所示:
TypeScript
// Request needed libraries. //@ts-ignore const [{ Map }] = await Promise.all([ google.maps.importLibrary("places"), ]); // Create the input HTML element, and append it. //@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore document.body.appendChild(placeAutocomplete);
JavaScript
// Request needed libraries. //@ts-ignore const [{ Map }] = await Promise.all([google.maps.importLibrary("places")]); // Create the input HTML element, and append it. //@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore document.body.appendChild(placeAutocomplete);
向地图添加 Autocomplete widget
如要向地图添加 Autocomplete widget,请创建一个新的 input
元素,使用该元素创建新的 google.maps.places.PlaceAutocompleteElement
实例,将 PlaceAutocompleteElement
附加到 div
,然后将该元素作为自定义控件推送到地图上,如以下示例所示:
TypeScript
//@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore placeAutocomplete.id = 'place-autocomplete-input'; const card = document.getElementById('place-autocomplete-card') as HTMLElement; //@ts-ignore card.appendChild(placeAutocomplete); map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);
JavaScript
//@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore placeAutocomplete.id = "place-autocomplete-input"; const card = document.getElementById("place-autocomplete-card"); //@ts-ignore card.appendChild(placeAutocomplete); map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);
限制自动补全预测结果
默认情况下,地点自动补全服务会显示所有地点类型(偏向于用户所在位置附近的预测结果),并提取用户所选地点的所有可用数据字段。通过限制或自定义调整结果来设置地点自动补全选项,可以显示更相关的预测结果。
限制预测结果会导致 Autocomplete widget 忽略限制区域以外的任何结果。常见做法是将结果范围限定在地图边界内。自定义调整结果会使 Autocomplete widget 显示指定区域内的结果,但某些匹配项可能不在这个指定区域内。
按国家/地区限制地点搜索
如要将地点搜索限定在一个或多个特定国家/地区,请使用 componentRestrictions
属性指定国家/地区代码,如以下代码段所示:
const pac = new google.maps.places.PlaceAutocompleteElement({ inputElement: input, componentRestrictions: {country: ['us', 'au']}, });
将地点搜索限定在地图边界内
如要将地点搜索限定在地图的边界内,请使用 locationRestrictions
属性添加边界,如以下代码段所示:
const pac = new google.maps.places.PlaceAutocompleteElement({ inputElement: input, locationRestriction: map.getBounds(), });
将范围限定在地图边界内时,请务必添加监听器,以在边界发生变化时更新边界:
map.addListener('bounds_changed', () => { autocomplete.locationRestriction = map.getBounds(); });
如要移除 locationRestriction
,请将其设置为 null
。
自定义调整地点搜索结果
使用 locationBias
属性并传递半径,即可自定义调整地点搜索结果,将其限定在一个圆形区域内,如下所示:
const autocomplete = new google.maps.places.PlaceAutocompleteElement({ inputElement: input, locationBias: {radius: 100, center: {lat: 50.064192, lng: -130.605469}}, });
如要移除 locationBias
,请将其设置为 null
。
将地点搜索结果限定为特定类型
使用 types
属性并指定一种或多种类型,即可将地点搜索结果限定为特定类型的地点,如下所示:
const autocomplete = new google.maps.places.PlaceAutocompleteElement({ inputElement: input, types: ['establishment'], });
如要查看所支持类型的完整列表,请参阅表 3:地点自动补全请求支持的类型。
获取地点详情
如要获取所选地点的地点详情,请向 PlaceAutocompleteElement
添加 gmp-place-select
监听器,如以下示例所示:
TypeScript
// Add the gmp-placeselect listener, and display the results. //@ts-ignore placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => { await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'] }); selectedPlaceTitle.textContent = 'Selected Place:'; selectedPlaceInfo.textContent = JSON.stringify( place.toJSON(), /* replacer */ null, /* space */ 2); });
JavaScript
// Add the gmp-placeselect listener, and display the results. //@ts-ignore placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => { await place.fetchFields({ fields: ["displayName", "formattedAddress", "location"], }); selectedPlaceTitle.textContent = "Selected Place:"; selectedPlaceInfo.textContent = JSON.stringify( place.toJSON(), /* replacer */ null, /* space */ 2, ); });
在前面的示例中,事件监听器会返回 Place 类的对象。调用 place.fetchFields()
即可获取应用所需的地点详情数据字段。
下例中的监听器会请求地点信息并将其显示在地图上。
TypeScript
// Add the gmp-placeselect listener, and display the results on the map. //@ts-ignore 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; });
JavaScript
// Add the gmp-placeselect listener, and display the results on the map. //@ts-ignore 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; });
获取所选地点的地理编码结果
如要获取所选地点的地理编码结果,请使用 google.maps.Geocoder
获取位置,如以下代码段所示:
const map = new google.maps.Map(document.getElementById('map'), { center: {lat: 50.064192, lng: -130.605469}, zoom: 3, }); const marker = new google.maps.Marker({map}); const inputElement = document.getElementById('pac-input'); const autocomplete = new google.maps.places.PlaceAutocompleteElement({inputElement}); const geocoder = new google.maps.Geocoder(); autocomplete.addListener('gmp-placeselect', async ({prediction: place}) => { const results = await geocoder.geocode({place.id}); marker.setPlace({ placeId: place.id, location: results[0].geometry.location, }); });
示例地图
本部分包含本页介绍的示例地图的完整代码。
自动补全元素
此示例会向网页添加 Autocomplete widget,并显示每个选定地点的结果。
TypeScript
async function initMap(): Promise<void> { // Request needed libraries. //@ts-ignore const [{ Map }] = await Promise.all([ google.maps.importLibrary("places"), ]); // Create the input HTML element, and append it. //@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore document.body.appendChild(placeAutocomplete); // Inject HTML UI. const selectedPlaceTitle = document.createElement('p'); selectedPlaceTitle.textContent = ''; document.body.appendChild(selectedPlaceTitle); const selectedPlaceInfo = document.createElement('pre'); selectedPlaceInfo.textContent = ''; document.body.appendChild(selectedPlaceInfo); // Add the gmp-placeselect listener, and display the results. //@ts-ignore placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => { await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'] }); selectedPlaceTitle.textContent = 'Selected Place:'; selectedPlaceInfo.textContent = JSON.stringify( place.toJSON(), /* replacer */ null, /* space */ 2); }); } initMap();
JavaScript
async function initMap() { // Request needed libraries. //@ts-ignore const [{ Map }] = await Promise.all([google.maps.importLibrary("places")]); // Create the input HTML element, and append it. //@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore document.body.appendChild(placeAutocomplete); // Inject HTML UI. const selectedPlaceTitle = document.createElement("p"); selectedPlaceTitle.textContent = ""; document.body.appendChild(selectedPlaceTitle); const selectedPlaceInfo = document.createElement("pre"); selectedPlaceInfo.textContent = ""; document.body.appendChild(selectedPlaceInfo); // Add the gmp-placeselect listener, and display the results. //@ts-ignore placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => { await place.fetchFields({ fields: ["displayName", "formattedAddress", "location"], }); selectedPlaceTitle.textContent = "Selected Place:"; selectedPlaceInfo.textContent = JSON.stringify( place.toJSON(), /* replacer */ null, /* space */ 2, ); }); } initMap();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #map { height: 100%; } /* * Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } p { font-family: Roboto, sans-serif; font-weight: bold; }
HTML
<html> <head> <title>Place Autocomplete element</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 style="font-family: roboto, sans-serif">Search for a place here:</p> <!-- prettier-ignore --> <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))}) ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "alpha"});</script> </body> </html>
试用示例
自动补全地图
以下示例展示了如何向 Google 地图添加 Autocomplete widget。
TypeScript
let map: google.maps.Map; let marker: google.maps.marker.AdvancedMarkerElement; let infoWindow: google.maps.InfoWindow; async function initMap(): Promise<void> { // Request needed libraries. //@ts-ignore 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') as HTMLElement, { center: { lat: 40.749933, lng: -73.98633 }, zoom: 13, mapId: '4504f8b37365c3d0', mapTypeControl: false, }); //@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore placeAutocomplete.id = 'place-autocomplete-input'; const card = document.getElementById('place-autocomplete-card') as HTMLElement; //@ts-ignore 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. //@ts-ignore 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, }); } initMap();
JavaScript
let map; let marker; let infoWindow; async function initMap() { // Request needed libraries. //@ts-ignore 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, }); //@ts-ignore const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement(); //@ts-ignore placeAutocomplete.id = "place-autocomplete-input"; const card = document.getElementById("place-autocomplete-card"); //@ts-ignore 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. //@ts-ignore 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, }); } initMap();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #map { height: 100%; } /* * Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } #place-autocomplete-card { background-color: #fff; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; margin: 10px; padding: 5px; font-family: Roboto, sans-serif; font-size: large; font-weight: bold; } #place-autocomplete { width: 250px; } #infowindow-content .title { font-weight: bold; } #map #infowindow-content { display: inline; }
HTML
<html> <head> <title>Place Autocomplete map</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> <div class="place-autocomplete-card" id="place-autocomplete-card"> <p>Search for a place here:</p> </div> <div id="map"></div> <!-- prettier-ignore --> <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))}) ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "alpha"});</script> </body> </html>