You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于VanillaJS的拖拽排序组件添加拖拽动画求助

Hey there! Awesome work getting that drag-and-drop grid up and running—it’s already functional, so adding smooth animations will take it to the next level. Let’s implement two key animations to match polished drag-and-drop UX: a floating preview of the dragged item, a placeholder to show where the item will land, plus smooth position transitions when items swap.

Key Animations We’ll Add

  • Drag Preview: A scaled, semi-transparent clone of the item that follows your mouse while dragging
  • Drop Placeholder: A dashed placeholder that appears when hovering over a target, letting you know where the item will slot in
  • Smooth Swap Transition: CSS transitions to make item position changes feel fluid instead of abrupt

Updated CSS

.icons {
    margin: auto;
    border: 1px solid black;
    width: 600px;
    height: 200px;
    display: grid;
    grid-template-columns: auto auto auto;
    grid-gap:20px;
}
.icons span {
    text-align: center;
    padding: 20px;
    background-color: blueviolet;
    font-size: 18px;
    border-radius: 8px;
    cursor: grab;
    /* Add smooth transition for position/color changes */
    transition: transform 0.3s ease, background-color 0.3s ease;
}
.icons span:active {
    cursor: grabbing;
}

/* Drag preview element */
.drag-preview {
    position: absolute;
    pointer-events: none;
    opacity: 0.7;
    transform: scale(1.1);
    transition: transform 0.2s ease;
    z-index: 1000;
}

/* Drop placeholder for target position */
.drop-placeholder {
    background-color: rgba(0,0,0,0.1);
    border: 2px dashed #666;
    border-radius: 8px;
    transition: all 0.2s ease;
}

Updated JavaScript

var icons=[ {order:1,name:"tel",bg:'red'}, {order:2,name:"facebook",bg:'green'}, {order:3,name:"whatsup",bg:'blue'}, {order:4,name:"waze",bg:'yellow'}, {order:5,name:"gallery",bg:'purple'}, {order:6,name:"insta",bg:'grey'} ];
let dragPreview = null; // Track the drag preview element

function rendericons(icons) {
    var zone=document.getElementById("icons");
    var sorticons = icons.slice(0);
    sorticons.sort(function(a,b) {return a.order - b.order; });
    var html="";
    for(var x in sorticons) {
        html+="<span style='background-color:"+sorticons[x]['bg']+"' id='"+sorticons[x]['order']+"' draggable='true'>"+sorticons[x]['name']+"</span>";
    }
    zone.innerHTML=html;
}

rendericons(icons);

document.addEventListener("dragstart", function(event) {
    event.dataTransfer.setData("Text", event.target.id);
    event.target.style.opacity = "0.4";

    // Create a preview element that follows the mouse
    dragPreview = event.target.cloneNode(true);
    dragPreview.classList.add("drag-preview");
    document.body.appendChild(dragPreview);
    updateDragPreviewPosition(event);
});

document.addEventListener("drag", function(event) {
    // Update preview position as mouse moves
    updateDragPreviewPosition(event);
});

document.addEventListener("dragend", function(event) {
    event.target.style.opacity = "1";
    // Clean up preview and placeholders
    if (dragPreview) {
        document.body.removeChild(dragPreview);
        dragPreview = null;
    }
    document.querySelectorAll(".drop-placeholder").forEach(el => el.remove());
});

// Handle placeholder on drag enter
document.addEventListener("dragenter", function(event) {
    if (event.target.tagName === "SPAN" && event.target.id !== event.dataTransfer.getData("Text")) {
        const placeholder = document.createElement("span");
        placeholder.classList.add("drop-placeholder");
        event.target.parentNode.insertBefore(placeholder, event.target);
    }
});

document.addEventListener("dragover", function(event) {
    event.preventDefault();
});

// Remove placeholder when leaving the target
document.addEventListener("dragleave", function(event) {
    if (event.target.tagName === "SPAN") {
        const placeholder = event.target.previousElementSibling;
        if (placeholder && placeholder.classList.contains("drop-placeholder")) {
            placeholder.remove();
        }
    }
});

document.addEventListener("drop", function(event) {
    event.preventDefault();
    var data = event.dataTransfer.getData("Text");
    var itemtoreplace=event.target.id;
    replaceitems(data,itemtoreplace);
});

function replaceitems(data,itemtoreplace) {
    if(itemtoreplace!="icons"){
        // Clean up placeholder before re-rendering
        document.querySelectorAll(".drop-placeholder").forEach(el => el.remove());
        
        var beforeindex=0;
        var replaceindex=0;
        for(x in icons) {
            if(icons[x]['order']==data) beforeindex=x;
            if(icons[x]['order']==itemtoreplace) replaceindex=x;
        }
        icons[beforeindex]['order']=itemtoreplace;
        icons[replaceindex]['order']=data;
        rendericons(icons);
    }
}

// Helper to update preview position
function updateDragPreviewPosition(event) {
    if (dragPreview) {
        // Center preview on mouse cursor
        dragPreview.style.left = `${event.clientX - dragPreview.offsetWidth / 2}px`;
        dragPreview.style.top = `${event.clientY - dragPreview.offsetHeight / 2}px`;
    }
}

Updated HTML (no changes needed, included for completeness)

<div id="icons" class="icons droptarget"></div>

How It Works

  1. Drag Preview: When you start dragging, we clone the active element, style it to look like a floating preview, and update its position every time the mouse moves. This gives clear visual feedback of what you’re dragging.
  2. Drop Placeholder: When hovering over another item, a dashed placeholder appears to indicate where the dragged item will be placed. It disappears when you move away from the target.
  3. Smooth Transitions: We added transition to the grid items so when their positions swap (via re-rendering), they move smoothly instead of jumping. The preview also scales slightly for extra emphasis during the drag.

内容的提问来源于stack exchange,提问作者davidi sheleg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:28:53