如何仅在点击未选中Widget时取消已选Widget的选中状态?
Widget批量拖拽系统问题修复
问题现象
选中两个Widget后,拖拽未选中的Widget时,所有已选Widget会一同被拖拽,不符合预期。
预期效果
- 鼠标按下未选中的Widget时,移除所有已选Widget的
.selected类 - 鼠标按下已选中的Widget时,保留选中状态,正常拖拽选中的所有Widget
修改后的JavaScript代码
let isSelecting = false; let selectionStartX, selectionStartY, selectionEndX, selectionEndY; let selectionRectangle; let draggedElements = []; const widgets = document.querySelectorAll('.widgets'); document.addEventListener('mousedown', (event) => { const header = event.target.closest('.widget-header'); if (header) { const currentWidget = header.parentElement; // 判断当前点击的Widget是否已选中 const isCurrentSelected = currentWidget.classList.contains('selected'); // 如果点击的是未选中的Widget,清除所有选中状态并选中当前Widget if (!isCurrentSelected) { widgets.forEach(widget => widget.classList.remove('selected')); currentWidget.classList.add('selected'); } // 获取所有选中的Widget进行拖拽 draggedElements = Array.from(widgets).filter(widget => widget.classList.contains('selected')); draggedElements.forEach((widget) => { const rect = widget.getBoundingClientRect(); const shiftX = event.clientX - rect.left; const shiftY = event.clientY - rect.top; function moveElement(event) { const x = event.clientX - shiftX; const y = event.clientY - shiftY; widget.style.left = `${x}px`; widget.style.top = `${y}px`; } function stopMoving() { document.removeEventListener('mousemove', moveElement); document.removeEventListener('mouseup', stopMoving); } document.addEventListener('mousemove', moveElement); document.addEventListener('mouseup', stopMoving); }); return; } const clickedWidget = Array.from(widgets).find(widget => { const rect = widget.getBoundingClientRect(); return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom; }); if (clickedWidget) { // 点击Widget非头部区域时,切换选中状态(未选中则先清空其他选中) if (!clickedWidget.classList.contains('selected')) { widgets.forEach(w => w.classList.remove('selected')); } clickedWidget.classList.toggle('selected'); return; } if (event.target !== selectionRectangle) { isSelecting = true; selectionStartX = event.clientX; selectionStartY = event.clientY; selectionRectangle = document.createElement('div'); selectionRectangle.id = 'selection-rectangle'; selectionRectangle.style.position = 'absolute'; selectionRectangle.style.border = '2px dashed blue'; selectionRectangle.style.pointerEvents = 'none'; selectionRectangle.style.display = 'none'; document.body.appendChild(selectionRectangle); widgets.forEach(widget => widget.classList.remove('selected')); } }); document.addEventListener('mousemove', (event) => { if (isSelecting) { selectionEndX = event.clientX; selectionEndY = event.clientY; const width = Math.abs(selectionEndX - selectionStartX); const height = Math.abs(selectionEndY - selectionStartY); selectionRectangle.style.width = `${width}px`; selectionRectangle.style.height = `${height}px`; selectionRectangle.style.left = `${Math.min(selectionEndX, selectionStartX)}px`; selectionRectangle.style.top = `${Math.min(selectionEndY, selectionStartY)}px`; selectionRectangle.style.display = 'block'; widgets.forEach((widget) => { const widgetRect = widget.getBoundingClientRect(); const isIntersecting = isRectangleIntersecting(widgetRect, { x: Math.min(selectionStartX, selectionEndX), y: Math.min(selectionStartY, selectionEndY), width, height, }); if (isIntersecting) { widget.classList.add('selected'); } else { widget.classList.remove('selected'); } }); } }); document.addEventListener('mouseup', () => { if (isSelecting) { isSelecting = false; selectionRectangle.remove(); } }); function isRectangleIntersecting(rect1, rect2) { return ( rect1.left >= rect2.x && rect1.top >= rect2.y && rect1.right <= rect2.x + rect2.width && rect1.bottom <= rect2.y + rect2.height ); }
CSS代码(无需修改)
#selection-rectangle { position: absolute; border: 2px dashed blue; pointer-events: none; display: none; z-index: 9999999; } .widgets.selected { outline-color: blue; outline-width: 2px; outline-style: dashed; } .widgets { position: absolute; z-index: 9; background-color: #000000; color: white; font-size: 25px; font-family: Arial, Helvetica, sans-serif; border: 2px solid #212128; text-align: center; width: 500px; height: 200px; min-width: 166px; min-height: 66px; overflow: hidden; resize: both; image-resolution: none; border-radius: 10px; } .widget-header { padding: 10px; cursor: move; z-index: 10; background-color: #040c14; outline-color: white; outline-width: 2px; outline-style: solid; }
HTML代码(无需修改)
<div id="widget1" class="widgets" style="left: 50px; top: 50px;"> <div id="widget1header" class="widget-header"></div> </div> <div id="widget2" class="widgets" style="left: 150px; top: 150px;"> <div id="widget2header" class="widget-header"></div> </div> <div id="widget3" class="widgets" style="left: 250px; top: 250px;"> <div id="widget3header" class="widget-header"></div> </div>
修改说明
- 移除重复拖拽函数:删除原有三次重复定义的
dragElement,统一使用全局mousedown事件处理拖拽逻辑,避免逻辑冲突 - 添加选中状态判断:点击Widget头部时,若当前Widget未选中,先清空所有选中状态再选中当前Widget;若已选中则保留批量选中状态
- 优化非头部点击逻辑:点击Widget非头部区域时,切换当前Widget选中状态,未选中时自动清空其他选中项
内容的提问来源于stack exchange,提问作者AKSIL
相关产品推荐
相关产品推荐

