Konva.js动态加载元素鼠标按下事件仅对最后一个元素生效求助
解决Konva.js循环加载元素后事件仅对最后一个生效的问题
这是JavaScript里非常常见的闭包作用域陷阱,我来帮你搞定它!
问题原因
你在for...in循环里给每个元素绑定mousedown事件,但循环里用var声明的变量是函数作用域的——也就是说,整个循环里的elem_id、realized_elem_container其实都是同一个变量,每次迭代都会覆盖它的值。当事件触发时,循环已经执行完毕,这些变量都指向了最后一次迭代的元素数据,所以不管点哪个元素,都会弹出最后一个elem_id,也只会显示最后一个容器。
解决方案
这里有两种简单有效的修复方式:
方法1:使用立即执行函数(IIFE)创建独立作用域
通过IIFE把当前迭代的变量“封存”起来,让每个事件函数都能拿到当前迭代的专属值:
function showExElem(elem_obj) { //Iterate over the object - create each element - assign to current layer for (var key in elem_obj) { var elem_json = elem_obj[key][0]; var elem_container_json = elem_obj[key][1]; var elem_id = elem_obj[key][2]; //Transform into elem and container var realized_elem = Konva.Node.create(elem_json); var realized_elem_container = Konva.Node.create(elem_container_json); //Add to layer and redraw layer.add(realized_elem); realized_elem_container.nodes([realized_elem]); layer.add(realized_elem_container); //Draw the layer layer.draw(); // 用IIFE包裹事件绑定代码,传入当前迭代的变量 (function(currentElemId, currentContainer) { realized_elem.on('mousedown', function () { alert(currentElemId); //Hide all other containers var containers = layer.find('.container'); containers.hide(); //Show the element container currentContainer.show(); layer.draw(); // 别忘了重新绘制层,确保视图更新 }); })(elem_id, realized_elem_container); } }
方法2:改用let声明变量(ES6+推荐)
let是块级作用域的,在for循环里每次迭代都会创建新的变量绑定,每个事件函数会自然捕获当前迭代的变量值,代码更简洁:
function showExElem(elem_obj) { //Iterate over the object - create each element - assign to current layer // 把所有var换成let,利用块级作用域解决问题 for (let key in elem_obj) { let elem_json = elem_obj[key][0]; let elem_container_json = elem_obj[key][1]; let elem_id = elem_obj[key][2]; //Transform into elem and container let realized_elem = Konva.Node.create(elem_json); let realized_elem_container = Konva.Node.create(elem_container_json); //Add to layer and redraw layer.add(realized_elem); realized_elem_container.nodes([realized_elem]); layer.add(realized_elem_container); //Draw the layer layer.draw(); //On click of the element show the element container and trigger the edit fields at the top realized_elem.on('mousedown', function () { alert(elem_id); //Hide all other containers var containers = layer.find('.container'); containers.hide(); //Show the element container realized_elem_container.show(); layer.draw(); // 补充绘制,确保容器显示生效 }); } }
额外提示
记得在调用currentContainer.show()或者realized_elem_container.show()之后,调用layer.draw(),这样Konva才会立即更新画布视图,让容器的显示状态生效。
内容的提问来源于stack exchange,提问作者Jakob
相关产品推荐
相关产品推荐

