Konva中双击无法一次性删除Label组合形状的技术求助
Konva组合形状双击删除解决方案
问题说明
基于Konva框架构建的Label组合形状(包含Tag和Text子元素),双击删除功能仅能删除单个子元素(Tag或Text),无法一次性移除整个组合,导致多组合场景下操作成本极高。
解决方案
双击事件触发时,e.target指向的是点击到的子元素(Tag/Text),而非顶层的Label容器。只需通过子元素向上追溯找到对应的Label父节点,删除整个父节点即可实现一次性删除组合。
修改步骤
- 在双击事件处理函数中,从当前点击的子元素向上遍历,找到类型为
Label的顶层父节点 - 删除该Label节点,而非当前点击的子元素
修改后的核心代码(仅展示双击事件部分)
stageDraw.on('dblclick dbltap', function (e) { if (e.target === stageDraw) { return; } // 向上遍历找到顶层Label节点 let currentShape = e.target; while (currentShape && currentShape.className !== 'Label') { currentShape = currentShape.getParent(); } // 确认找到有效节点后执行删除 if (currentShape) { currentShape.remove(); currentShape.destroy(); layerDraw.draw(); generateJsonLayout(); } });
完整代码(保留原有逻辑,仅更新双击事件)
var numberLabel = new Konva.Label({ x: width / 2, y: 30, id: 'cNumberLabel', draggable: true, }); numberLabel.add(new Konva.Tag({ fill: bgCollor, stroke: 'black', lineJoin: 'round', pointerDirection: direction, pointerWidth: 8, pointerHeight: 11, cornerRadius: 2, draggable: false, })); var textNode = new Konva.Text({ text: '', fontSize: 15, draggable: false, align: 'center', width: 22, fontStyle: 'bold', id: 'cTextNodecNumberLabel', }); numberLabel.add(textNode); layerDraw.add(numberLabel); textNode.on('dragend click', (e) => { textNode.hide(); var textPosition = textNode.absolutePosition(); var areaPosition = { x: stageDraw.container().offsetLeft + textPosition.x, y: stageDraw.container().offsetTop + textPosition.y, }; var textarea = document.createElement('textarea'); document.body.appendChild(textarea); textarea.value = textNode.text(); textarea.style.position = 'absolute'; textarea.style.top = areaPosition.y + 'px'; textarea.style.left = areaPosition.x + 'px'; textarea.style.width = textNode.width() - textNode.padding() * 2 + 'px'; textarea.style.height = textNode.height() - textNode.padding() * 2 + 5 + 'px'; textarea.style.fontSize = textNode.fontSize() + 'px'; textarea.style.border = 'none'; textarea.style.padding = '0px'; textarea.style.margin = '0px'; textarea.style.overflow = 'hidden'; textarea.style.background = 'none'; textarea.style.outline = 'none'; textarea.style.resize = 'none'; textarea.style.lineHeight = textNode.lineHeight(); textarea.style.fontFamily = textNode.fontFamily(); textarea.style.transformOrigin = 'left top'; textarea.style.textAlign = textNode.align(); textarea.style.color = textNode.fill(); rotation = textNode.rotation(); var transform = ''; if (rotation) { transform += 'rotateZ(' + rotation + 'deg)'; } var px = 0; var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; if (isFirefox) { px += 2 + Math.round(textNode.fontSize() / 20); } transform += 'translateY(-' + px + 'px)'; textarea.style.transform = transform; textarea.style.height = 'auto'; textarea.style.height = textarea.scrollHeight + 3 + 'px'; textarea.focus(); function removeTextarea() { textarea.parentNode.removeChild(textarea); window.removeEventListener('click', handleOutsideClick); textNode.show(); } function setTextareaWidth(newWidth) { if (!newWidth) { newWidth = textNode.placeholder.length * textNode.fontSize(); } var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; if (isSafari || isFirefox) { newWidth = Math.ceil(newWidth); } var isEdge = document.documentMode || /Edge/.test(navigator.userAgent); if (isEdge) { newWidth += 1; } textarea.style.width = newWidth + 'px'; } textarea.addEventListener('keydown', function (e) { if (e.keyCode === 13 && !e.shiftKey) { textNode.text(textarea.value); removeTextarea(); } if (e.keyCode === 27) { removeTextarea(); } }); textarea.addEventListener('mouseout', function (e) { textNode.text(textarea.value); removeTextarea(); }); textarea.addEventListener('keydown', function (e) { scale = textNode.getAbsoluteScale().x; setTextareaWidth(textNode.width() * scale); textarea.style.height = 'auto'; textarea.style.height = textarea.scrollHeight + textNode.fontSize() + 'px'; }); function handleOutsideClick(e) { if (e.target !== textarea) { textNode.text(textarea.value); removeTextarea(); } } setTimeout(() => { window.addEventListener('click', handleOutsideClick); }); }); textNode.on('mouseover', function () { stageDraw.container().style.cursor = "pointer"; }); textNode.on("mouseleave", function() { stageDraw.container().style.cursor = "default"; }); stageDraw.on('dblclick dbltap', function (e) { if (e.target === stageDraw) { return; } // 向上遍历找到顶层Label节点 let currentShape = e.target; while (currentShape && currentShape.className !== 'Label') { currentShape = currentShape.getParent(); } if (currentShape) { currentShape.remove(); currentShape.destroy(); layerDraw.draw(); generateJsonLayout(); } });
内容的提问来源于stack exchange,提问作者José Maia
相关产品推荐
相关产品推荐

