zoukankan      html  css  js  c++  java
  • JavaScript进阶之实现拖拽

    最近做到的react项目就有一个拖拽的需求,然后大概搜索了一下,找到了star比较高的react-dnd库,但是阅读react-dnd的官方文档还是有点难受的,因为概念性比较强,所以在介绍react-dnd之前我们来实现原生拖拽

    原生实现拖拽

    Mouse事件实现拖拽

    在h5之前,原生实现拖拽是根据Mouse事件来实现的,需要用到以下这三个事件mousedown,mouseup,mousemove

    • mousedown 事件在指针设备按钮按下时触发。

    • mouseup事件在指针设备按钮抬起时触发。

    • 当指针设备( 通常指鼠标 )在元素上移动时, mousemove 事件被触发。

    JavaScript三大家族

    明白了上述????三个事件方法的作用以及JavaScript三大家族,我们来实现个简单版的拖拽

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <img id="ball" src="https://js.cx/clipart/ball.svg" alt="">
        <script>
           const ball=document.querySelector("#ball")
           ball.onmousedown = function(event) {
           let shiftX = event.clientX - ball.getBoundingClientRect().left;
           let shiftY = event.clientY - ball.getBoundingClientRect().top;
            ball.style.position = 'absolute';
            ball.style.zIndex = 1000;
            document.body.append(ball);
            moveAt(event.pageX, event.pageY);
            // 移动现在位于坐标 (pageX, pageY) 上的球
            // 将初始的偏移考虑在内
            function moveAt(pageX, pageY) {
            ball.style.left = pageX - shiftX + 'px';
            ball.style.top = pageY - shiftY + 'px';
            }
            function onMouseMove(event) {
            moveAt(event.pageX, event.pageY);
            }
            // 在 mousemove 事件上移动球
            document.addEventListener('mousemove', onMouseMove);
            // 放下球,并移除不需要的处理程序
            ball.onmouseup = function() {
            document.removeEventListener('mousemove', onMouseMove);
            ball.onmouseup = null;
            };
            };
            ball.ondragstart = function() {
            return false;
        };
        </script>
    </body>
    </html>
    

    效果如下:

    注意

    ball.ondragstart = function() {
      return false;
    };
    

    如果不设置这段代码,会发生奇怪的现象,这是因为浏览器有自己的对图片和一些其他元素的拖放处理,会在我们拖放时自动运行,这与我们的拖放处理产生了冲突。

    HTML 拖放(Drag and Drop)

    拖拽事件

    HTML 的 drag & drop 使用了 DOM event model 以及从mouse events 继承而来的 drag events 。一个典型的drag操作是这样开始的:用户用鼠标选中一个可拖动的(draggable)元素,移动鼠标到一个可放置的(droppable)元素,然后释放鼠标。在操作期间,会触发一些事件类型,有一些事件类型可能会被多次触发(比如drag 和 dragover 事件类型)

    • drag: 拖拽源

    • drop:拖拽源最终放置的目标

    • DataTransfer 对象:退拽对象用来传递的媒介,使用一般为Event.dataTransfer。

    • draggable 属性:就是标签元素要设置draggable=true

    • ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上

    • ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此事件作用在目标元素上

    • ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上

    • ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上

    • ondragend 事件:当拖拽完成后触发的事件,此事件作用在被拖曳元素上

    • Event.preventDefault()方法:阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。Event.effectAllowed 属性:就是拖拽的效果。

    注意理解上述????的概念有注意理解react-dnd库的api

    举个例子????:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
        />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <style>
          body {
            font: 16px Arial, Helvetica, sans-serif;
          }
          li {
            200px;
            height: 40px;
            text-align: center;
            line-height: 40px;
            border:1px dashed #cccccc; 
            cursor: pointer;
            user-select: none;
            background-color: white;
            list-style: none;
          }
          .more {
            border-top: 1px dotted rgb(196, 196, 196);
            font-size: 12px;
            padding-top: 10px;
          }
          .more,
          .more a {
            color: rgb(96, 96, 96);
          }
        </style>
      </head>
      <body>
        <ul>
          <li
            draggable="true"
            ondragend="dragEnd()"
            ondragover="dragOver(event)"
            ondragstart="dragStart(event)"
          >
            Apples
          </li>
          <li
            draggable="true"
            ondragend="dragEnd()"
            ondragover="dragOver(event)"
            ondragstart="dragStart(event)"
          >
            Oranges
          </li>
          <li
            draggable="true"
            ondragend="dragEnd()"
            ondragover="dragOver(event)"
            ondragstart="dragStart(event)"
          >
            Bananas
          </li>
          <li
            draggable="true"
            ondragend="dragEnd()"
            ondragover="dragOver(event)"
            ondragstart="dragStart(event)"
          >
            Strawberries
          </li>
        </ul>
        <script>
          var selected;
          const li = document.createElement("li");
          function dragOver(e) {
            // 向前拖拽 向后拖拽
            // 拖动目标(drop)是不是在拖拽源(drag)的前面
            if (isBefore(selected, e.target)){         
               e.target.parentNode.insertBefore(selected, e.target);
            }else {e.target.parentNode.insertBefore(selected, e.target.nextSibling);}
          }
    
          function dragEnd() {
            selected = null;
          }
    
          function dragStart(e) {
            selected = e.target;
            console.log(selected)
          }
    
          function isBefore(el1, el2) {
            var cur;
            if (el2.parentNode === el1.parentNode) {
              for (cur = el1.previousSibling; cur; cur = cur.previousSibling) {
                if (cur === el2) return true;
              }
            } else return false;
          }
        </script>
      </body>
    </html>
    

    效果图:

    是不是很接近我们的需求啦

    自定义拖动图像

    拖动过程中,浏览器会在鼠标旁显示一张默认图片。当然,应用程序也可以通过 setDragImage() 方法自定义一张图片,如下面的例子所示。

     function dragStart(e) {
            selected = e.target;
            dragstart_handler(e)
            // 延时是为了浏览器能生成拖拽图片
            setTimeout(()=>{
              selected.style.opacity='0'
            },0)
          }
       function dragstart_handler(ev) {
          var img = new Image(); 
          img.src = 'https://js.cx/clipart/ball.svg'; 
          ev.dataTransfer.setDragImage(img, 10, 10);
         }
    

    定义拖动效果

    dropEffect 属性用来控制拖放操作中用户给予的反馈。它会影响到拖动过程中浏览器显示的鼠标样式。比如,当用户悬停在目标元素上的时候,浏览器鼠标也许要反映拖放操作的类型。

    有 3 个效果可以定义:

    • copy 表明被拖动的数据将从它原本的位置拷贝到目标的位置。

    • move 表明被拖动的数据将被移动。

    • link 表明在拖动源位置和目标位置之间将会创建一些关系表格或是连接。

    参考:MDN HTML5 drag & drop 拖拽与拖放简介 

  • 相关阅读:
    POJ
    hdu 5652
    CodeForces
    #6285. 数列分块入门 9
    #6284. 数列分块入门 8
    #6283. 数列分块入门 7
    #6282. 数列分块入门 6
    #6280. 数列分块入门 4 #6281. 数列分块入门 5
    #6278. 数列分块入门 2和#6278. 数列分块入门 3
    spark-sklearn TypeError: 'JavaPackage' object is not callable
  • 原文地址:https://www.cnblogs.com/vnues/p/14300331.html
Copyright © 2011-2022 走看看