js鼠标框选元素

2,987 阅读1分钟

最近遇到一个需求,就是传统的勾选无法便捷的选择出我们要的元素,由此引申出新的需求,那就是鼠标框选多个元素。 然后自己手写了一个测试例子感觉还不错,在此记录一下。 总的来说就是利用鼠标的onmousedown,onmouseup,onmousemove这三个事件记录鼠标按下以及鼠标移动到最后的鼠标抬起时候的位置,能勾得出一个框选范围,同时在被选择的元素中进行遍历,对遍历元素的四条边框位置进行判断,满足条件及为在框选范围内,并对范围内元素的样式进行修改。若需要得出选择元素集合,只需要再定义一个数组接收选中的元素即可。

<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=gbk">
        <title>拉框</title>
        <style>
          /* html,body{
             margin: 0;
          } */
          .list{
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: row;
            padding: 10px;
            justify-content: flex-start;
            list-style: none;
            flex-wrap: wrap;
          }
          .listItem{
            list-style: none;
            margin-bottom: 6px;
            margin-right: 6px;
            width: 55px;
            height: 55px;
            border:1px solid #ccc;
          }
          .seled{border:1px solid red;background-color:#D6DFF7;} 

        </style>
    </head>
    <body>
        <div id='lay1'
            onmousedown='down(event)'
            onmouseup='up(event)'
            onmousemove='move(event)'
            style='width:400px;height:400px;visibility:visible;border:solid 1px blue;'
        >        
        <ul class="list">
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
          <li class="listItem"></li>
        </ul>   
        </div>   
    </div>
        <script language="javascript">
           
            // 是否需要(允许)处理鼠标的移动事件,默认识不处理
            var select = false;
            var lis =document.getElementsByClassName('listItem');
            // 定义移动元素div
            var rect = null;
            // 记录鼠标按下时的坐标
            var downX = 0;
            var downY = 0;
            // 记录鼠标抬起时候的坐标
            var mouseX2=downX;
            var mouseY2=downY;
           
            //处理鼠标按下事件
            function down(event){
                // 鼠标按下时才允许处理鼠标的移动事件
                select = true;
                rect = document.createElement("div"); 
                // 框选div 样式
                rect.style.cssText = "position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:1px dashed #0099FF;background-color:#C3D5ED;z-index:1000;filter:alpha(opacity:60);opacity:0.6;display:none;"; 
                rect.id = "selectDiv"; 
                // 添加到lay1下
                document.getElementById('lay1').appendChild(rect); 
                
             
                // 取得鼠标按下时的坐标位置
                downX =event.x ||event.clientX;
                downY = event.y||event.clientY;
                rect.style.left = downX + "px"; 
                rect.style.top = downY + "px"; 
                //设置你要画的矩形框的起点位置
                rect.style.left = downX;
                rect.style.top = downY;
            }
           
            //鼠标抬起事件
            function up(event){
              for (let i = 0; i < lis.length; i++) {
                  //将移动的div的四个点和和div元素的四个点进行比较
                  if (
                    //判断div元素 右边框的位置大于移动div的左起始点
                    rect.offsetLeft < (lis[i].offsetLeft + lis[i].offsetWidth ) &&
                    //判断div元素 下边框的位置大于移动div的上起始点
                    (lis[i].offsetTop + lis[i].offsetHeight) >rect.offsetTop
                    &&
                    // 判断div元素左边框的位置小于移动div的右起始点
                    rect.offsetLeft + rect.offsetWidth > lis[i].offsetLeft&&
                    // 判断div元素上边框的位置小于移动div的下起始点
                    rect.offsetTop + rect.offsetHeight > lis[i].offsetTop 
                  ) {
                    //将已选中的样式改变
                    if (lis[i].className.indexOf("seled") == -1) { 
                      lis[i].className = lis[i].className + " seled"; 
                    }
        
                  } else {
                    //如果没有选中则清除样式
                    if (lis[i].className.indexOf("seled") != -1) { 
                        lis[i].className = "listItem"; 
                    }
                  }
                }
                //鼠标抬起,就不允许在处理鼠标移动事件
                select = false;
                //隐藏图层
                if (rect) { 
                 document.getElementById('lay1').removeChild(rect); 
                } 
            }
           
            //鼠标移动事件,最主要的事件
            function move(event){
                /*
                这个部分,根据你鼠标按下的位置,和你拉框时鼠标松开的位置关系,可以把区域分为四个部分,根据四个部分的不同,
                我们可以分别来画框,否则的话,就只能向一个方向画框,也就是点的右下方画框.
               
                */
                if(select){
                    // 取得鼠标移动时的坐标位置
                    mouseX2 = event.clientX;
                    mouseY2 = event.clientY;
                    // 显示框选元素
                    if (rect.style.display == "none") { 
                      rect.style.display = ""; 
                    } 
                    rect.style.left = Math.min(mouseX2, downX) + "px"; 

                    rect.style.top = Math.min(mouseY2, downY) + "px"; 

                    rect.style.width = Math.abs(mouseX2 - downX) + "px"; 

                    rect.style.height = Math.abs(mouseY2 - downY) + "px";
                    // A part
                    if( mouseX2 < downX && mouseY2 < downY ){
                        rect.style.left = mouseX2;
                        rect.style.top = mouseY2 ;   
                    }
                   
                    // B part
                    if( mouseX2 > downX && mouseY2 < downY){
                        rect.style.left = downX ;
                        rect.style.top = mouseY2;   
                    }
                   
                    // C part
                    if( mouseX2 < downX && mouseY2 > downY){
                        rect.style.left = mouseX2;
                        rect.style.top = downY ;   
                    }
                   
                    // D part
                    if( mouseX2 > downX && mouseY2 > downY ){
                        rect.style.left = downX ;
                        rect.style.top = downY;
                    }           
           
                }
                
                // 阻止事件上传
                window.event.cancelBubble = true;
                // 阻止默认事件
                window.event.returnValue = false;   
                
            }
        </script>
    </body>
</html>