发布于 2026-01-06 0 阅读
0

使用 React 的拖放功能创建应用程序,无需库 👆!

¡Creando un app que usa Drag and Drop con React sin librerias 👆!

使用 React 和拖放功能创建应用程序,无需库 👆!

使用拖放应用程序可以轻松地进行日常操作,从而获得应用程序的使用体验。您可能会实施该项目。

在这个场合,我们可以实现拖放功能的应用程序,但使用外部库,可以与 React JS 配合。

🚨 注意:Este post 需要使用React 和 TypeScript的基础(基础钩子和自定义钩子)

Cualquier Tipo de Feedback es bienvenido, gracias y espero disfrutes el articulo.🤗

 

内容表。

📌 Tecnologías 是一个实用程序。

📌 Creando el proyecto。

📌 Primeros pasos。

📌 Creando nuestras tarjetas。

📌 Creando los contenedores para nuestras tarjetas。

📌定义目标信息和界面信息。

📌 Creando el 组件 DragAndDrop.tsx

📌 Agregando algunos datos para crear tarjetas。

📌 Mostrando algunas tarjetas。

📌实现拖动功能。

📌实现 Drop 功能。

📌 Creando el estado para mantener las tarjetas。

📌实现 las funciones para hacer el drop en los contenedores。

📌可选。重构代码和DragAndDrop.tsx

结论

📌现场演示。

📌 Código fuente。

 

👉 Tecnologías a utilizar.

  • ▶️ React JS(版本 18)
  • ▶️ Vite JS
  • ▶️ TypeScript
  • ▶️ CSS vanilla (Los estilos los encuentras en el repositorio al Final de este post)

 

👉 Creando el proyecto.

Al proyecto le colocaremos el nombre de:(dnd-app可选,tu le puedes poner el nombre que gustes)。



npm init vite@latest


Enter fullscreen mode Exit fullscreen mode

与 Vite JS 结合的奶油和与 TypeScript 结合的 React 选择。

执行命令时,请执行以下操作:



cd dnd-app


Enter fullscreen mode Exit fullscreen mode

Luego instalamos las dependentencias。



npm install


Enter fullscreen mode Exit fullscreen mode

使用代码编辑器(en mi caso VS code)编写项目。



code .


Enter fullscreen mode Exit fullscreen mode

Luego con este comando levantaremos el servidor de desarrollo, y Finalmente vamos a un navegador y accedemos a http://localhost:5173(en vite version 2 el puertoera localhost:3000, pero en la nueva version el puerto es localhost:5173)



npm run dev


Enter fullscreen mode Exit fullscreen mode

 

👉 Primeros pasos.

De una vez, Creamos la carpeta src/componentsy agregamos el archivo Title.tsxy dentro agregamos:



export const Title = () => {
    return (
        <div className="title flex">
            <h1>Creating basic Drag & Drop 👆 </h1>
            <span>( without external libraries )</span>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

很快,档案库中的src/App.tsx所有内容都将成为档案和库的组成部分,其功能与创建的标题相同。



import { Title } from "./components/Title"

const App = () => {
  return (
    <div className="container-main flex">
        <Title />
    </div>
  )
}
export default App


Enter fullscreen mode Exit fullscreen mode

Debería de verse así 👀:

标题

 

👉 Creando nuestras tarjetas。

档案馆地毯src/componentsCardItem.tsx

由于没有重新调整宁古纳道具,所以无法实现。




export const CardItem = () => {
    return (
        <div className='card-container'>
            <p>content</p>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

Aun no usaremos el componente Card en un archivo , pero si quieres puedes puedes importarlo en el archivo src/App.tsxpara que puedas darle algunos estilos y verlos en pantalla .

 

👉 Creando los contenedores para nuestras tarjetas。

Ahora vamos a crear nuestro contenedor para las tarjetas。
Dentro de la crafta src/componentsagregamos el archivo ContainerCards.tsxy agregamos lo siguiente:

Este componente por el momento recibe como parámetro el estado ( puedes ver de que tipo es el Status )



import { Status } from '../interfaces'

interface Props {
  status: Status
}

export const ContainerCards = ({ status }: Props) => {

    return (
        <div className="layout-cards" >
            <p>{status} hero</p>
            {/* Cards */}
        </div>
    )
}



Enter fullscreen mode Exit fullscreen mode

 

🟠 定义类型和目标信息界面。

El 类型 Status es el siguiente:



export type Status = 'good' | 'bad' | 'normal'


Enter fullscreen mode Exit fullscreen mode

Este tipo esta en dentro de la carpeta src/interfacesdentro de un archivo index.ts(el cual deben ir creando, ya que el type Status lo usaremos en varios archivos )

Aprovechando que se están creando el index.tsen src/interfacestambién agreguen la siguiente interfaz.

Asi es como lucirán los datos de las tarjetas。



export interface Data {
    id: number
    content: string
    status: Status
}


Enter fullscreen mode Exit fullscreen mode

 

👉 Creando 组件 DragAndDrop.tsx

布埃诺,我已经创建了有关目标的组件,但需要 3 个目标:

  • Uno para lo heroes buenos.
  • Uno para lo heroes normales.
  • Uno para lo heroes malos.

Dentro de la crafta src/componentsagregamos el archivo DragAndDrop.tsxy agregamos lo siguiente:



import { Status } from "../interfaces"
import { ContainerCards } from "./ContainerCards"

const typesHero: Status[] = ['good', 'normal', 'bad']

export const DragAndDrop = () => {
    return (
        <div className="grid">
            {
                typesHero.map( container => (
                    <ContainerCards
                        status={container}
                        key={container}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

Este 组件 debemos agregarlo alsrc/App.tsx



import { DragAndDrop} from "./components/DragAndDrop"
import { Title } from "./components/Title"

const App = () => {

  return (
    <div className="container-main flex">
      <Title />
      <DragAndDrop />
    </div>
  )
}
export default App


Enter fullscreen mode Exit fullscreen mode

每日头条...
无卡片网格

列出所有有关目标和分类的内容。 👋Ahora

necesitamos crear algunas tarjetas。

 

👉 Agregando algunos datos para crear tarjetas。

我们将在地毯src/assets和档案中index.ts列出有关目标的数据列表。



import { Data } from "../interfaces";

export const data: Data[] = [
    {
        id: 1,
        content: 'Aqua-man',
        status: 'good'
    },
    {
        id: 2,
        content: 'Flash',
        status: 'normal'
    },
    {
        id: 3,
        content: 'Green Lantern',
        status: 'good'
    },
    {
        id: 4,
        content: 'Batman',
        status: 'bad'
    },
]



Enter fullscreen mode Exit fullscreen mode

Ahora,devuelta en src/componentes/DragAndDrop.tsxen Componente ContainerCards pasamos una nueva prop llamada items a dicha prop le pasamos como valor la data que hemos creado en la Carlasrc/assets



import { ContainerCards } from "./ContainerCards"
import { Status } from "../interfaces"
import { data } from "../assets"

const typesHero: Status[] = ['good', 'normal', 'bad']

export const DragAndDrop = () => {
    return (
        <div className="grid">
            {
                typesHero.map( container => (
                    <ContainerCards
                        status={container}
                        key={container}
                        items={data}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

这是因为ContainerCards 中的项目没有属性。 😥

但是,请在 siguiente 部分排列。 👇

 

👉 Mostrando algunas tarjetas。

对于最重要的部件,需要将其与其他组件的参数结合起来。

1 - Primero el componentesrc/components/CardItem.tsx

Recibirá como props la data que es de tipo Data, la que habíamos definido con anterioridad .

大多数数据都包含专有内容



import { Data } from "../interfaces"

interface Props {
    data: Data
}

export const CardItem = ({ data, handleDragging }: Props) => {

    return (
        <div className='card-container'>
            <p>{data.content}</p>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

2 - 组件间的属性属性项以及数据和结构的src/components/ContainerCards.tsx列表



import { Data, Status } from "../interfaces"

interface Props {
    items: Data[]
    status: Status
}

export const ContainerCards = ({ items = [], status }: Props) => {

    return (
        <div className="layout-cards">
            <p>{status} hero</p>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

实现物品迭代的礼仪p规范 旋转卡片物品属性
CardItem.tsxitemdata



import { Data, Status } from "../interfaces"
import { CardItem } from "./CardItem"

interface Props {
    items: Data[]
    status: Status
}

export const ContainerCards = ({ items = [], status}: Props) => {

    return (
        <div className="layout-cards">
            <p>{status} hero</p>
            {
                items.map(item => (
                    <CardItem
                        data={item}
                        key={item.id}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

Esto te dará una advertencia de que las key se repiten 😥

这需要 3 个 ContainerCards 的渲染。

但状态之间的 3 个组成部分之间存在差异

Por lo que haremos la siguiente 条件:

  • 如果ContainerCards是一个组件(超级英雄之海)的组件,则会渲染出相反的效果。


import { Data, Status } from "../interfaces"
import { CardItem } from "./CardItem"

interface Props {
    items: Data[]
    status: Status
}

export const ContainerCards = ({ items = [], status }: Props) => {

    return (
        <div className="layout-cards">
            <p>{status} hero</p>
            {
                items.map(item => (
                    status === item.status
                    && <CardItem
                        data={item}
                        key={item.id}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

Y asi evitamos elconflictcon las llaves y se clasificaran las tarjetas de la siguiente manera 👀...

网格和卡片

 

👉 实现拖动功能。

实现拖动功能,首先定义国家和功能src/components/DragAndDrop.tsx

  • El estado nos ayudara a saber si si esta haciendo Drag, yasi cambiar los estilos de.

    • 如果您的背叛是错误的,您将无法启动应用程序来拖拽庄园。
    • 独奏真正的cuando se arrastre alguna tarjeta。
  • 功能、布尔布尔值的计算方法、设置的值、设置的值以及设置 IsDragging 属性的值。

Pasamos como 组件ContainerCards

  • isDragging ,tendra el valor del estado
  • 手柄拖动,可实现国家的功能。


import { ContainerCards } from "./ContainerCards"
import { data } from "../assets"
import { Status } from "../interfaces"

const typesHero: Status[] = ['good', 'normal', 'bad']

export const DragAndDrop = () => {

  const [isDragging, setIsDragging] = useState(false)

  const handleDragging = (dragging: boolean) => setIsDragging(dragging)


    return (
        <div className="grid">
            {
                typesHero.map(container => (
                    <ContainerCards
                        items={data}
                        status={container}
                        key={container}

                        isDragging={isDragging}
                        handleDragging={handleDragging}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

ContainerCards无法提供任何帮助,因此可能会出现错误。与ContainerCards El archivo

的国际界面相比,这很困难
src/components/ContainerCards.tsx




interface Props {
    items: Data[]
    status: Status
    isDragging: boolean
    handleDragging: (dragging: boolean) => void
}


Enter fullscreen mode Exit fullscreen mode

您需要使用道具。

  • 注意,在类名中,如果有条件,则拖动 es verdadero entonces agregamos la clase layout-dragging。这是一个单独的坎比亚拉颜色的颜色和内容的边界,cuando se arrastre una tarjeta。

  • 注意,如果您使用新的卡片项目,则可以使用手柄拖动,这是为了实现前面的效果而设计的组件。



import { CardItem } from "./CardItem"
import { Data, Status } from "../interfaces"

interface Props {
    items: Data[]
    status: Status
    isDragging: boolean
    handleDragging: (dragging: boolean) => void
}

export const ContainerCards = ({ items = [], status, isDragging, handleDragging }: Props) => {

    return (
        <div
            className={`layout-cards ${isDragging ? 'layout-dragging' : ''}`}
        >
            <p>{status} hero</p>
            {
                items.map(item => (
                    status === item.status
                    && <CardItem
                        data={item}
                        key={item.id}
                        handleDragging={handleDragging}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

卡片项目出现错误,但拖动手柄时没有任何提示,这是由于界面上的修改造成的。

src/components/CardItem.tsx修改国际档案的时间



interface Props {
    data: Data,
    handleDragging: (dragging: boolean) => void
}


Enter fullscreen mode Exit fullscreen mode

是的,请注意拖拽组件的功能。
首先,在div所有目标上,可拖动的属性是该组件的主要组件。



import { Data } from "../interfaces"

interface Props {
    data: Data,
    handleDragging: (dragging: boolean) => void
}

export const CardItem = ({ data, handleDragging }: Props) => {
    return (
        <div
            className='card-container'
            draggable
        >
            <p>{data.content}</p>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

onDragEnd属性是一个执行handleDragEnd函数的属性。

该功能的主要功能是拖动错误,当拖拽结束时弹出,您可以将目标拖拽至目标位置,然后停止拖拽,然后将所有拖拽拖拽到一起。开始。



import { Data } from "../interfaces"

interface Props {
    data: Data,
    handleDragging: (dragging: boolean) => void
}

export const CardItem = ({ data, handleDragging }: Props) => {


    const handleDragEnd = () => handleDragging(false)

    return (
        <div
            className='card-container'
            draggable
            onDragEnd={handleDragEnd}
        >
            <p>{data.content}</p>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

执行onDragStart操作(如果执行拖拽操作,则执行拖拽操作,然后执行onDragStart操作)。

onDragStart是一个执行handleDragStart函数的函数。

此功能可用于记录事件和数据传输的相关属性。

专有数据传输不允许您获取数据,而这些数据可以通过元素进行传输。

数据传输的属性setData可以设置数据传输的内容,并提供参数说明:

  • 格式:es el formatato de la data a mantener, el cual es "text"

  • 数据:这是有关元素的信息。独奏接受弦乐。 En este caso, almacenaremos el id de la tarjeta.

注意:它存在于数据传输的属性中,清除数据缓存中的数据。如果没有必要执行此操作,您可以使用“文本”作为识别符。

获取数据内容后,可以通过手柄拖动真正的勇气来使用该元素。



import { Data } from "../interfaces"

interface Props {
    data: Data,
    handleDragging: (dragging: boolean) => void
}

export const CardItem = ({ data, handleDragging }: Props) => {

    const handleDragStart = (e: React.DragEvent<HTMLDivElement>) => {
        e.dataTransfer.setData('text', `${data.id}`)
        handleDragging(true)
    }
    const handleDragEnd = () => handleDragging(false)

    return (
        <div
            className='card-container'
            draggable
            onDragStart={handleDragStart}
            onDragEnd={handleDragEnd}
        >
            <p>{data.content}</p>
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

您可以在其他元素中添加信息,也可以在其他内容中获取更多信息。

当你遇到一个目标时,你会看到一些关于该目标的内容。

网格拖拽效果

 

👉 实现 Drop 功能。

太阳元素的前面,是其他元素的实现。

🟠 Creando el estado para mantener las tarjetas。

首先,我们将在国家和实际情况中列出英雄名单,并在其他内容中将其作为目标,这是英雄地位的现实时刻,这将是新的组织列表的渲染。

Para eso vamos a src/components/DragAndDrop.tsxy Creamos un nuevo estado。
Su valor inicial va a Ser la data que hemos definido previamente en src/assets.



import { data } from "../assets"

const [listItems, setListItems] = useState<Data[]>(data)


Enter fullscreen mode Exit fullscreen mode

是的,在渲染ContainerCards组件的时刻,您将获得数据和项目属性的价值,以及列表项的价值



import { ContainerCards } from "./ContainerCards"
import { data } from "../assets"
import { Status } from "../interfaces"

const typesHero: Status[] = ['good', 'normal', 'bad']

export const DragAndDrop = () => {

  const [isDragging, setIsDragging] = useState(false)
  const [listItems, setListItems] = useState<Data[]>(data)

  const handleDragging = (dragging: boolean) => setIsDragging(dragging)


    return (
        <div className="grid">
            {
                typesHero.map(container => (
                    <ContainerCards
                        items={listItems}
                        status={container}
                        key={container}

                        isDragging={isDragging}
                        handleDragging={handleDragging}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

创建列表项目的实际功能。
La llamaremos handleUpdateList,以及参数说明:

  • id: el identificador de la tarjeta,sera de Tipo Número。
  • 状态:el nuevo estado de la tarjeta,sera de tipo Status。

功能内部...

1 - Primero Buscaremos el elemento en el valor del estado listItems,mediate el ID。

2 - 评估存在的数据和状态,以及不同的状态,并确定国家的地位。

3 - 详细说明条件,并根据功能参数的新状态指定目标和实际情况。

4 - Llamamos al setListItems para realizar el estado, colocando:

  • La tarjeta con su propiedad status effectiveizada.

  • 在新的安排中,过滤掉元素以实现实际情况并消除信息的双重性。

很快,ContainerCards 的所有组件都使用了新的 llamada handleUpdateList属性,并提供了创建handleUpdateList 的功能



import { ContainerCards } from "./ContainerCards"
import { data } from "../assets"
import { Status } from "../interfaces"

const typesHero: Status[] = ['good', 'normal', 'bad']

export const DragAndDrop = () => {

  const [isDragging, setIsDragging] = useState(false)
  const [listItems, setListItems] = useState<Data[]>(data)

  const handleDragging = (dragging: boolean) => setIsDragging(dragging)

  const handleUpdateList = (id: number, status: Status) => {

       let card = listItems.find(item => item.id === id)

       if (card && card.status !== status) {

           card.status = status

           setListItems( prev => ([
                card!,
                ...prev.filter(item => item.id !== id)
            ]))
       }
   }

    return (
        <div className="grid">
            {
                typesHero.map(container => (
                    <ContainerCards
                        items={listItems}
                        status={container}
                        key={container}

                        isDragging={isDragging}
                        handleDragging={handleDragging}
                        handleUpdateList={handleUpdateList}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

这是一个错误,因为ContainerCards组件没有指定的handleUpdateList,因此ContainerCards界面的实际情况是这样的。

src/components/ContainerCards.tsx:



interface Props {
    items: Data[]
    status: Status
    isDragging: boolean
    handleDragging: (dragging: boolean) => void
    handleUpdateList: (id: number, status: Status) => void
}


Enter fullscreen mode Exit fullscreen mode

 

👉 Realizando las funciones para hacer el drop en los contenedores。

我们位于src/components/ContainerCards.tsx

VAMOS 组件是新元素的稳定

  • onDragOver:产生一个可排列的元素,该元素可排列为有效的对象。使用handleDragOver功能即可立即创建。

  • onDrop:产生 cuando el elemento arrastrado se deja caer。按下手柄下降功能,即刻创建。



<div
    className={`layout-cards ${isDragging ? 'layout-dragging' : ''}`}
    onDragOver={handleDragOver}
    onDrop={handleDrop}
>
    <p>{status} hero</p>
    {
        items.map(item => (
            status === item.status
            && <CardItem
                data={item}
                key={item.id}
                handleDragging={handleDragging}
            />
        ))
    }
</div>


Enter fullscreen mode Exit fullscreen mode

handleDragOver 功能是单独的。首先,在onDragOver
上发出事件 如果叛逃者没有任何其他要素,并且允许叛逃者与叛逃者保持一致。



const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
}


Enter fullscreen mode Exit fullscreen mode

现在handleDrop函数

  • Primero,recibirá el evento que emite onDrop

  • Dentro de la función, evitamos el comportamiento por defoto, el cual se nota mas con images (cuando soltamos una imagen en un lugar de nuestra app, abre la imagen, sacándonos de la app).

  • 事件发生后,您将获得数据传输的属性并获得数据传输的属性,并获得目标 ID 的有效身份。

    • 一个标志+将把e.dataTransfer.getData('text')勇气转化为一个数字。
  • 使用handleUpdateList函数来处理道具中的组件(可以解构组件)。

    • 首先,您必须先获取属性中数据,然后再将数据传输到数字中。
    • 说明组件中道具的作用。
  • 最后,骆驼手柄拖动Mandando el valor de false para indicar al usuario que ya no estamos arrastrando nada。



const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    const id = +e.dataTransfer.getData('text')
    handleUpdateList(id, status)
    handleDragging(false)
}


Enter fullscreen mode Exit fullscreen mode

Así se vería el código desrc/components/ContainerCards.tsx



import { Data, Status } from "../interfaces"
import { CardItem } from "./CardItem"

interface Props {
    items: Data[]
    status: Status
    isDragging: boolean
    handleUpdateList: (id: number, status: Status) => void
    handleDragging: (dragging: boolean) => void
}

export const ContainerCards = ({ items = [], status, isDragging, handleDragging, handleUpdateList }: Props) => {

    const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
        e.preventDefault()
        handleUpdateList(+e.dataTransfer.getData('text'), status)
        handleDragging(false)
    }

    const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => e.preventDefault()

    return (
        <div
            className={`layout-cards ${isDragging ? 'layout-dragging' : ''}`}
            onDrop={handleDrop}
            onDragOver={handleDragOver}
        >
            <p>{status} hero</p>
            {
                items.map(item => (
                    status === item.status
                    && <CardItem
                        data={item}
                        key={item.id}
                        handleDragging={handleDragging}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

最终结果是德贝利亚诗句德斯塔曼内拉🥳!

应用演示 GIF

 

👉可选。代码重构DragAndDrop.tsx

Tenemos bastante lógica en nuestro componente,por lo cual seria una buena optción create un custom hook para administrar esa lógica。

奶油地毯src/hooks和档案骆驼包useDragAndDrop.ts

Primero 定义了功能、数据设置的初始状态



export const useDragAndDrop = (initialState: Data[]) => {}


Enter fullscreen mode Exit fullscreen mode

DragAndDrop.tsx组件在自定义挂钩中记录了逻辑和 colocamos。

列表项的初始值是钩子参数的值。

Y por ultimo retornamos como un object:

  • 正在拖动。
  • 列表项。
  • 处理更新列表。
  • 处理拖拽。


import { useState } from "react"
import { Data, Status } from "../interfaces"

export const useDragAndDrop = (initialState: Data[]) => {

    const [isDragging, setIsDragging] = useState(false)
    const [listItems, setListItems] = useState<Data[]>(initialState)

    const handleUpdateList = (id: number, status: Status) => {

       let card = listItems.find(item => item.id === id)

       if (card && card.status !== status) {

           card.status = status

           setListItems( prev => ([
                card!,
                ...prev.filter(item => item.id !== id)
            ]))
       }
   }

    const handleDragging = (dragging: boolean) => setIsDragging(dragging)

    return {
        isDragging,
        listItems,
        handleUpdateList,
        handleDragging,
    }
}


Enter fullscreen mode Exit fullscreen mode

Ahora en el componente src/components/DragAndDrop.tsxllamamos 是一款我们定制的钩子。

Le mandamos la data a nuestro hook, por parametro y alone desestructuramos las propiedades y listo!.。



import { ContainerCards } from "./ContainerCards"
import { useDragAndDrop } from "../hooks/useDragAndDrop"
import { Status } from "../interfaces"
import { data } from "../assets"

const typesHero: Status[] = ['good', 'normal', 'bad']

export const DragAndDrop = () => {

    const { isDragging, listItems, handleDragging, handleUpdateList } = useDragAndDrop(data)

    return (
        <div className="grid">
            {
                typesHero.map(container => (
                    <ContainerCards
                        items={listItems}
                        status={container}
                        key={container}

                        isDragging={isDragging}
                        handleDragging={handleDragging}
                        handleUpdateList={handleUpdateList}
                    />
                ))
            }
        </div>
    )
}


Enter fullscreen mode Exit fullscreen mode

Así quedara mas 是清晰的组件。 🎉

 

👉 结论。

该过程是在外部库中使用拖放功能构建应用程序的格式。

  • Una forma de mejorar esta applicación seria usando un a administrador de estado para evitar estar pasando demasiadas support a los componentes .

  • 如果您已经精心设计并扩展了功能,请选择 terceros paquete de terceros que te recomiendo bastante,是的react-beautiful-dnd,这是一个非常受欢迎的图书馆。

Espero haberte ayudado a entender como realizar este ejercicio,非常感谢 por llegar hasta aquí! 🤗❤️

您可以通过评论来获得有趣的结果,通过拖放可以看到不同的形状。 🙌

 

🟠 现场演示。

https://drag-and-drop-react-app.netlify.app

🟠 Código fuente.

GitHub 标志 Franklin361 /拖放式 React

使用 React JS 和拖放功能创建应用程序🤏

使用 React 和拖放功能创建应用程序,无需库 👆!

这次,我们将使用 React JS 实现拖放功能,而无需任何其他外部包或库!

 

应用演示 GIF

 

特点⚙️

  1. 卡片拖拽。
  2. 将卡片放入容器中。
  3. 卡片分类。

 

科技🧪

  • React JS
  • TypeScript
  • Vite JS
  • 原生 CSS 3

 

安装🧰

  1. 克隆仓库(需要安装Git)。
    git clone https://github.com/Franklin361/drag-and-drop-react
Enter fullscreen mode Exit fullscreen mode
  1. 安装项目依赖项。
    npm install
Enter fullscreen mode Exit fullscreen mode
  1. 运行项目。
    npm run dev
Enter fullscreen mode Exit fullscreen mode

 

链接⛓️

应用演示 🔥

这是教程的链接,如果你想看看的话!👀




文章来源:https://dev.to/franklin030601/creando-un-app-que-usa-drag-and-drop-con-react-sin-librerias--gm3