如何在Leaflet.js的异步回调中通过onclick获取按钮文本生成地图
Leaflet地图按按钮属性着色问题
我使用Leaflet生成地图,希望点击按钮时根据按钮对应的属性为地图要素着色。尝试用this关键字获取按钮文本并在async/await调用中使用,但遇到瓶颈:能在console.log中打印文本,却无法保存该文本的引用。
原代码
index.html
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>Plain Leaflet API</title> <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin=""/> <!-- Make sure you put this AFTER Leaflet's CSS --> <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script> <link href='./css/style.css' rel='stylesheet' /> </head> <body> <div id="container"> <div id="options"> <button id="vanilla" onclick="getButtonText()">Vanilla</button> <button id="strawberry"onclick="getButtonText()">Strawberry</button> <button id="chocolate"onclick="getButtonText()">chocolate</button> </div> <div id='map'></div> </div> <script type="text/javascript" src="./js/config.js"></script> <script type="text/javascript" src="./js/app.js"></script> </body> </html>
app.js
let map = L.map('map') .setView([41.83,-87.68],11) let mapboxTiles = L.tileLayer(`https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/{z}/{x}/{y}?access_token=${MAPBOX_API_TOKEN}`, { attribution: '© <a href="https://www.mapbox.com/feedback/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', tileSize: 512, zoomOffset: -1 }).addTo(map); function getButtonText(){ //console.log(this.id,this.innerHTML) return this.innerHTML; } let data_path = "data.geojson" async function loadGeoJson(){ let hexColor = null //read in the geojson data const response = await fetch(data_path) const data = await response.json() //console.log(data.features[0].properties) let addGeoJSON = L.geoJson(data, { style:function(feature){ let vanilla = document.getElementById('vanilla').onclick = getButtonText; let strawberry = document.getElementById('strawberry').onclick = getButtonText; let chocolate = document.getElementById('chocolate').onclick = getButtonText; console.log(vanilla) } }).addTo(map) }
问题分析
this指向错误:通过onclick="getButtonText()"直接调用函数时,this指向全局对象(浏览器中为window),而非按钮元素,导致无法正确获取按钮文本。- 事件绑定逻辑混乱:在
L.geoJson的style函数内重复绑定点击事件毫无意义——style函数是为每个地图要素设置样式时触发的,这里绑定事件会造成重复绑定且逻辑错位。 - 缺少状态存储:没有全局变量保存当前选中的按钮属性值,无法在样式函数中根据选中状态动态调整颜色。
修正方案
修正后的index.html
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>Plain Leaflet API</title> <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin=""/> <!-- Make sure you put this AFTER Leaflet's CSS --> <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script> <link href='./css/style.css' rel='stylesheet' /> </head> <body> <div id="container"> <div id="options"> <button id="vanilla">Vanilla</button> <button id="strawberry">Strawberry</button> <button id="chocolate">chocolate</button> </div> <div id='map'></div> </div> <script type="text/javascript" src="./js/config.js"></script> <script type="text/javascript" src="./js/app.js"></script> </body> </html>
修正后的app.js
let map = L.map('map').setView([41.83, -87.68], 11); let mapboxTiles = L.tileLayer(`https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/{z}/{x}/{y}?access_token=${MAPBOX_API_TOKEN}`, { attribution: '© <a href="https://www.mapbox.com/feedback/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', tileSize: 512, zoomOffset: -1 }).addTo(map); // 全局变量存储当前选中的按钮文本 let selectedProperty = null; // 存储GeoJSON图层实例,方便后续更新样式 let geoJsonLayer = null; // 根据按钮文本返回对应颜色 function getColor(property) { switch(property.toLowerCase()) { case 'vanilla': return '#f5f5dc'; case 'strawberry': return '#ff6b6b'; case 'chocolate': return '#8B4513'; default: return '#cccccc'; } } // 按钮点击事件处理 function handleButtonClick(e) { selectedProperty = e.target.innerHTML; // 图层已加载时,重新设置所有要素样式 if (geoJsonLayer) { geoJsonLayer.setStyle(feature => ({ fillColor: getColor(selectedProperty), fillOpacity: 0.7, color: '#333', weight: 1 })); } } // 绑定所有按钮的点击事件 document.getElementById('vanilla').addEventListener('click', handleButtonClick); document.getElementById('strawberry').addEventListener('click', handleButtonClick); document.getElementById('chocolate').addEventListener('click', handleButtonClick); async function loadGeoJson() { const response = await fetch("data.geojson"); const data = await response.json(); // 创建并保存GeoJSON图层实例 geoJsonLayer = L.geoJson(data, { style: () => ({ fillColor: '#cccccc', fillOpacity: 0.7, color: '#333', weight: 1 }) }).addTo(map); } // 初始化加载GeoJSON数据 loadGeoJson();
关键改动说明
- 修复
this指向问题:用addEventListener绑定点击事件,通过e.target直接获取按钮元素,避免this指向错误。 - 状态管理优化:新增
selectedProperty保存当前选中的按钮文本,geoJsonLayer存储图层实例,确保点击按钮时能动态更新样式。 - 样式逻辑分离:提取
getColor函数统一管理属性与颜色的映射,点击按钮后调用setStyle方法批量更新所有要素样式。 - 清理冗余逻辑:移除
style函数内的无效事件绑定,让样式设置逻辑更清晰。
内容的提问来源于stack exchange,提问作者Zaynaib Giwa
相关产品推荐
相关产品推荐

