web-dev-qa-db-fra.com

Curseur personnalisé avec glisser-déposer d'un élément HTML sans bibliothèques

J'ai une page HTML qui contient des éléments déplaçables. Nos spécifications indiquent qu'en pointant la souris sur cet élément, le curseur doit être grab grab , et pendant que vous faites glisser le curseur doit être grabbing grabbing .

Je sais qu'il est possible de définir dropEffect qui modifie l'apparence du curseur au-dessus de la zone de dépôt, mais il existe très peu d'options: copy, move, link et none - no custom ou similaire.

J'ai essayé de changer le curseur avec Javascript et CSS, comme pour le paramètre cursor: grabbing; quand ondragstart est déclenché. Mais le curseur de déplacement par défaut du navigateur apparaît à la place lorsque vous faites glisser la zone de dépôt.

La question est donc la suivante:Que me manque-t-il pour afficher le curseur de saisie (  grabbing ) pendant le drag?

Malheureusement, je ne peux pas utiliser JQuery ou d'autres bibliothèques d'aide dans la solution. Merci d'avance!

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>

13
Travenin

Il semble que les navigateurs ne permettent pas de changer le curseur au début d’une opération de glisser-déposer. Je ne sais pas pourquoi mais c'est un problème connu, je pense qu'ils le seront à l'avenir.

Si jQuery n'est pas une option, vous pouvez implémenter un glisser-déposer à partir de zéro, en utilisant des événements de souris et en clonant l'élément source:

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
Javier Rey

C'est un problème connu rapporté ici

En glissant, le curseur se changera automatiquement en normal.

Mes essais m'ont donné le suivant. A donné une active sur l'élément avec le curseur de saisie. Pendant qu'il est actif, le curseur changera mais une fois que vous aurez commencé le glissement, il changera automatiquement.

J'ai essayé de définir le curseur body pour saisir sur dragstart mais aucun résultat. Même cela ne fonctionne pas. 

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>

5
Sagar V

Essaye ça ! Ça marche pour moi !

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

.draggable:active {
    cursor: -webkit-grabbing;
    cursor: grabbing;
}
0
Richard Foucaud

Je connais juste un peu les éléments déplaçables avec JavaScript pur et je suis désolé de ne pouvoir expliquer ce qui suit.

Le problème était que la onDragEnd ne se faisait jamais virer. J'ai donc cherché quelque chose et trouvé ce exemple avec des éléments déplaçables.
Maintenant, si vous modifiez la fonction de l'événement onDragStart, cela fonctionnera, mais je pense que vous devez modifier le curseur d'une autre manière, par exemple pour changer la classe du corps onDragStart

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

Tout en un

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>

0
UfguFugullu

J’ai passé quelque temps à trouver une solution à cela, a terminé avec cette astuce. Je pense que c'est la meilleure façon moins de code et de travail.

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

}

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