TypeScript版ReactDnd示例求助:在线Babel语法示例不兼容TypeScript2.1
我太懂你这个困扰了!TS 2.1那个时期类型系统还没像现在这么成熟,网上一堆用Babel写的React DnD示例,直接套到TS里要么类型报错要么跑不起来。下面给你一套完全适配TypeScript 2.1的完整示例,从拖拽源、放置目标到根组件的配置都给你写清楚,还附带针对TS2.1的关键注意事项:
完整TypeScript 2.1 + React DnD示例
第一步:安装兼容版本的依赖
TS2.1对新特性支持有限,必须用特定版本的React DnD才能避免类型冲突,执行以下命令安装:
npm install react-dnd@2.5.4 react-dnd-html5-backend@2.5.4 --save
1. 定义拖拽类型常量
先统一管理拖拽元素的类型标识,避免字符串硬编码带来的错误:
const ItemTypes = { BOX: 'box' as string };
这里加as string是因为TS2.1的类型推断不够完善,需要明确指定类型避免歧义。
2. 拖拽源组件(DraggableBox)
实现可拖拽的盒子组件,使用DragSource高阶包装,全程严格遵循TS2.1的类型规范:
import * as React from 'react'; import { DragSource, DragSourceConnector, DragSourceMonitor } from 'react-dnd'; // 拖拽源核心逻辑:开始拖拽时传递的数据 const boxSource = { beginDrag(props: { name: string }) { return { name: props.name }; } }; // 收集拖拽状态与连接方法,传递给组件Props function collect(connect: DragSourceConnector, monitor: DragSourceMonitor) { return { connectDragSource: connect.dragSource(), isDragging: monitor.isDragging() }; } // 明确组件Props的类型定义(TS2.1必须显式声明) type DraggableBoxProps = { name: string; connectDragSource: (node: React.ReactNode) => React.ReactNode; isDragging: boolean; }; class DraggableBox extends React.Component<DraggableBoxProps, {}> { render() { const { connectDragSource, isDragging, name } = this.props; // 用connectDragSource包裹可拖拽元素 return connectDragSource( <div style={{ opacity: isDragging ? 0.5 : 1, padding: '20px', border: '1px solid gray', margin: '10px', cursor: 'move' }} > {name} </div> ); } } // 包装成拖拽源组件 export default DragSource(ItemTypes.BOX, boxSource, collect)(DraggableBox);
3. 放置目标组件(DropZone)
实现接收拖拽元素的区域,使用DropTarget高阶包装:
import * as React from 'react'; import { DropTarget, DropTargetConnector, DropTargetMonitor } from 'react-dnd'; // 放置目标核心逻辑:处理元素放下后的行为 const zoneTarget = { drop(monitor: DropTargetMonitor) { const item = monitor.getItem(); alert(`你放下了:${item.name}`); } }; // 收集放置状态与连接方法,传递给组件Props function collect(connect: DropTargetConnector, monitor: DropTargetMonitor) { return { connectDropTarget: connect.dropTarget(), isOver: monitor.isOver() }; } // 明确组件Props的类型定义 type DropZoneProps = { connectDropTarget: (node: React.ReactNode) => React.ReactNode; isOver: boolean; }; class DropZone extends React.Component<DropZoneProps, {}> { render() { const { connectDropTarget, isOver } = this.props; // 用connectDropTarget包裹可放置区域 return connectDropTarget( <div style={{ padding: '40px', border: isOver ? '2px dashed blue' : '2px dashed gray', margin: '20px' }} > {isOver ? '松开放下盒子' : '拖拽盒子到这里'} </div> ); } } // 包装成放置目标组件 export default DropTarget(ItemTypes.BOX, zoneTarget, collect)(DropZone);
4. 根组件(App)
用DragDropContext包裹根组件,启用HTML5拖拽后端:
import * as React from 'react'; import { render } from 'react-dom'; import { DragDropContext } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; import DraggableBox from './DraggableBox'; import DropZone from './DropZone'; class App extends React.Component<{}, {}> { render() { return ( <div> <h2>React DnD + TypeScript 2.1 示例</h2> <DraggableBox name="盒子1" /> <DraggableBox name="盒子2" /> <DropZone /> </div> ); } } // 用HTML5后端包装根组件 export default DragDropContext(HTML5Backend)(App); // 渲染到页面 render(<App />, document.getElementById('root'));
针对TS2.1的关键补充:手动添加类型声明
TS2.1时期还没有官方的@types/react-dnd,所以需要在项目根目录创建react-dnd.d.ts文件,补充基础类型声明避免报错:
declare module 'react-dnd' { import * as React from 'react'; export type DragSourceConnector = { dragSource: (options?: any) => (node: React.ReactNode) => React.ReactNode; }; export type DragSourceMonitor = { isDragging: () => boolean; getItem: () => any; }; export type DropTargetConnector = { dropTarget: (options?: any) => (node: React.ReactNode) => React.ReactNode; }; export type DropTargetMonitor = { isOver: () => boolean; getItem: () => any; }; export function DragSource( type: string, source: any, collect: (connect: DragSourceConnector, monitor: DragSourceMonitor) => any ): (Component: React.ComponentClass<any>) => React.ComponentClass<any>; export function DropTarget( type: string, target: any, collect: (connect: DropTargetConnector, monitor: DragSourceMonitor) => any ): (Component: React.ComponentClass<any>) => React.ComponentClass<any>; export function DragDropContext(backend: any): (Component: React.ComponentClass<any>) => React.ComponentClass<any>; } declare module 'react-dnd-html5-backend' { const backend: any; export default backend; }
内容的提问来源于stack exchange,提问作者javaallone
相关产品推荐
相关产品推荐

