• JavaScript DOM 鼠标拖拽


    JavaScript DOM 鼠标拖拽

    在前端页面交互中,鼠标拖拽是一个体验良好的功能,实现鼠标拖拽需要了解鼠标行为坐标系和涉及到的许多兼容性写法。本文介绍鼠标位置的获取和、拽功能的实现以及拖拽函数的封装

    鼠标行为坐标系

    1. 鼠标行为触发事件时,事件对象上会有一些属性提供鼠标的位置信息

      属性 功能 兼容性
      clientX/Y 鼠标相对可视区域的坐标 /
      x/y 与 clientX/Y 功能相同 firefox 低版本不支持
      pageX/Y 鼠标相对整个文档的坐标 兼容 IE9 及以上
      layerX/Y 与 pageX/Y 功能相同 IE10 及以下同 clientX/Y
      screenX/Y 鼠标位置相对屏幕坐标 /
      offsetX/Y 鼠标位置相对块元素的坐标(包含边框) safari 不包含边框
    2. 获取鼠标相对整个文档的坐标:pageX/Y 兼容性差,需要进行封装

      鼠标相对整个文档的坐标 = 鼠标相对可视区域的坐标 + 滚动条滚动距离 - 文档偏移

      document.documentElement.clientTop 获取文档偏移,在 IE 一些版本中为 undefined

      function pagePos(ev) {
          var sTop = getScrollOffset().top,
              sLeft = getScrollOffset().left,
              cTop = document.documentElement.clientTop || 0,
              cLeft = document.documentElement.clientLeft || 0;
          return {
              X: ev.clientX + sLeft - cLeft,
              Y: ev.clientY + sTop - cTop
          }
      }
      // 封装的函数:获取滚动条滚动距离
      function getScrollOffset() {
          if (window.pageXOffset) {
              return {
                  top: window.pageYOffset,
                  left: window.pageXOffset
              }
          }
          else return {
              top:document.body.scrollTop || document.documentElement.scrollTop,
              left:document.body.scrollLeft || document.documentElement.scrollLeft
          }
      }
      

    拖拽函数封装

    1. 拖拽效果基于鼠标事件:mousedown、mousemove、mouseup

      分别为鼠标按下、鼠标移动、鼠标松开

    2. 原理:鼠标按下时,添加鼠标移动、鼠标松开的事件处理函数,鼠标移动时获取鼠标坐标,改变元素样式,鼠标松开时清除鼠标移动和鼠标松开的事件处理函数

      <!doctype html>
      <html lang="zh">
      <head>
          <meta charset="UTF-8">
          <title>Index</title>
          <style type="text/css">
              .box {
                  position: absolute;
                  top: 0;
                  left: 0;
                   100px;
                  height: 100px;
                  background-color: red;
              }
          </style>
      </head>
      <body>
      <div class="box"></div>
      <script>
          var box = document.getElementsByTagName('div')[0];
      
          box.onmousedown = function (ev) {
              var ev = ev || window.event,
                  x = pagePos(ev).X - parseInt(getStyles(box)['left']),
                  y = pagePos(ev).Y - parseInt(getStyles(box)['top']);
      
              document.onmousemove = function (ev) {
                  var ev = ev || window.event,
                      mPos = pagePos(ev);
                  box.style.left = mPos.X - x + 'px';
                  box.style.top = mPos.Y - y + 'px';
              }
              document.onmouseup = function () {
                  this.onmousemove = null;
                  this.onmouseup = null;
              }
          }
      
          // 封装的函数:获取鼠标相对整个文档的坐标
          function pagePos(ev) {
              var sTop = getScrollOffset().top,
                  sLeft = getScrollOffset().left,
                  cTop = document.documentElement.clientTop || 0,
                  cLeft = document.documentElement.clientLeft || 0;
              return {
                  X: ev.clientX + sLeft - cLeft,
                  Y: ev.clientY + sTop - cTop
              }
          }
      	// 封装的函数:获取滚动条滚动距离
          function getScrollOffset() {
              if (window.pageXOffset) {
                  return {
                      top: window.pageYOffset,
                      left: window.pageXOffset
                  }
              } else return {
                  top: document.body.scrollTop || document.documentElement.scrollTop,
                  left: document.body.scrollLeft || document.documentElement.scrollLeft
              }
          }
      
          // 封装的函数:获取元素样式的类数组
          function getStyles(elem) {
              if (window.getComputedStyle) {
                  return window.getComputedStyle(elem, null);
              } else return elem.currentStyle;
          }
      </script>
      </body>
      </html>
      
    3. 封装拖拽函数

      var box = document.getElementsByTagName('div')[0];
      elemDrag(box);
      
      // 封装的拖拽函数
      function elemDrag(elem) {
          var x,
              y;
          addEvent(elem, 'mousedown', function (ev) {
              var ev = ev || window.event;
              x = pagePos(ev).X - parseInt(getStyles(elem)['left']);
              y = pagePos(ev).Y - parseInt(getStyles(elem)['top']);
              addEvent(document, 'mousemove', mousemove);
              addEvent(document, 'mouseup', mouseup);
              cancelBubble(ev);
              preventDefaultEvent(ev);
          });
      
          function mousemove(ev) {
              var ev = ev || window.event;
              elem.style.left = pagePos(ev).X - x + 'px';
              elem.style.top = pagePos(ev).Y - y + 'px';
          }
      
          function mouseup(ev) {
              var ev = ev || window.event;
              removeEvent(document, 'mousemove', mousemove);
              removeEvent(document, 'mouseup', mouseup);
          }
      
      }
      // 绑定事件处理函数
      function addEvent(elem, type, fn) {
          if (elem.addEventListener) {
              elem.addEventListener(type, fn);
          } else if (elem.attachEvent) {
              elem.attachEvent('on' + type, function (ev) {
                  fn.call(elem, ev); // call 兼容性比 bind 好
              });
          } else {
              elem['on' + type] = fn;
          }
      }
      // 解绑事件处理函数
      function removeEvent(elem, type, fn) {
          if (elem.addEventListener) {
              elem.removeEventListener(type, fn);
          } else if (elem.attachEvent) {
              elem.detachEvent('on' + type, fn);
          } else {
              elem['on' + type] = null;
          }
      }
      // 获取鼠标在整个文档中的坐标
      function pagePos(ev) {
          var sTop = getScrollOffset().top,
              sLeft = getScrollOffset().left,
              cTop = document.documentElement.clientTop || 0,
              cLeft = document.documentElement.clientLeft || 0;
          return {
              X: ev.clientX + sLeft - cLeft,
              Y: ev.clientY + sTop - cTop
          }
      }
      // 获取滚动条滚动距离
      function getScrollOffset() {
          if (window.pageXOffset) {
              return {
                  top: window.pageYOffset,
                  left: window.pageXOffset
              }
          } else return {
              top: document.body.scrollTop || document.documentElement.scrollTop,
              left: document.body.scrollLeft || document.documentElement.scrollLeft
          }
      }
      // 获取元素样式的类数组
      function getStyles(elem) {
          if (window.getComputedStyle) {
              return window.getComputedStyle(elem, null);
          } else return elem.currentStyle;
      }
      // 阻止冒泡
      function cancelBubble(ev) {
          if (ev.stopPropagation) {
              ev.stopPropagation();
          } else ev.cancelBubble = true; // 兼容 IE8 及以下
      }
      // 阻止默认事件
      function preventDefaultEvent(ev) {
          if (ev.preventDefault) {
              ev.preventDefault();
          } else ev.returnValue = false; // 兼容 IE8 及以下
      }   
      
  • 相关阅读:
    Mycat适合场景及不适合场景
    solr与Elasticsearch对比
    分布式搜索之搭建Solrcloud(Solr集群)
    Mysql索引最左匹配原则
    CAS实现单点登录SSO执行原理及部署
    Spring Cloud,Dubbo及HSF对比
    Dubbo支持的协议的详解
    Dubbo架构设计详解
    几种分布式锁的实现方式
    深入分析volatile的实现原理
  • 原文地址:https://www.cnblogs.com/pgjett/p/12636333.html
Copyright © 2020-2023  润新知