【问题标题】:Custom cursor with drag and drop an HTML element without libraries自定义光标与拖放没有库的 HTML 元素
【发布时间】:2017-11-10 20:19:39
【问题描述】:

我有一个包含一些可拖动元素的 HTML 页面。我们的规范规定,将鼠标悬停在此类元素上时,光标必须grab,并且在拖动期间光标必须grabbing

我知道可以设置 dropEffect 来改变拖放区上方的光标外观,但选项很少:copymovelinknone -- 没有 自定义 或类似的。

我尝试使用 Javascript 和 CSS 更改光标,例如在触发 ondragstart 时设置 cursor: grabbing;。但是在拖放区域上拖动时会出现浏览器默认的移动光标。

所以问题是:在拖动过程中我缺少什么来显示抓取光标 ()?

不幸的是,我无法在解决方案中使用 JQuery 或其他帮助库。提前致谢!

var onDragStart = function(event) {
    event.dataTransfer.setData("Text", event.target.id);
    event.currentTarget.classList.add("being-dragged");
};

var onDragEnd = function(event) {
    event.currentTarget.classList.remove("being-dragged");
};

var onDragOver = function(event) {
    event.preventDefault();
};
.dropzone {
    width: 500px;
    height: 200px;
    background-color: silver;
}

.block {
    position: absolute;
    background-color: pink;
    margin: 10px;
    border: 20px solid pink;
}

.draggable {
    cursor: -webkit-grab;
    cursor: grab;
}

.being-dragged {
    cursor: -webkit-grabbing;
    cursor: grabbing;
    background-color: red;
}
<div class      = "dropzone"
    ondragover  = "onDragOver(event);"
    >
    Grab and drag block around
    <div class      = "draggable block"
        draggable   = "true"
        ondragstart = "onDragStart(event);"
        ondragend   = "onDragEnd(event);"
        >
        I'm draggable
    </div>
</div>

【问题讨论】:

  • 应该是简单的JavaScript 还是你也会使用jQuery?如果你会使用jQuery,那么你会使用jQuery UIs Draggable 插件吗?
  • 纯 JS。 jQuery 无法使用,抱歉。
  • 您将不得不使用假光标;跟随鼠标的img。这将与本机图标一起显示,因此您需要使其与外观相得益彰,而不是与之竞争。 afaik,你会得到最接近的。

标签: javascript html css drag-and-drop


【解决方案1】:

为了弄清楚这一点,我经历了很多痛苦。接受的答案网络上的最佳答案,但现在的最佳做法是使用元素的 .setPointerCapture 事件,它允许您在元素上收听类似拖动的行为并采取行动限制在Drag API 的狭隘行为中。一种方法是这样的:

el.onpointerdown = ev => {
    el.onpointermove = pointerMove 
    el.setPointerCapture(ev.pointerId)
}

pointerMove = ev => {
    console.log('Dragged!')
}

el.onpointerup = ev => {
    el.onpointermove = null
    el.releasePointerCapture(ev.pointerId)
}

显而易见的礼物是,这里没有发现潜行在后门中的光标劫持。

【讨论】:

    【解决方案2】:

    似乎浏览器不允许在拖放操作开始时更改光标。我不知道为什么,但这是一个已知问题,我相信他们将来会这样做。

    如果 jQuery 不是一个选项,一种可能的解决方法是从头开始实现拖放,使用鼠标事件并克隆源元素:

    var onDragStart = function (event) {
      event.preventDefault();
      var clone = event.target.cloneNode(true);
      clone.classList.add("dragging");
      event.target.parentNode.appendChild(clone);
      var style = getComputedStyle(clone);
      clone.drag = {
        x: (event.pageX||(event.clientX+document.body.scrollLeft)) - clone.offsetLeft + parseInt(style.marginLeft),
        y: (event.pageY||(event.clientY+document.body.scrollTop)) - clone.offsetTop + parseInt(style.marginTop),
        source: event.target
      };
    };
    
    var onDragMove = function (event) {
      if (!event.target.drag) {return;}
      event.target.style.left = ((event.pageX||(event.clientX+document.body.scrollLeft)) - event.target.drag.x) + "px";
      event.target.style.top = ((event.pageY||(event.clientY+document.body.scrollTop)) - event.target.drag.y) + "px";
    };
    
    var onDragEnd = function (event) {
      if (!event.target.drag) {return;}
      // Define persist true to let the source persist and drop the target, otherwise persist the target.
      var persist = true;
      if (persist || event.out) {
        event.target.parentNode.removeChild(event.target);
      } else {
        event.target.parentNode.removeChild(event.target.drag.source);
      }
      event.target.classList.remove("dragging");
      event.target.drag = null;
    };
    
    var onDragOver = function (event) {
      event.preventDefault();
    };
    .dropzone {
      width: 500px;
      height: 200px;
      background-color: silver;
    }
    
    .block {
      position: absolute;
      background-color: pink;
      margin: 10px;
      border: 20px solid pink;
    }
    
    .draggable {
      position: absolute;
      cursor: pointer; /* IE */
      cursor: -webkit-grab;
      cursor: grab;
    }
    
    .dragging {
      cursor: -webkit-grabbing;
      cursor: grabbing;
      background-color: red;
    }
    <div class="dropzone" onmouseover="onDragOver(event);">
      Grab and drag block around
      <div class    = "draggable block"
        onmousedown = "onDragStart(event);"
        onmousemove = "onDragMove(event);"
        onmouseup   = "onDragEnd(event);"
        onmouseout  = "event.out = true; onDragEnd(event);"
      >
        I'm draggable
      </div>
    </div>

    【讨论】:

    • 浏览器似乎不支持原生拖动事件中的自定义光标,这很可悲。你的回答最接近我的预期。谢谢。
    【解决方案3】:

    我花了一些时间来解决这个问题,以这个技巧结束。我觉得这是减少代码和恰当工作的最佳方式。

    .drag{
        cursor: url('../images/grab.png'), auto; 
    
    }
    
    .drag:active {
        cursor: url('../images/grabbing.png'), auto;
    }
    

    【讨论】:

      【解决方案4】:

      试试这个!它对我有用!

      .draggable {
          cursor: -webkit-grab;
          cursor: grab;
      }
      
      .draggable:active {
          cursor: -webkit-grabbing;
          cursor: grabbing;
      }
      

      【讨论】:

      • 不适合我。您使用的是哪种浏览器和操作系统?我使用的是 Windows 和最新的 Chrome 和 Firefox。
      • 我使用的是 Windows 8 和 Chrome 59,对我来说没问题
      • 在这个 JS fiddle 中也有? jsfiddle.net/7Lrofezt我将您的答案与我的代码结合在一起。
      • 好的,我明白了.. 移动框时光标会发生变化。我试图修改你的 jsfiddle 来帮助你解决这个问题,但我还不能。祝你好运
      【解决方案5】:

      这是一个已知问题报告here

      拖动时,光标会自动变正常。

      我的尝试给了我以下信息。使用抓取光标在元素上添加active。当它处于活动状态时,光标会改变,但一旦你开始拖动,它会自动改变。

      我尝试将 body 光标设置为在 dragstart 上抓取但没有结果。即使它不起作用。

      var onDragStart = function(event) {
          event.dataTransfer.setData("Text", event.target.id);
          event.currentTarget.classList.add("being-dragged");
      };
      
      var onDragEnd = function(event) {
          event.currentTarget.classList.remove("being-dragged");
      };
      
      var onDragOver = function(event) {
          event.preventDefault();
      };
      .dropzone {
          width: 500px;
          height: 200px;
          background-color: silver;
      }
      
      .block {
          position: absolute;
          background-color: pink;
          margin: 10px;
          border: 20px solid pink;
      }
      
      .draggable {
          cursor: -webkit-grab;
          cursor: grab;
      }
      
      .draggable:active{
          cursor : -moz-grabbing;
          cursor: -webkit-grabbing;
          cursor: grabbing;
      }
      .being-dragged{
          background-color: red;
          cursor : -moz-grabbing;
          cursor: -webkit-grabbing;
          cursor: grabbing;
      }
      <div class      = "dropzone"
          ondragover  = "onDragOver(event);"
          >
          Grab and drag block around
          <div class      = "draggable block"
              draggable   = "true"
              ondragstart = "onDragStart(event);"
              ondragend   = "onDragEnd(event);"
              >
              I'm draggable
          </div>
      </div>

      【讨论】:

        【解决方案6】:

        我对纯JavaScript 的可拖动元素了解一点,很抱歉我无法解释以下内容。

        问题是onDragEnd 永远不会被解雇,所以我搜索了一些东西并找到了这个带有可拖动元素的example
        现在,如果您更改 onDragStart 事件的功能,它将起作用,但我认为您必须以另一种方式更改光标,例如更改主体的类 onDragStart

        var onDragStart = function(event) {
          event.dataTransfer.setData("Text", event.target.id);
          event.currentTarget.classList.add("being-dragged");
        };
        

        一体机

        var onDragStart = function(event) {
          event.dataTransfer.setData("Text", event.target.id);
          event.currentTarget.classList.add("being-dragged");
        };
        var onDragEnd = function(event) {
          event.currentTarget.classList.remove("being-dragged");
        };
        var onDragOver = function(event) {
          event.preventDefault();
        };
        .dropzone {
          width: 500px;
          height: 500px;
          background-color: silver;
        }
        .block {
          width: 200px;
          height: 50px;
          background-color: pink;
        }
        .draggable1 {
          cursor: -webkit-grab;
          cursor: grab;
        }
        .being-dragged {
          cursor: -webkit-grabbing;
          cursor: grabbing;
          background-color: red;
        }
        <div class="dropzone" ondragover="onDragOver(event);">
          <div class="draggable1 block" draggable="true" ondragstart="onDragStart(event);" ondragend="onDragEnd(event);">
            I'm draggable
          </div>
        </div>

        【讨论】:

        • 感谢您的回答,它在我的 sn-p 中提供了一个错误修复(编辑了我的问题),但我真正的问题是抓取光标,而您的回答没有提供。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-11
        • 2010-10-17
        • 2011-12-19
        相关资源
        最近更新 更多