Leaflet.js中select标签onchange事件触发多次地图飞行跳转异常
问题描述
使用Leaflet.js制作地图时,从GeoJSON文件读取国家列表并渲染到<select>下拉框中。预期用户选择某国家时,地图执行飞行跳转至对应区域。使用click事件监听选项时功能正常,但改用<select>的onchange事件后,地图先跳转到选中的国家,随后会自动依次跳转到循环中的所有国家。
原相关代码
下拉框渲染与事件绑定代码
countryList.forEach((country) => { const option = document.createElement('option'); //flying to the country on user click on country select.addEventListener('change', () => { flyToStore(country); }); countries=country.properties.country; option.innerText =countries ; select.appendChild(option); }); }
飞行跳转函数
function flyToStore(store) { const lat = store.geometry.coordinates[1]; const lng = store.geometry.coordinates[0]; myMap.flyTo([lat, lng], 6, { duration: 3 }); setTimeout(() => { L.popup({closeButton: false, offset: L.point(0, -8)}) .setLatLng([lat, lng]) .setContent(makePopupContent(store)) .openOn(myMap); }, 3000); }
问题原因
你在countryList.forEach循环里,给同一个<select>元素重复绑定了change事件——每循环一个国家,就新增一个change事件监听器。当用户触发一次change时,所有绑定的监听器都会执行,每个监听器对应循环里的一个country对象,所以会依次跳转到所有国家。
而之前用click事件是绑定在每个<option>上,每个选项的事件独立,不会重复触发。
修复方案
把change事件绑定从循环里移出来,不要在循环内重复绑定。而是在事件触发时,根据选中的选项获取对应的国家数据,再调用flyToStore。
修正后的代码
方案一:通过dataset存储国家数据
// 先渲染所有选项 countryList.forEach((country) => { const option = document.createElement('option'); const countryName = country.properties.country; option.innerText = countryName; // 将country对象转为JSON字符串存储在option的dataset中 option.dataset.countryData = JSON.stringify(country); select.appendChild(option); }); // 给select绑定一次change事件即可 select.addEventListener('change', () => { const selectedOption = select.options[select.selectedIndex]; // 解析dataset中的JSON字符串为country对象 const country = JSON.parse(selectedOption.dataset.countryData); flyToStore(country); });
方案二:通过国家名称匹配(需名称唯一)
// 渲染选项时设置value为国家名称 countryList.forEach((country) => { const option = document.createElement('option'); const countryName = country.properties.country; option.innerText = countryName; option.value = countryName; select.appendChild(option); }); // 绑定change事件,通过名称匹配对应country select.addEventListener('change', () => { const selectedName = select.value; const country = countryList.find(item => item.properties.country === selectedName); if (country) { flyToStore(country); } });
飞行跳转函数保持不变
function flyToStore(store) { const lat = store.geometry.coordinates[1]; const lng = store.geometry.coordinates[0]; myMap.flyTo([lat, lng], 6, { duration: 3 }); setTimeout(() => { L.popup({closeButton: false, offset: L.point(0, -8)}) .setLatLng([lat, lng]) .setContent(makePopupContent(store)) .openOn(myMap); }, 3000); }
内容的提问来源于stack exchange,提问作者Faraz Anwar
相关产品推荐
相关产品推荐

