React Drag N' Drop 简介 Showtime 结论

2025-06-07

React 拖放

介绍

开演时间

结论

介绍

如果说 UI 设计就像一顿丰盛的感恩节大餐,“拖拽”功能简直就是面包和黄油,或者火鸡,甚至是火腿。或者……咳咳……你懂的!😉 这功能很棒。这是我们网站上的理想功能。它能让用户在使用我们的应用程序时真正掌控自己的体验。

注意:这篇文章需要 7 分钟才能读完,你可能需要更长时间才能跟上。我完全理解你不想浪费时间的心情!我也理解你希望遵循正确的教程。❤️ 所以,如果你想在继续之前先看看实况​​,请点击这里...在台式电脑上... 本教程不适用于移动设备。

那么,不用多说,让我们开始吧。

重要信息

我想在这里介绍几个概念。如果您已经熟悉 Web API,以下是一些资源,可快速回顾dataTransferdataTransfer.getData()dataTransfer.setData()
dataTransfer
dataTransfer.getData()
dataTranser.setData()

这些概念对于我个人来说很难理解,所以不用担心——我会在这个博客中详细介绍到底发生了什么。

设置

让我们从头开始。npx create-react-app your-choice-appname在终端中输入并按回车键,创建一个 React 应用程序,“your-choice-appname” 可以随意命名这个项目。

完成后,我们来清理一下。删除它App.test.js,然后重命名index.cssmain.css。因为我们可以。👍

接下来,您需要确保将您的内容导入到main.css您的内部index.js,如下所示:

import React from 'react';
import ReactDOM from 'react-dom';
import './main.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

...
Enter fullscreen mode Exit fullscreen mode

完美的!

创建板卡和卡组件

我们将遵循关注点分离规则,因此让我们在源文件夹中创建一个名为“components”的文件夹—— src/components

在此文件夹内,创建两个文件Card.jsxBoard.jsx

这些将是props相互接受参数的功能组件。这对于来回传输数据是必要的。

注意:事情到这里开始变得有点令人困惑了。要理解接下来会发生什么,需要先理解两者同时发生的情况Card.jsxBoard.jsx我会提供详尽的解释,所以请耐心等待。一旦明白了,你就会体验到我所说的“顿悟时刻”。

Board.jsx

让我们从 Board 组件的骨架开始。我们将从以下内容开始:

import React from 'react';

export default function Board(props) {

    return (
        <div>

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

在深入探讨该组件的应用逻辑之前,我们需要为 设定一些属性div。我们需要为它赋值一个id和一个,这就是我们要用到的。让我们修改它,让它反映出我们希望它执行的动态操作。classNameprops

import React from 'react';

export default function Board(props) {

    return (
        <div 
            id={props.id} 
            className={props.className}
        >

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

这样做的原因是我们稍后将以这样的方式使用这个板组件:
<Board id="1" className="board"></Board>
正如您所见,我们的道具将是“id”和“className”。

drop

现在我们可以开始添加函数了。我们想在面板上处理两个 React 事件。它们是onDrop(当我们把 a 拖放card到 this 中时board)和(当光标将 a 拖到 a 中时,onDragOver用于跟踪 a 的数据)。让我们将这些事件应用到我们的cardboarddiv

注意:这些事件将由我们尚未创建的函数触发,但我们接下来将创建它们。

export default function Board(props) {

    return (
        <div 
            id={props.id} 
            className={props.className}
            onDrop={drop}
            onDragOver={dragOver}
        >

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

好了,现在到了最有趣的部分!我们将创建一个名为的函数drop,并将其放在我们的上方return()

export default function Board(props) {
     const drop = e => {
        const card_id = e.dataTransfer.getData('card_id');
        const card = document.getElementById(card_id);

        e.target.appendChild(card);
    }

    return (
        <div 
            id={props.id} 
            className={props.className}
            onDrop={drop}
            onDragOver={dragOver}
        >

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

哇哦,等等!马特,这是怎么回事?

很高兴你问了这个问题!让我们从函数中的前两个声明开始drop

const card_id = e.dataTransfer.getData('card_id')负责从 中获取数据,稍后card我们会将其拖入 中board。我们设置了一个“card_id”的声明,并将其设置为 this ,这样当我们adataTransfer时,它将直接从我们的游标中获取。(抱歉,我有点重复了。我觉得如果你“明白我的意思”,那说明我解释得很好。😉)dropcard

接下来,我们将设置另一个“card”声明,该声明用于抓取cardDOM 中的元素 ID,以便将其放入board.

最后,我们使用e.target.appendChild(card)将我们的添加到carde.target当前e.target正在boardcard放入的)。

拖拽

这个方法简洁明了。我们要做的是创建一个dragOver函数,该函数接受e一个参数,用于event阻止 React 事件的默认行为onDragOver。简单来说,就是阻止背部onDragOver被拖拽card到它被拖拽时的原始位置。为了触发board事件,该事件必须处于启动状态,但不能处于完成状态。onDrop

 const dragOver = e => {
        e.preventDefault();
 }
Enter fullscreen mode Exit fullscreen mode

总而言之,我们希望所有卡片都能显示在页面上。为此,我们只需{ props.children }在 之间添加div

您的完成的Board.jsx组件应该如下所示:

import React from 'react';

export default function Board(props) {
    const drop = e => {
        const card_id = e.dataTransfer.getData('card_id');
        const card = document.getElementById(card_id);

        e.target.appendChild(card);
    }

    const dragOver = e => {
        e.preventDefault();
    }

    return (
        <div 
            id={props.id} 
            className={props.className}
            onDrop={drop} 
            onDragOver={dragOver}
        >
            { props.children }
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

卡片.jsx

是时候介绍我们的Card.jsx组件了!我们将以类似的方式开始设置Board.jsx

import React from 'react';

export default function Card(props) {
    return (
        <div>

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

接下来,让我们在 中设置一些属性div。除了组件中已有的id和之外,我们还想为卡片应用一个名为 的特殊属性。为了使卡片能够,嗯……你猜对了——可拖动,我们需要将此属性设置为。classNameBoard.jsxdraggabletrue

import React from 'react';

export default function Card(props) {
    return (
        <div
            id={props.id}
            draggable={props.draggable}
            className={props.className}
        >

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

您可能已经得出结论,我们将以类似的方式使用此组件<Board></Board>

<Card id="1" className="card" draggable="true">
    <p>Card one</p>
</Card>
Enter fullscreen mode Exit fullscreen mode

现在我们可以开始添加函数了dragStart(用于将卡片数据移动到光标处)和dragOver(用于防止卡片掉落到其他卡片上)。这两个函数都将由 React 事件onDragStart和执行onDragOver

import React from 'react';

export default function Card(props) {
    return (
        <div
            id={props.id}
            draggable={props.draggable}
            className={props.className}
            onDragStart={dragStart}
            onDragOver={dragOver}
        >

        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

拖动开始

好东西!现在让我们添加这些函数。就在 上方return(),我们可以从我们的函数开始dragStart

const dragStart = e => {
    const target = e.target;
    e.dataTransfer.setData('card_id', target.id)
}
Enter fullscreen mode Exit fullscreen mode

我们正在声明一个target将被赋值给 的e.targete.target也就是card我们将要拖动的 )。接下来,我们将介绍 HTML 拖放 API 的另一个函数:e.dataTransfer.setData('card_id', target.id)。这里发生的情况是,我们将游标中的数据设置为 ,card_id并将我们正在拖动的卡片的 ID(target.id)分配给此引用。

叮叮……💡 还记得e.dataTransfer.getData('card_id')我们的Board.jsx组件吗?card数据在组件中设置Card.jsx,然后Board.jsx获取该数据……看到了吗?我告诉过你,这一切都会很顺利。😉

拖拽

我们的最后一个函数……dragOver这个函数简短明了。我们只需要将它应用于stopPropagation事件即可。此函数的目的是防止卡片被拖放到其他卡片上。否则,用户很快就会感到困惑!

const dragOver = e => {
    e.stopPropagation();
}
Enter fullscreen mode Exit fullscreen mode

最后,不要忘记添加到{ props.children }div就像我们对所做的那样Board.jsx

好了!我们已经准备好应用这些组件了。

开演时间

进入你的项目App.js,然后导入Card.jsxBoard.jsx导出src/component。最后,我们将在网页上显示两个看板和两个卡片。你的项目App.js应该如下所示:

import React, { Component } from 'react';
import Board from './components/Board.js';
import Card from './components/Card.js';

export default class App extends Component {  

  render() {
    return (
      <div className="App">
        <main className="flexbox">
          <Board id="board-1" className="board">
            <Card id="1" className="card" draggable="true">
              <p>Card one</p>
            </Card>
            <Card id="2" className="card" draggable="true">
              <p>Card two</p>
            </Card>
          </Board>

          <Board id="board-2" className="board">
            <Card id="3" className="card" draggable="true">
              <p>Card three</p>
            </Card>
            <Card id="4" className="card" draggable="true">
              <p>Card four</p>
            </Card>
          </Board>
        </main>
      </div>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

还有一件事你还需要做……在你的代码中应用一些样式,main.css这样你就可以轻松看到你的组件了。现在这样做应该足够了:

* {
    margin: 0; padding: 0; box-sizing: border-box;
}

body {
    background-color: #f3f3f3;
}

.flexbox {
    display: flex;
    justify-content: space-between;
    width: 100%;
    max-width: 786px;
    height: 100vh;

    overflow: hidden;

    margin: 0 auto;
    padding: 15px;
}

.flexbox .board {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 300px;
    background-color: #313131;
    padding: 15px;
}

.flexbox .board .card {
    padding: 15px 25px;
    background-color: #f3f3f3;

    cursor: pointer;
    margin-bottom: 15px;
}
Enter fullscreen mode Exit fullscreen mode

加大音量npm start并玩弄卡片!

结论

作为开发者,我们常常会对那些看起来远比实际复杂得多的流程抱有不好的印象。对我来说,拖放功能听起来比这个方法糟糕得多。虽然还有很多地方可以改进,让体验更加稳定,但希望这能给其他开发者一个公平的评价。:) 祝大家编程愉快!

文章来源:https://dev.to/matthewpalmer9/react-drag-n-drop-47ee
PREV
作为开发人员如何脱颖而出?
NEXT
什么是 CSP?为何以及如何将其添加到您的网站。