Пользовательский курсор с перетаскиванием элемента HTML без библиотек

У меня есть HTML-страница с несколькими элементами перетаскивания. Наши спецификации говорят, что наведение мыши на такой элемент курсором должно быть grab grab, а во время перетаскивания курсор должен быть grabbing grabbing.

Я знаю, что можно установить dropEffect, который изменяет внешний вид курсора над областью сброса, но вариантов очень мало: copy, move, link и none - не является обычным или похожим.

Я попытался сменить курсор на Javascript и CSS, например, установить cursor: grabbing; при запуске ondragstart. Однако вместо перетаскивания в зону выпадения появляется указатель перемещения по умолчанию браузера.

Итак, вопрос: Что мне не хватает, чтобы показать захват курсора (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>

Ответ 1

Кажется, что браузеры не позволяют менять курсор в начале операции перетаскивания. Я не знаю, почему, но это известная проблема, я считаю, что они будут в будущем.

Если 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>

Ответ 2

Известный вопрос о здесь

При перетаскивании курсор автоматически изменится на нормальный.

Мои попытки дали мне следующее. Возьмите 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>

Ответ 3

Я знаю немного о перетаскиваемых элементах с чистым JavaScript, и мне жаль, что я не могу объяснить следующее.

Проблема заключалась в том, что onDragEnd никогда не срабатывает, поэтому я искал что-то и нашел этот пример с перетаскиваемыми элементами.
Теперь, если вы измените функцию события 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>

Ответ 4

Попробуйте это! Это работает для меня!

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

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

Ответ 5

Я провел какое-то время, чтобы найти решение для этого, закончилось этим трюком. Я считаю, что это лучший способ уменьшить количество кода и умение работать.

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

}

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