在现代Web开发中,拖拽交互是提升用户体验的有效手段。本文将介绍如何使用原生JavaScript实现基本的拖拽功能,并展示如何通过触摸事件适配移动设备。此外,我们还将使用SortableJS库演示如何在栅格布局中拖拽移动卡片,为构建响应式的交互界面提供解决方案。

使用原生JavaScript实现拖拽功能

HTML 结构

我们将定义一个具有特定样式的<div>元素,用户可以在页面上自由拖动这个元素。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Drag and Drop Example</title>
<style>
    #draggable {
        width: 100px;
        height: 100px;
        background-color: teal;
        position: absolute;
        cursor: pointer;
    }
</style>
</head>
<body>
<div id="draggable">Drag me!</div>
<script src="app.js"></script>
</body>
</html>

JavaScript 代码

app.js文件中,我们编写代码来处理拖拽逻辑,包括监听鼠标事件和触摸事件。

document.addEventListener('DOMContentLoaded', function () {
    const elem = document.getElementById('draggable');
    let offsetX = 0, offsetY = 0, isDragging = false;

    const startDrag = (x, y) => {
        isDragging = true;
        offsetX = x - elem.getBoundingClientRect().left;
        offsetY = y - elem.getBoundingClientRect().top;
    };

    const stopDrag = () => {
        isDragging = false;
    };

    const doDrag = (x, y) => {
        if (isDragging) {
            elem.style.left = (x - offsetX) + 'px';
            elem.style.top = (y - offsetY) + 'px';
        }
    };

    elem.addEventListener('mousedown', e => startDrag(e.clientX, e.clientY));
    document.addEventListener('mouseup', stopDrag);
    document.addEventListener('mousemove', e => doDrag(e.clientX, e.clientY));

    // 添加触摸事件监听
    elem.addEventListener('touchstart', e => {
        e.preventDefault();
        const touch = e.touches[0];
        startDrag(touch.clientX, touch.clientY);
    }, { passive: false });

    document.addEventListener('touchend', stopDrag);
    document.addEventListener('touchmove', e => {
        if (isDragging) {
            const touch = e.touches[0];
            doDrag(touch.clientX, touch.clientY);
        }
    }, { passive: false });
});

使用SortableJS库实现拖拽网格

HTML 和 CSS

在HTML文件中,我们创建一个栅格布局,每个卡片可以通过SortableJS进行拖拽。

<div id="grid" class="grid">
    <div class="card">Card 1</div>
    <div class="card">Card 2</div>
    <div class="card">Card 3</div>
    <div class="card">Card 4</div>
    <div class="card">Card 5</div>
    <div class="card">Card 6</div>
</div>

JavaScript 初始化SortableJS

app.js文件中,我们使用SortableJS来使栅格中的卡片可拖拽。

document.addEventListener('DOMContentLoaded', () => {
    new Sortable(document.getElementById('grid'), {
        animation: 150,
        ghostClass: 'sortable-ghost',
        chosenClass: "sortable-chosen",
        dragClass: "sortable-drag",
    });
});

完整代码

原生拖拽

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Drag and Drop Example</title>
<style>
    #draggable {
        width: 100px;
        height: 100px;
        background-color: teal;
        position: absolute;
        cursor: pointer;
    }
</style>
</head>
<body>
<div id="draggable">Drag me!</div>

<script src="app.js"></script>
</body>
</html>
// app.js
document.addEventListener('DOMContentLoaded', function () {
    const elem = document.getElementById('draggable');
    let offsetX = 0, offsetY = 0, isDragging = false;

    const startDrag = (x, y) => {
        isDragging = true;
        offsetX = x - elem.getBoundingClientRect().left;
        offsetY = y - elem.getBoundingClientRect().top;
    };

    const stopDrag = () => {
        isDragging = false;
    };

    const doDrag = (x, y) => {
        if (isDragging) {
            elem.style.left = (x - offsetX) + 'px';
            elem.style.top = (y - offsetY) + 'px';
        }
    };

    elem.addEventListener('mousedown', e => startDrag(e.clientX, e.clientY));
    document.addEventListener('mouseup', stopDrag);
    document.addEventListener('mousemove', e => doDrag(e.clientX, e.clientY));

    // 添加触摸事件监听
    elem.addEventListener('touchstart', e => {
        e.preventDefault();
        const touch = e.touches[0];
        startDrag(touch.clientX, touch.clientY);
    }, { passive: false });

    document.addEventListener('touchend', stopDrag);
    document.addEventListener('touchmove', e => {
        if (isDragging) {
            const touch = e.touches[0];
            doDrag(touch.clientX, touch.clientY);
        }
    }, { passive: false });
});

SortableJS 拖拽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Draggable Grid Demo</title>
    <style>
        .grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            padding: 10px;
        }
        .card {
            padding: 20px;
            background-color: #f9f9f9;
            border: 1px solid #ccc;
            text-align: center;
        }
        .sortable-ghost {
          opacity: 0.4;
        }
    </style>
</head>
<body>
<div id="grid" class="grid">
    <div class="card">Card 1</div>
    <div class="card">Card 2</div>
    <div class="card">Card 3</div>
    <div class="card">Card 4</div>
    <div class="card">Card 5</div>
    <div class="card">Card 6</div>
    <div class="card">Card 7</div>
    <div class="card">Card 8</div>
    <div class="card">Card 9</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
<script src="app.js"></script>
</body>
</html>
// app.js
document.addEventListener('DOMContentLoaded', () => {
  var el = document.getElementById('grid');
  var sortable = new Sortable(el, {
      animation: 500,  // 动画延迟
      ghostClass: 'sortable-ghost',  // 拖拽时的透明类
      chosenClass: "sortable-chosen",  // 选择类
      dragClass: "sortable-drag",  // 拖拽类
  });
});

结论

通过这些示例,我们展示了如何从零开始实现基本的拖拽功能,以及如何使用SortableJS库提供更复杂的拖拽界面。无论是通过原生JavaScript实现基础功能,还是利用现代库简化开发流程,拖拽交互都能显著提升用户体验。这些技术的应用可以广泛应用于各种Web开发项目中,帮助开发者构建更动态、更互动的Web应用。

相关阅读


A Student on the way to full stack of Web3.