class LocationPicker { constructor() { this.map = null; this.marker = null; this.geolocation = null; this.localSearch = null; this.currentPoint = null; this.loadNum = 0; this.config = { theme: 'light', // 主题风格,light|dark key: null, // 百度地图 API Key title: null, // 页面标题,如:选择打卡地点 label: null, // 搜索列表标签,如:附近的地点 placeholder: null, // 搜索框占位符,如:搜索附近的地点 point: null, // 初始坐标,如:116.404,39.915 noresult: null, // 无搜索结果提示,如:附近没有找到地点 radius: 300, // 搜索半径,单位:300 zoom: 16, // 地图缩放级别 errtip: null, // 定位失败提示 errclose: false, // 定位失败是否关闭页面 channel: null, // 回传数据通道 selectclose: false, // 选择地点是否关闭页面 }; this.init(); } async init() { // 先初始化参数 this.initParams(); // 如果没有 key,直接返回 if (!this.config.key) { console.error('未提供百度地图 API Key'); return; } try { // 等待地图 JS 加载完成 await this.loadBaiduMapScript(); // 初始化地图 this.initMap(); } catch (error) { console.error('加载百度地图失败:', error); } } initParams() { // 获取当前URL的查询参数 const urlParams = new URLSearchParams(window.location.search); // 遍历 config 对象的所有属性 Object.keys(this.config).forEach(key => { // 从 URL 参数中获取值 const value = urlParams.get(key); if (value !== null) { // 根据参数类型进行转换 switch (key) { case 'radius': // 转换为数字 this.config[key] = parseInt(value) || 300; break; case 'point': // 转换为坐标数组 const [lng, lat] = value.replace(/[|-]/, ',').split(',').map(parseFloat); if (lng && lat) { this.config[key] = {lng, lat}; } break; default: // 字符串类型直接赋值 this.config[key] = value; } } }); // 设置主题风格 document.documentElement.classList.add(`theme-${this.config.theme}`); document.body.style.backgroundColor = "#ffffff"; // 设置标题 if (this.config.title) { document.title = this.config.title; } // 设置搜索框占位符 if (this.config.placeholder) { document.getElementById('search-input').placeholder = this.config.placeholder; } // 设置label if (this.config.label) { document.getElementById('address-label').innerText = this.config.label; } } initMap() { // 初始化地图 this.map = new BMap.Map('map-container'); // 创建定位控件 const locationControl = new BMap.GeolocationControl({ anchor: BMAP_ANCHOR_BOTTOM_RIGHT, showAddressBar: false, enableAutoLocation: false, locationIcon: new BMap.Icon("empty.svg", new BMap.Size(0, 0)) }); // 监听定位事件 locationControl.addEventListener("locationSuccess", (e) => { // 定位成功事件 this.updateCurrentPoint(e.point); }); locationControl.addEventListener("locationError", (e) => { // 定位失败事件 console.error('定位失败:', e.message); this.locationError(); }); // 添加定位控件到地图 this.map.addControl(locationControl); // 初始化本地搜索,移除地图渲染 this.localSearch = new BMap.LocalSearch(this.map, { renderOptions: { autoViewport: false // 关闭自动视野调整 } }); // 设置地图中心点 if (this.config.point) { const {lng, lat} = this.config.point; this.config.point = new BMap.Point(lng, lat); // 设置地图中心点和缩放级别 this.map.centerAndZoom(this.config.point, this.config.zoom); // 创建圆形区域 const circle = new BMap.Circle(this.config.point, this.config.radius, { fillColor: "#333333", fillOpacity: 0.1, strokeColor: "#333333", strokeWeight: 1, strokeOpacity: 0.3 }); this.map.addOverlay(circle); } // 绑定事件 this.bindEvents(); // 初始化时自动定位 this.getCurrentLocation(); } bindEvents() { const searchInput = document.getElementById('search-input'); // 监听回车键 searchInput.addEventListener('keyup', (e) => { if (e.key === 'Enter') { searchInput.blur(); } }); // 监听失去焦点 searchInput.addEventListener('blur', () => { this.searchAddress(); }); } getCurrentLocation() { this.loaderShow(); this.geolocation = new BMap.Geolocation(); this.geolocation.getCurrentPosition((result) => { this.loaderHide(); if (result && result.point) { this.updateCurrentPoint(result.point) } else { console.error('定位失败'); this.locationError(); } }, {enableHighAccuracy: true}); } updateCurrentPoint(point) { this.currentPoint = point; this.map.centerAndZoom(this.currentPoint, this.config.zoom); this.updateMarker(this.currentPoint); this.searchNearby(); } updateMarker(point) { if (this.marker) { this.marker.setPosition(point); } else { this.marker = new BMap.Marker(point); this.map.addOverlay(this.marker); } } searchAddress() { const keyword = document.getElementById('search-input').value; this.searchNearby(keyword ? [keyword] : []); } searchNearby(keywords = [], retryCount = 0) { // 当前位置未获取 if (this.currentPoint === null) { return; } // 清除之前的搜索结果 this.localSearch.clearResults(); // 搜索附近的关键词 if (keywords.length === 0) { keywords = ["写字楼", "公司", "银行", "餐馆", "商场", "超市", "学校", "医院", "公交站", "地铁站"] } // 定义一个随机数,用于判断定时器是否过期 this.searchRandom = Math.random(); // 设置搜索完成回调 this.loaderShow(); this.localSearch.setSearchCompleteCallback((results) => { this.loaderHide(); if (this.localSearch.getStatus() !== BMAP_STATUS_SUCCESS) { // 搜索失败 if (retryCount < 60) { const tmpRand = this.searchRandom; this.loaderShow(); setTimeout(() => { this.loaderHide(); tmpRand === this.searchRandom && this.searchNearby(keywords, ++retryCount); }, 1000) return; } } // 搜索结果 document.getElementById('address-list').style.display = 'block'; const array = []; if (results instanceof Array) { results.some(result => { if (!result) { return false; } for (let i = 0; i < result.getCurrentNumPois(); i++) { const poi = result.getPoi(i); poi._distance = this.config.point ? this.map.getDistance(this.config.point, poi.point) : null; array.push(poi); } }); } this.updatePoiList(array); }); // 执行搜索 this.localSearch.searchNearby(keywords, this.currentPoint, this.config.radius); } updatePoiList(results) { const poiList = document.getElementById('poi-list'); poiList.innerHTML = ''; // 如果没有搜索结果 if (results.length === 0 && this.config.noresult) { poiList.innerHTML = '