自定义光标与拖放没有库的 HTML 元素

Posted

技术标签:

【中文标题】自定义光标与拖放没有库的 HTML 元素【英文标题】:Custom cursor with drag and drop an HTML element without libraries 【发布时间】: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,你会得到最接近的。 【参考方案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 中提供了一个错误修复(编辑了我的问题),但我真正的问题是抓取光标,而您的回答没有提供。

以上是关于自定义光标与拖放没有库的 HTML 元素的主要内容,如果未能解决你的问题,请参考以下文章

拖放DataGrid中下降,拖动过程中自定义光标不工作

为啥自定义光标图像显示不正确?

通过拖放将自定义元素的对象引用传递给另一个自定义元素

如何在html拖放中设置自定义数据

HTML5元素拖拽drag与拖放drop相关API

HTML5元素拖拽drag与拖放drop相关API