Implement a draggable Polyfill that beautifies native drag and drop

Implementation of drag and drop

Before html5 was popularized, it was troublesome to drag and drop elements. The general idea is to monitor events related to mouse movement. Here is the pseudo code

odiv.onmousedown = function(ev){
    //Record start position
document.onmousemove = function(ev){
    //Move target element
document.onmouseup = function(ev){
    //Cancel mouse movement event

html5 adds the drag and drop draggable standard, which makes drag and drop simple. You can realize various drag and drop functions only by listening to the drag and drop events of elements.

<div draggable="true">drag me</div>
In addition to setting the draggable="true" attribute, img and links are draggable by default

Of course, setting the draggable="true" element is only "draggable", and restore it after you let go. If you need to drag it to the specified location, you only need to record it in drop

dropbox.addEventListener('drop',function(ev){ = XX; = XX;


Native drag

Native drag has many advantages. You can learn about it by yourself, just like the difference between native and simulator.

However, a little bit of aesthetic pursuit will certainly not use the original default drag, because it is really not very good-looking.

Let's first look at the native drag effect


Native drag effect

The default drag effect is a translucent preview (called "ghost" temporarily). If the dragged element size is relatively small, the generated preview is acceptable, but translucent, as shown below

It's just that the "gradient" can't be seen from the outside, and it's hard to accept the "gradient" effect. Anyway, it's hard to see from the outside

Secondly, another effect is that the dragged elements remain still, but the dragged "ghost" is moving. If the background is a little more complex, it will be completely indistinguishable

Resource search website Encyclopedia Guangzhou VI design company

Custom native drag and drop

The native drag and drop is basically not customizable. The only thing that can be changed is the setDragImage method. You can specify a preview image to replace the default into the preview image. However, this method is also weak. The customized preview image is still semi transparent with the default effect. Secondly, it is also troublesome to generate the preview image of the current node in real time.

Another idea is actually easier, as follows.

  1. Remove default Preview
  2. Copy a copy of the current target element, cloneObj
  3. Monitor drag events and change the location of cloneObj
  4. Remove cloneObj after dragging

The following are pseudo codes. The complete code can be viewed at the end of the article

1. Remove the default preview

Although setDragImage is a chicken's rib, we can set a transparent image to remove the default preview image

dragbox.addEventListener('dragstart', function (ev) {
    var img = new Image();
    img.src = "data:image/svg+xml,%3Csvg xmlns='' %3E%3Cpath /%3E%3C/svg%3E";
    ev.dataTransfer.setDragImage(img, 0, 0);
After setting draggable="true" for common elements, Chrome can be dragged directly. FireFox needs to set EV in dragstart dataTransfer. SetData ('text ',' arbitrary value ') is OK

2. Copy a copy of the current target element, cloneObj

Copy a copy of the current target element and set attributes such as position:fixed, which can be suspended on the page and then added to the body, as follows

var cloneObj = this.cloneNode(true); = 'position:fixed;left:0;top:0;z-index:999;pointer-events:none;transform:translate3d( ' + left + 'px ,' + top + 'px,0);'

3. Monitor drag events and change the position of cloneObj

The drag event will be triggered when dragging an element. Similar to the mouse movement event, it can get the current mouse position (the mousemove event is not triggered during the drag process) and hide the original target

dragbox.addEventListener('drag', function (ev) {
    if(cloneObj){ = 'translate3d( ' + left + 'px ,' + top + 'px,0)'; = 'visible';

It's true for Chrome. Although FireFox can also trigger the drag event, it can't get the mouse position information (all 0). Therefore, we can only monitor on the dragover. Although it's not perfect, it's also a method

document.addEventListener('dragover', function (ev) {
    if(cloneObj){ = 'translate3d( ' + left + 'px ,' + top + 'px,0)';    

4. Remove cloneObj after dragging

After dragging, remove cloneObj and restore the original target

oDiv.addEventListener('dragend', function (ev) {
    cloneObj = null; = 'visible';


According to the above ideas, a draggable polyfill is completed. The function of this polyfill is very simple. It only beautifies the original drag and drop, removes the original translucent preview, and does not change the original logic. This patch can be applied as long as the original drag and drop is used in the project.

Project address

The use method is also very simple. It can be directly referenced

<script src="./lib/draggable-polyfill.js"></script>

If it is an engineering project, npm installation can also be used

npm i draggable-polyfill

Then you can import it directly

import draggable-polyfill;

More examples are available

It should be noted that since only the current node is copied, if your style depends on the parent, the copied style will be different from the original target

.parent .dragbox{
/*Change to*/


Other skills

You can find a native drag and drop case on the Internet and paste the above draggable Polyfill directly on the console JS, you can "try" it immediately. For example, in this example, open the console, paste it, and then enter to see the drag effect (as follows).

Tags: Javascript

Posted by Kaizard on Sun, 01 May 2022 23:51:44 +0300