我们没有在鼠标移动的时候去实时统计被框选到的DOM元素,如果需要实时统计或者实时修改被选择的DOM元素的样式,以便更准确的让用户感知到被框选的内容的话,可以选择在mousemove事件里边去实现以下代码:
<script> (function () { var mouseStopId; var mouseOn = false; var startX = 0; var startY = 0; document.onmousedown = function (e) { clearEventBubble(e); if (e.buttons !== 1 || e.which !== 1) return; mouseStopId = setTimeout(function () { mouseOn = true; startX = e.clientX; startY = e.clientY; var selDiv = document.createElement('div'); selDiv.style.cssText = 'position:absolute;width:0;height:0;margin:0;padding:0;border:1px dashed #eee;background-color:#aaa;z-index:1000;opacity:0.6;display:none;'; selDiv.id = 'selectDiv'; document.body.appendChild(selDiv); selDiv.style.left = startX + 'px'; selDiv.style.top = startY + 'px'; }, 300); } document.onmousemove = function (e) { if (!mouseOn) return; clearEventBubble(e); var _x = e.clientX; var _y = e.clientY; var selDiv = document.getElementById('selectDiv'); selDiv.style.display = 'block'; selDiv.style.left = Math.min(_x, startX) + 'px'; selDiv.style.top = Math.min(_y, startY) + 'px'; selDiv.style.width = Math.abs(_x - startX) + 'px'; selDiv.style.height = Math.abs(_y - startY) + 'px'; }; // 添加鼠标松开事件监听 document.onmouseup = function (e) { if (!mouseOn) return; clearEventBubble(e); var selDiv = document.getElementById('selectDiv'); var fileDivs = document.getElementsByClassName('fileDiv'); var selectedEls = []; // 获取参数 var l = selDiv.offsetLeft; var t = selDiv.offsetTop; var w = selDiv.offsetWidth; var h = selDiv.offsetHeight; for (var i = 0; i < fileDivs.length; i++) { var sl = fileDivs[i].offsetWidth + fileDivs[i].offsetLeft; var st = fileDivs[i].offsetHeight + fileDivs[i].offsetTop; if (sl > l && st > t && fileDivs[i].offsetLeft < l + w && fileDivs[i].offsetTop < t + h) { // 该DOM元素被选中,进行处理 selectedEls.push(fileDivs[i]); } } // 打印被选中DOM元素 console.log(selectedEls); // 恢复参数 selDiv.style.display = 'none'; mouseOn = false; }; function clearEventBubble (e) { if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; if (e.preventDefault) e.preventDefault(); else e.returnValue = false; } })(); </script>
这里判断一个元素是否被选中采用的判断条件是:
该DOM元素的最右边(fileDiv[i].offsetLeft + fileDiv[i].offsetWidth)是否要比选框元素最左边(selDiv.offsetLeft)的位置要小;
该DOM元素的最下边(fileDiv[i].offsetTop + fileDiv[i].offsetHeight)是否要比选框元素的最上边(selDiv.offsetTop)的位置要大;
该DOM元素的最左边(fileDiv[i].offsetLeft)是否要比选框元素的最后边(selDiv.offsetLeft + selDiv.offsetWidth)的位置数值要小;
该DOM元素的最上边(fileDiv[i].offsetTop)是否要比选框元素的最下边(selDiv.offsetTop + selDiv.offsetHeight)的位置数值要小;
满足了以上四个条件,即可判别为该DOM元素被选中了。
实际应用
上边的例子,举得有些过于简单了。实际的开发当中,框选的范围往往不可能是整个document.body,而是某一个具体的有特定宽度跟高度限制的元素。这个时候,就还需要考虑这个框选容器元素造成的定位偏差,以及容器内元素过多,出现滚动条的情况了。
乍一看,上边的情况需要考虑的因素多了不少,比较容易乱。我这里采用的方法是修改坐标系的方式来实现上边描述的功能。上文我们已经实现了在document.body整个页面左上角顶点作为坐标原点来实现框选功能,这时候我们需要修改坐标原点为框选容器的左上角顶点作为坐标原点即可。
换言之,就是修改mousedown跟mousemove事件时,初始位置由原来的e.clientX跟e.clientY修改为e.clientX - selectContaienr.offsetLeft + selectContainer.scrollLeft跟e.clientY - selectContainer.offsetTop + selectContainer.scrollTop。
坐标更改shi'yi'tu
<html> <head> <title>region</title> <style> body { margin: 0; padding: 0; } #selectContainer { position: relative; width: 400px; /* 演示宽高与位置 */ height: 400px; top: 200px; left: 200px; border: 1px solid #eee; overflow: hidden; overflow-y: auto; } .fileDiv { display: inline-block; width: 100px; height: 100px; margin: 24px; background-color: #0082CC; } </style> </head> <body> <div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div> </body> </html>