Q01: JS分栏效果问题——发现鼠标拖动分割线经过下边的iframe的时候就失效

693 阅读1分钟

问题描述:JS分栏效果问题:发现鼠标拖动分割线向上拖拽,然后鼠标弹起后正常;鼠标拖动分割线向下,然后鼠标弹起后,发现还可以继续拖拽分割线,这是不正常的。经过分析发现是以为鼠标弹起的时候坐落在了iframe上导致鼠标弹起事件失效。

效果图:

image.png

问题代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
    /* 拖拽相关样式 */
    .box {
      width: 100%;
      height: 100%;
      margin: 1% 0px;
      overflow: hidden;
      box-shadow: -1px 9px 10px 3px rgba(0, 0, 0, 0.11);
    }
    /*底部div样式*/
    .bottom {
      position: absolute;
      bottom: 0;
      height: 200px;  
      width: 100%;
      background: #fff;
    }
    /*拖拽区div样式*/
    .resize {
      position: absolute;
      bottom: 203px;
      height: 3px;
      width: 100%;
      color: #fff;
      background-color: #ccc;
      border-radius: 5px;
      cursor: row-resize;
    }
    /*拖拽区鼠标悬停样式*/
    .resize:hover {
      color: #999;
    }
  </style>
  <script>
    /* 
    遇到的问题:最初写的时候,发现鼠标拖动分割线经过左右两边的iframe的时候就不灵了。
    */
    window.onload = function () {
      var resize = document.getElementsByClassName('resize')[0];
      var bottom = document.getElementsByClassName('bottom')[0];
      var box = document.getElementsByClassName('box')[0];
      // 鼠标按下事件
      resize.onmousedown = function (e) {
          //颜色改变提醒
          resize.style.background = '#818181';
          var startY = e.clientY;
          resize.bottom = bottom.offsetHeight;
          
          function moveHandle (e) {
            var endY = e.clientY;
            var moveLen = resize.bottom + (startY - endY); 

            resize.style.bottom = Math.max(0, moveLen) + 'px'; // 设置底部区域的高度
            console.log('resize.bottom: ' + resize.style.bottom, moveLen)

            bottom.style.height = moveLen + 'px';
          }
          // 鼠标拖动事件
          document.onmousemove = moveHandle
          // 鼠标松开事件
          resize.onmouseup = document.onmouseup = function (evt) {
              //颜色恢复
              resize.style.background = '#d6d6d6';
              document.onmousemove = null;
              document.onmouseup = null;
              resize.releaseCapture && resize.releaseCapture(); //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
          };
          resize.setCapture && resize.setCapture(); //该函数在属于当前线程的指定窗口里设置鼠标捕获
          return false;
      };
    }
  </script>
</head>
<body>
  <div class="box" ref="box">
    <div class="bottom">
        <!--底部div内容-->
        <iframe src="http://www.baidu.com" width="100%" height="100%" style="margin-top: 10px; border: none;"></iframe>
    </div>
    <div class="resize" title="收缩底边栏"></div>
  </div>
</body>
</html>

解决方案:这个问题给出的解决方案是,当鼠标按下去准备拖动分割线的时候,出现一个半透明的遮盖层,这个遮盖层的z-index比较高,那么鼠标在移动的时候其实是在这个遮盖层之上移动,这样就会触发mousemove。

最终代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    html, body { height: 100%; width: 100%; }
    /* 拖拽相关样式 */
    .box {
      width: 100%;
      height: 100%;
      overflow: hidden;
      box-shadow: -1px 9px 10px 3px rgba(0, 0, 0, 0.11);
    }
    /*底部div样式*/
    .bottom {
      position: absolute;
      bottom: 0;
      height: 200px;  
      width: 100%;
      background: #fff;
    }
    /*拖拽区div样式*/
    .resize {
      position: absolute;
      bottom: 200px;
      height: 8px;
      width: 100%;
      color: #fff;
      background-color: #eaeaea;
      border-radius: 5px;
      cursor: row-resize;
    }
    /*拖拽区鼠标悬停样式*/
    .resize:hover {
      color: #eaeaea;
    }
    .mask {
      position: absolute;
      /* height: 8px; */
      width: 100%;
      left: 0;
      top: -7px;
      z-index: 999;
      color: red;
      text-align: center;
    }
    .resize:hover .mask {
      color: blue;
    }
  </style>
  <script>
    /* 
    遇到的问题:最初写的时候,发现鼠标拖动分割线经过左右两边的iframe的时候就不灵了。
    这个问题给出的解决方案是:当鼠标按下去准备拖动分割线的时候,出现一个半透明的遮盖层,这个遮盖层的z-index比较高,那么鼠标在移动的时候其实是在这个遮盖层之上移动,这样就会触发mousemove。
    */

    function throttle(func, wait, options) {
        var timeout, context, args, result;
        var previous = 0;
        if (!options) options = {};

        var later = function() {
          previous = options.leading === false ? 0 : new Date().getTime();
          timeout = null;
          func.apply(context, args);
          if (!timeout) context = args = null;
        };

        var throttled = function() {
          var now = new Date().getTime();
          if (!previous && options.leading === false) previous = now;
          var remaining = wait - (now - previous);
          context = this;
          args = arguments;
          if (remaining <= 0 || remaining > wait) {
            if (timeout) {
              clearTimeout(timeout);
              timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if (!timeout) context = args = null;
          } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
          }
        };

        throttled.cancel = function() {
          clearTimeout(timeout);
          previous = 0;
          timeout = null;
        }

        return throttled;
    }

    window.onload = function () {
      var resize = document.getElementsByClassName('resize')[0];
      var mask = document.getElementsByClassName('mask')[0];
      var bottom = document.getElementsByClassName('bottom')[0];
      var box = document.getElementsByClassName('box')[0];
      
      resize.onmousedown = function (e) {
        var startY = e.clientY;
        mask.style.height = '300px';
        mask.style.background = 'transparent';
        console.log('bottom.offsetHeight: ' + bottom.offsetHeight)
        resize.bottom = bottom.offsetHeight;

        function moveHandle (e) {
          var endY = e.clientY;
          var clientHeight = document.documentElement.clientHeight || document.body.clientHeight
          var moveLen = resize.bottom + (startY - endY);

          if (moveLen > clientHeight) {
            moveLen = clientHeight
          }
          if (moveLen < 10) {
            moveLen = 0
          }

          resize.style.bottom = moveLen + 'px';
          bottom.style.height = moveLen + 'px';
        }
        
        document.onmousemove = throttle(moveHandle, 10)
        resize.onmouseup = document.onmouseup = function (evt) {
          mask.style.height = '8px';
          document.onmousemove = null;
          document.onmouseup = null;
          resize.releaseCapture && resize.releaseCapture(); //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
        };
        resize.setCapture && resize.setCapture(); //该函数在属于当前线程的指定窗口里设置鼠标捕获
        return false;
      };
    }
  </script>
</head>
<body>
  <div class="box" ref="box">
    <div class="bottom">
        <!--底部div内容-->
        <iframe src="http://www.baidu.com" width="100%" height="100%" style="margin-top: 10px; border: none;"></iframe>
    </div>
    <div class="resize" title="收缩底边栏"><div class="mask"></div></div>
  </div>
</body>
</html>

阿里云解决方案:

image.png