Mapbox循环调用flyTo函数报错:addEventListener及center未定义问题排查
解决Mapbox flyTo按钮循环绑定的问题
我来帮你搞定这个问题,你的代码里有两个核心问题,咱们一步步拆解解决:
1. 第一个错误:addEventListener is not a function
你定义的names变量是通过字符串拼接生成的,本质是一串文本,所以names[i]只是字符串里的单个字符,根本不是DOM按钮元素,自然没法调用addEventListener。其实你完全不需要这个names变量,直接用获取到的elements按钮元素集合就可以了。
2. 第二个错误:Cannot read property 'center' of undefined & 所有按钮跳同一视图
这是前端开发里经典的闭包陷阱:你用var声明循环变量i,它的作用域是整个函数,当点击事件触发时,循环早就执行完了,i的值已经变成了elements.length(也就是3),而views[3]是不存在的,所以报错;如果改成views[0].center,所有按钮触发时都会用这个固定值,自然跳同一个视图。
解决闭包问题的两种简洁方法:
方法一:用let代替var声明循环变量
let有块级作用域,每次循环都会创建一个独立的i,点击事件里的i会绑定当前循环的那个值:
for(let i=0; i<elements.length; i++) { elements[i].addEventListener('click', function () { map.flyTo({ center: views[i].center, zoom: views[i].zoom, pitch: views[i].pitch, bearing: views[i].bearing }); }); };
方法二:用forEach遍历元素(更优雅)
直接遍历按钮元素和对应的视图索引,彻底避开循环变量的问题,而且你的views对象的键和flyTo需要的参数完全匹配,可以直接传整个对象:
elements.forEach((btn, index) => { btn.addEventListener('click', () => { map.flyTo(views[index]); }); });
修改后的完整代码
<div id='map' class="myMap"></div> <!-- View buttons --> <div id='console'> <button class="location" name='loc 1' id='v1'>View 1</button> <button class="location" name='loc 2' id='v2'>View 2</button> <button class="location" name='loc 3' id='v3'>View 3</button> </div> <script> // Mapboxgl demo app 'use strict'; var map; mapboxgl.accessToken = 'pk.eyJ1IjoiYmVuamFtaW4td3lzcyIsImEiOiJVcm5FdEw4In0.S8HRIEq8NqdtFVz2-BwQog'; // init the map map = new mapboxgl.Map({ container: 'map', style: 'https://www.mapbox.com/mapbox-gl-styles/styles/outdoors-v7.json', center: [-1.83, -78.183], zoom: 5.5, }); var views = [{ name: "View 1", zoom: 10, pitch: 0, bearing: 0, center: [-0.33,-78.49], }, { name: "View 2", zoom: 10, pitch: 0, bearing: 0, center: [-1.04,-79.43], }, { name: "View 3", zoom: 10, pitch: 0, bearing: 0, center: [-2.19,-78.11], }, ]; // 获取按钮元素集合 var elements = document.getElementsByClassName('location'); // 用forEach绑定事件,避免闭包问题 elements.forEach((btn, index) => { btn.addEventListener('click', () => { map.flyTo(views[index]); }); }); </script>
另外,你之前的document.write(names)会覆盖页面内容,建议直接删掉。
内容的提问来源于stack exchange,提问作者cjn
相关产品推荐
相关产品推荐

