如何检测用户是否尝试调整使用CSS resize: both的可拖拽元素大小
最优实现方案
核心思路是复用浏览器原生的resize状态判断,不需要自己硬编码坐标阈值,完全规避浏览器/系统的样式差异问题:
- 浏览器触发resize规则时会自动修改光标类型为
se-resize(右下角双向箭头),只需要在拖拽触发前判断当前光标类型,只要是调整尺寸相关的光标,直接终止拖拽逻辑即可。
具体修改点
你只需要替换原有mousedown事件中20px坐标判断的逻辑即可:
// 原有硬编码坐标逻辑可完全删除 /* if cursor within 20px from bottom right corner don't move */ // const r = e.target.getBoundingClientRect(); // if (r.right < e.x + 20 && r.bottom < e.y + 20) // return; // 替换为光标类型判断逻辑 const cursorStyle = getComputedStyle(e.target).cursor; // 匹配所有调整尺寸的光标类型,兼容不同浏览器表现 if(['se-resize', 'nwse-resize', 'resize'].includes(cursorStyle)) return;
优化后的完整可运行代码
JS
!function(){ "use strict"; let x, y, drag; document.addEventListener("mousedown", function(e) { if (e.target.parentNode.lastChild !== e.target && e.target.parentNode.classList.contains("main")) { //bring element to the front and dispatch mousedown event again otherwise resize doesn't work e.target.parentNode.appendChild(e.target); return e.target.dispatchEvent(new MouseEvent(e.type, e)); } if (!e.target.classList.contains("draggable")) return; // 替换原有坐标判断为光标类型判断 const cursorStyle = getComputedStyle(e.target).cursor; if(['se-resize', 'nwse-resize', 'resize'].includes(cursorStyle)) return; drag = e.target; x = e.x - drag.offsetLeft; y = e.y - drag.offsetTop; document.body.classList.add("drag"); drag.classList.add("drag"); }); document.addEventListener("mouseup", function(e) { document.body.classList.remove("drag"); drag = drag && drag.classList.remove("drag"); }); document.addEventListener("mousemove", function(e) { if (!drag || e.x - drag.offsetLeft == x || e.y - drag.offsetTop == y) return; drag.style.left = (e.x - x) + "px"; drag.style.top = (e.y - y) + "px"; }); /*init*/ for (let i = 0, c, d = document.getElementsByClassName("main")[0].children; i < d.length; i++) { c = (0x1000000 + Math.random() * 0xffffff).toString(16).substr(1, 6); d[i].style.backgroundColor = '#' + c; d[i].classList.toggle("dark", ((parseInt(c.substr(0, 2), 16) * 299) + (parseInt(c.substr(2, 2), 16) * 587) + (parseInt(c.substr(4, 2), 16) * 114)) / 1000 < 128); d[i].style.left = document.documentElement.scrollWidth / 8 + Math.random() * (document.documentElement.scrollWidth / 1.33 - d[i].offsetWidth) + "px"; d[i].style.top = document.documentElement.scrollHeight / 8 + Math.random() * (document.documentElement.scrollHeight / 1.33 - d[i].offsetHeight) + "px"; } }()
CSS(原有逻辑无需修改)
div.main>div { width: 5em; height: 5em; border: 1px solid black; position: absolute; resize: both; overflow: hidden; mix-blend-mode: hard-light; display: flex; border-radius: 0.3em; } div.main>div:hover { box-shadow: 0 0 5px black; } div.main>div:last-child { box-shadow: 0 0 10px black; } div.draggable { cursor: grab; } div.main>div:not(.draggable):before { content: "can't move me"; } div.main>div.draggable:before { content: "move me"; } div.main>div:before { color: black; text-shadow: 0 0 1em black; margin: auto; text-align: center; } div.main>div.dark:before { color: white; text-shadow: 0 0 1em white; } body.drag { user-select: none; } body.drag div.draggable { cursor: grabbing; }
HTML(原有逻辑无需修改)
<div class="main"> <div></div> <div class="draggable"></div> <div class="draggable"></div> <div class="draggable"></div> </div>
方案优势
- 完全适配不同浏览器、操作系统的resize手柄尺寸差异,不会出现坐标判断失效的问题
- 逻辑更轻量,不需要额外计算元素坐标,性能更好
- 完全贴合用户预期,光标是移动状态时触发拖拽,是调整大小状态时触发原生resize,无逻辑冲突
内容的提问来源于stack exchange,提问作者vanowm
相关产品推荐
相关产品推荐

