¡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/components书 CardItem.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 al src/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 Carla src/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 componente src/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
您需要使用道具。
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:
很快,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 组件是新元素的稳定 器 。
< 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 de src/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
最终结果是德贝利亚诗句德斯塔曼内拉🥳!
👉可选。代码重构 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.
使用 React 和拖放功能创建应用程序,无需库 👆!
这次,我们将使用 React JS 实现拖放功能,而无需任何其他外部包或库!
特点⚙️
卡片拖拽。
将卡片放入容器中。
卡片分类。
科技🧪
React JS
TypeScript
Vite JS
原生 CSS 3
安装🧰
克隆仓库(需要安装 Git )。
git clone https://github.com/Franklin361/drag-and-drop-react
Enter fullscreen mode
Exit fullscreen mode
安装项目依赖项。
npm install
Enter fullscreen mode
Exit fullscreen mode
运行项目。
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