PlaceListElement(也称为“地点搜索”)是一个 HTML 元素,用于在列表中呈现地点搜索结果。您可以通过以下两种方式配置 gmp-place-list
元素:
- “搜索附近”请求,用于配置微件以呈现地点附近搜索中的搜索结果。
- Search by text request(按文本请求搜索),用于配置微件以呈现地点文本搜索中的搜索结果。
搜索附近地点请求
以下示例会在响应附近搜索时呈现地点列表元素。为简单起见,我们仅列出了三种地点类型:咖啡厅、餐厅和电动汽车充电站。选择某个结果后,系统会针对所选地点显示一个信息窗口,其中显示该地点的详细信息。如需将地点列表元素添加到地图,请向 HTML 页面添加 gmp-place-list
元素,如以下代码段所示:
<gmp-map center="-37.813,144.963" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="controls"> <select name="types" class="type-select"> <option value="">Select a place type</option> <option value="cafe">Cafe</option> <option value="restaurant">Restaurant</option> <option value="electric_vehicle_charging_station"> EV charging station </option> </select> </div> <div class="list-container"> <gmp-place-list selectable style="display: none;"></gmp-place-list> </div> </div> </gmp-map> <gmp-place-details style="display: none;"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details>
系统会使用多个 querySelector
调用来选择要与之互动的网页元素:
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const typeSelect = document.querySelector(".type-select"); const placeDetails = document.querySelector("gmp-place-details"); const placeDetailsRequest = document.querySelector('gmp-place-details-place-request');
当用户点击搜索按钮时,系统会调用
configureFromSearchNearbyRequest
,并且地点列表元素会显示结果(标记是在 addMarkers
辅助函数中添加的)。以下代码段还显示了使用 gmp-placeselect
事件处理地点列表上的点击事件的代码:
placeDetails.addEventListener('gmp-load', (event) => { // Center the info window on the map. map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 }); }); typeSelect.addEventListener('change', (event) => { // First remove all existing markers. for (marker in markers) { markers[marker].map = null; } markers = {}; if (typeSelect.value) { placeList.style.display = 'block'; placeList.configureFromSearchNearbyRequest({ locationRestriction: getContainingCircle(map.innerMap.getBounds()), includedPrimaryTypes: [typeSelect.value], }).then(addMarkers); // Handle user selection in Place Details. placeList.addEventListener('gmp-placeselect', ({ place }) => { markers[place.id].click(); }); } });
查看完整代码示例
JavaScript
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const typeSelect = document.querySelector(".type-select"); const placeDetails = document.querySelector("gmp-place-details"); const placeDetailsRequest = document.querySelector('gmp-place-details-place-request'); let markers = {}; let infoWindow; async function initMap() { await google.maps.importLibrary('places'); const { LatLngBounds } = await google.maps.importLibrary('core'); const { InfoWindow } = await google.maps.importLibrary('maps'); const { spherical } = await google.maps.importLibrary('geometry'); infoWindow = new InfoWindow; let marker; function getContainingCircle(bounds) { const diameter = spherical.computeDistanceBetween(bounds.getNorthEast(), bounds.getSouthWest()); const calculatedRadius = diameter / 2; const cappedRadius = Math.min(calculatedRadius, 50000); // Radius cannot be more than 50000. return { center: bounds.getCenter(), radius: cappedRadius }; } findCurrentLocation(); map.innerMap.setOptions({ mapTypeControl: false, clickableIcons: false, }); placeDetails.addEventListener('gmp-load', (event) => { // Center the info window on the map. map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 }); }); typeSelect.addEventListener('change', (event) => { // First remove all existing markers. for (marker in markers) { markers[marker].map = null; } markers = {}; if (typeSelect.value) { placeList.style.display = 'block'; placeList.configureFromSearchNearbyRequest({ locationRestriction: getContainingCircle(map.innerMap.getBounds()), includedPrimaryTypes: [typeSelect.value], }).then(addMarkers); // Handle user selection in Place Details. placeList.addEventListener('gmp-placeselect', ({ place }) => { markers[place.id].click(); }); } }); } async function addMarkers() { const { AdvancedMarkerElement } = await google.maps.importLibrary('marker'); const { LatLngBounds } = await google.maps.importLibrary('core'); const bounds = new LatLngBounds(); if (placeList.places.length > 0) { placeList.places.forEach((place) => { let marker = new AdvancedMarkerElement({ map: map.innerMap, position: place.location }); markers[place.id] = marker; bounds.extend(place.location); marker.addListener('gmp-click', (event) => { if (infoWindow.isOpen) { infoWindow.close(); } placeDetailsRequest.place = place.id; placeDetails.style.display = 'block'; placeDetails.style.width = '350px'; infoWindow.setOptions({ content: placeDetails, }); infoWindow.open({ anchor: marker, map: map.innerMap }); }); map.innerMap.setCenter(bounds.getCenter()); map.innerMap.fitBounds(bounds); }); } } async function findCurrentLocation() { const { LatLng } = await google.maps.importLibrary('core'); if (navigator.geolocation) { navigator.geolocation.getCurrentPosition((position) => { const pos = new LatLng(position.coords.latitude, position.coords.longitude); map.innerMap.panTo(pos); map.innerMap.setZoom(14); }, () => { console.log('The Geolocation service failed.'); map.innerMap.setZoom(14); }); } else { console.log('Your browser doesn\'t support geolocation'); map.innerMap.setZoom(14); } } initMap();
CSS
html, body { height: 100%; margin: 0; } body { display: flex; flex-direction: column; font-family: Arial, Helvetica, sans-serif; } h1 { font-size: large; text-align: center; } gmp-map { box-sizing: border-box; height: 600px; } .overlay { position: relative; top: 40px; margin: 20px; width: 400px; } .controls { display: flex; gap: 10px; margin-bottom: 10px; height: 32px; } .search-button { background-color: #5491f5; color: #fff; border: 1px solid #ccc; border-radius: 5px; width: 100px; cursor: pointer; } .type-select { border: 1px solid #ccc; border-radius: 5px; flex-grow: 1; padding: 0 10px; } .list-container { height: 400px; overflow: auto; border-radius: 10px; } gmp-place-list { background-color: #fff; font-size: large }
HTML
<!DOCTYPE html> <html> <head> <title>Place List Nearby Search with Google Maps</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="style.css"> <script type="module" src="./index.js"></script> </head> <body> <gmp-map center="-37.813,144.963" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="controls"> <select name="types" class="type-select"> <option value="">Select a place type</option> <option value="cafe">Cafe</option> <option value="restaurant">Restaurant</option> <option value="electric_vehicle_charging_station"> EV charging station </option> </select> </div> <div class="list-container"> <gmp-place-list selectable style="display: none;"></gmp-place-list> </div> </div> </gmp-map> <gmp-place-details style="display: none;"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details> <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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "alpha"});</script> </body> </html>
试用示例
按文字搜索请求
此示例会在响应用户文本搜索时呈现地点列表元素。选择某个结果后,系统会针对所选地点显示一个信息窗口,其中显示该地点的详细信息。如需将地点列表元素添加到地图,请将 gmp-place-list
元素添加到 HTML 页面,如以下代码段所示:
<gmp-map center="37.395641,-122.077627" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="text-search-container"> <input type="text" id="textSearchInput" placeholder="Enter text search..."> <button id="textSearchButton">Search</button> </div> <div class="list-container"> <gmp-place-list selectable style="display: none;"></gmp-place-list> </div> </div> <gmp-place-details style="display: none;"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details> </gmp-map>
系统会使用多个 querySelector
调用来选择要与之互动的网页元素:
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const placeDetails = document.querySelector("gmp-place-details"); let marker = document.querySelector('gmp-advanced-marker'); const textSearchInput = document.getElementById('textSearchInput'); const textSearchButton = document.getElementById('textSearchButton'); const placeDetailsRequest = document.querySelector('gmp-place-details-place-request');
在用户输入搜索查询后运行搜索函数时,系统会调用
configureFromSearchByTextRequest
,并通过地点列表元素呈现结果(标记是在 addMarkers
辅助函数中添加的)。以下代码段显示了该函数的代码:
async function searchByTextRequest() { if (textSearchInput.value !== "") { placeList.style.display = "block"; placeList.configureFromSearchByTextRequest({ locationRestriction: bounds, textQuery: textSearchInput.value, }).then(addMarkers); // Handle user selection in Place Details. placeList.addEventListener("gmp-placeselect", ({ place }) => { markers[place.id].click(); }); } }
查看完整代码示例
以下示例使用地点列表界面组件根据使用
configureFromSearchNearbyRequest
进行的文本搜索显示地点,并向地图添加可点击的标记,以便在选择地点时显示地点详情。
JavaScript
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const placeDetails = document.querySelector("gmp-place-details"); let marker = document.querySelector('gmp-advanced-marker'); const textSearchInput = document.getElementById('textSearchInput'); const textSearchButton = document.getElementById('textSearchButton'); const placeDetailsRequest = document.querySelector('gmp-place-details-place-request'); let markers = {}; let infoWindow; let center = { lat: 37.395641, lng: -122.077627 }; // Mountain View, CA. let bounds; async function initMap() { const { Map, InfoWindow } = await google.maps.importLibrary("maps"); const { Place } = await google.maps.importLibrary("places"); // Set bounds for location restriction. bounds = new google.maps.LatLngBounds({ lat: 37.37808200917261, lng: -122.13741583377849 }, { lat: 37.416676154341324, lng: -122.02261728794109 }); infoWindow = new google.maps.InfoWindow; // Center the map map.innerMap.panTo(center); map.innerMap.setZoom(14); map.innerMap.setOptions({ mapTypeControl: false, clickableIcons: false, }); // Fire when the Place Details Element is loaded. placeDetails.addEventListener('gmp-load', (event) => { // Center the info window on the map. map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 }); }); // Handle clicks on the search button. textSearchButton.addEventListener('click', searchByTextRequest); // Handle enter key on text input. textSearchInput.addEventListener('keydown', (event) => { if (event.key === 'Enter') { searchByTextRequest(); } }); } async function searchByTextRequest() { if (textSearchInput.value !== "") { placeList.style.display = "block"; placeList.configureFromSearchByTextRequest({ locationRestriction: bounds, textQuery: textSearchInput.value, }).then(addMarkers); // Handle user selection in Place Details. placeList.addEventListener("gmp-placeselect", ({ place }) => { markers[place.id].click(); }); } } async function addMarkers() { const { AdvancedMarkerElement } = await google.maps.importLibrary("marker"); const { LatLngBounds } = await google.maps.importLibrary("core"); const bounds = new LatLngBounds(); // First remove all existing markers. for (marker in markers) { markers[marker].map = null; } markers = {}; if (placeList.places.length > 0) { placeList.places.forEach((place) => { let marker = new AdvancedMarkerElement({ map: map.innerMap, position: place.location, }); markers[place.id] = marker; bounds.extend(place.location); marker.collisionBehavior = google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL; marker.addListener('gmp-click', (event) => { if (infoWindow.isOpen) { infoWindow.close(); } // Set the Place Details request to the selected place. placeDetailsRequest.place = place.id; placeDetails.style.display = "block"; placeDetails.style.width = "350px"; infoWindow.setOptions({ content: placeDetails }); infoWindow.open({ anchor: marker, map: map.innerMap }); placeDetails.addEventListener('gmp-load', () => { map.innerMap.fitBounds(place.viewport, { top: 400, left: 400 }); }); }); map.innerMap.setCenter(bounds.getCenter()); map.innerMap.fitBounds(bounds); }); } } initMap();
CSS
html, body { height: 100%; margin: 0; } gmp-map { box-sizing: border-box; height: 500px; } gmp-place-list { background-color: #fff; font-size: large } .overlay { position: relative; top: 20px; margin: 20px; width: 400px; } .list-container { height: 400px; overflow: auto; border-radius: 10px; } /* Styles for the text search container and its elements */ .text-search-container { display: flex; /* Arrange input and button side-by-side */ gap: 8px; /* Space between input and button */ padding-bottom: 10px; /* Space below the search bar */ border-bottom: 1px solid #eee; /* Separator line */ } #textSearchInput { flex-grow: 1; /* Allow input to take available space */ padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1rem; } #textSearchInput:focus { outline: none; border-color: #4a80e8; /* Highlight on focus */ box-shadow: 0 0 0 2px rgba(74, 128, 232, 0.2); } #textSearchButton { padding: 8px 15px; background-color: #4a80e8; /* Example button color */ color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem; transition: background-color 0.2s ease-in-out; } #textSearchButton:hover { background-color: #356ac0; /* Darker shade on hover */ }
HTML
<!DOCTYPE html> <html> <head> <title>Place List Text Search with Google Maps</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="style.css"> <script type="module" src="./index.js"></script> </head> <body> <gmp-map center="37.395641,-122.077627" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="text-search-container"> <input type="text" id="textSearchInput" placeholder="Enter text search..."> <button id="textSearchButton">Search</button> </div> <div class="list-container"> <gmp-place-list selectable style="display: none;"></gmp-place-list> </div> </div> <gmp-place-details style="display: none;"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details> </gmp-map> <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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "alpha"});</script> </body> </html>