原生JS下Google Places Autocomplete四大技术问题咨询
需求:用户在自定义输入框输入单一城市地址,仅输出该地址的经纬度,无需地图,原生JS开发(无框架)。
尝试过程中遇到多种方案问题:部分方案报「function not defined」错误;标注「New」的方案无输出或报错;还有「legacy」方案、组件及官方推荐的「Place」版本。
当前实现部分需求的代码:
(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: "MY_API_KEY_HERE", v: "weekly"}); async function initMap() { (await google.maps.importLibrary('places')); //Required boundary const sw = {lat: -28.265107, lng: 153.168935 }; const ne = {lat: -27.695280, lng: 153.255725 }; const cornerBounds = new google.maps.LatLngBounds(sw, ne); // Create input field const placeAutocomplete = new google.maps.places.PlaceAutocompleteElement({ locationRestriction: cornerBounds }); placeAutocomplete.placeholder = 'Search for a place...'; document.body.appendChild(placeAutocomplete); // Data output HTML const selectedPlaceTitle = document.createElement('p'); selectedPlaceTitle.textContent = ''; document.body.appendChild(selectedPlaceTitle); const selectedPlaceInfo = document.createElement('pre'); selectedPlaceInfo.textContent = ''; document.body.appendChild(selectedPlaceInfo); // Listener placeAutocomplete.addEventListener('gmp-select', async ({ placePrediction }) => { // Fetch data const place = placePrediction.toPlace(); await place.fetchFields({ fields: ['location'] }); selectedPlaceTitle.textContent = 'Selected Place:'; jsonStr = JSON.stringify(place.toJSON(), null, 2) selectedPlaceInfo.textContent = jsonStr; jsonParse = JSON.parse(jsonStr); // Gives latitude and longitude correctly console.log(jsonParse['location']['lat'], jsonParse['location']['lat']) }); } initMap();
遇到的问题:设置位置限制后部分地址无法检索,取消限制则正常检索。
咨询问题:
- 当前代码是否为最新版本?若不是,应如何修改?
- 如何修改代码以使用自定义输入框而非脚本生成的输入框?
- 该方案是否为成本最低的实现方式?
- 是否应采用其他完全不同的实现方案?
1. 当前代码是否为最新版本?
你的代码使用的是Google Maps JavaScript API的模块化加载方式(v3.50+的weekly渠道),属于官方推荐的最新实现模式。位置限制导致部分地址无法检索,是因为LatLngBounds的范围限制过严,或者部分目标地址的地理坐标落在你设置的边界之外。
优化边界限制的方法:
- 放宽
sw和ne的坐标范围,确保目标城市的所有区域都被覆盖 - 改用
Circle类型的位置限制,基于中心点和半径,灵活性更高:
// 替换原边界代码 const center = {lat: -27.98, lng: 153.21}; // 目标城市中心点 const radius = 10000; // 半径10公里,可按需调整 const locationRestriction = new google.maps.Circle({center, radius});
2. 使用自定义输入框的修改方法
要替换脚本生成的PlaceAutocompleteElement,改用自定义输入框,需使用**PlaceAutocomplete服务**而非UI组件,步骤如下:
- 在HTML中添加自定义输入框:
<input type="text" id="custom-input" placeholder="输入地址..."> <div id="result"></div>
- 修改
initMap函数,绑定自定义输入框:
async function initMap() { const { Autocomplete } = await google.maps.importLibrary('places'); // 位置限制(可选,用Circle或放宽的Bounds) const center = {lat: -27.98, lng: 153.21}; const radius = 10000; const locationRestriction = new google.maps.Circle({center, radius}); // 获取自定义输入框 const input = document.getElementById('custom-input'); // 初始化Autocomplete const autocomplete = new Autocomplete(input, { locationRestriction, types: ['address'] // 仅返回地址类型,可选 }); // 监听地址选择事件 autocomplete.addListener('place_changed', () => { const place = autocomplete.getPlace(); // 提取并输出经纬度 if (place.geometry?.location) { const lat = place.geometry.location.lat(); const lng = place.geometry.location.lng(); document.getElementById('result').textContent = `纬度:${lat},经度:${lng}`; console.log('经纬度:', lat, lng); } else { document.getElementById('result').textContent = '未找到有效地址'; } }); } initMap();
注意:移除原代码中创建PlaceAutocompleteElement的部分,确保输入框id与JS选择器一致。
3. 该方案是否为成本最低的实现方式?
是的。Google Maps Places API的Autocomplete + Place Details组合是低成本的最优选择:
- Autocomplete请求:按调用次数计费,每月60000次免费额度内完全免费
- Place Details请求:仅用户选择预测结果时触发,且仅请求
location字段不会产生额外费用
该方案能减少无效的地址解析请求,对比直接调用Geocoding API,既降低成本又提升用户输入体验。
4. 是否需要采用其他完全不同的实现方案?
不需要,当前基于Google Places API的方案最契合你的需求:原生JS支持、自带地址补全、精准获取经纬度。
如果不需要地址补全,仅需解析输入地址为经纬度,可直接使用Geocoding API,但该方案无输入提示,用户错误率高,且易浪费请求额度:
// 示例:直接调用Geocoding API async function getLatLng(address) { const apiKey = 'MY_API_KEY_HERE'; const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${apiKey}`; const response = await fetch(url); const data = await response.json(); if (data.status === 'OK') { const location = data.results[0].geometry.location; console.log(location.lat, location.lng); return location; } else { console.log('解析失败:', data.status); return null; } } // 绑定按钮触发解析 document.getElementById('submit-btn').addEventListener('click', () => { const address = document.getElementById('custom-input').value; getLatLng(address); });
内容的提问来源于stack exchange,提问作者MBourne

