- 基于 React 19 + Vite 7 + Tailwind CSS 4 - 实现拖拽排序功能 (@dnd-kit) - 5个传感器实验项目展示 - 响应式设计和现代化 UI - 修复拖拽释放到空白区域时的潜在 bug 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
4.1 KiB
React
112 lines
4.1 KiB
React
import { useState } from 'react';
|
||
import {
|
||
DndContext,
|
||
closestCenter,
|
||
KeyboardSensor,
|
||
PointerSensor,
|
||
useSensor,
|
||
useSensors,
|
||
} from '@dnd-kit/core';
|
||
import {
|
||
arrayMove,
|
||
SortableContext,
|
||
sortableKeyboardCoordinates,
|
||
verticalListSortingStrategy,
|
||
} from '@dnd-kit/sortable';
|
||
import { DraggableItem } from './components/DraggableItem';
|
||
import { Cpu, Thermometer, Gauge, Radio, Zap, Droplets } from 'lucide-react';
|
||
|
||
function App() {
|
||
const [experiments, setExperiments] = useState([
|
||
{ id: '1', name: '温度传感器实验', icon: Thermometer, description: '学习温度传感器的工作原理及应用' },
|
||
{ id: '2', name: '压力传感器实验', icon: Gauge, description: '了解压力传感器的测量原理与特性' },
|
||
{ id: '3', name: '位移传感器实验', icon: Radio, description: '掌握位移传感器的检测方法' },
|
||
{ id: '4', name: '光电传感器实验', icon: Zap, description: '探索光电传感器的光电转换原理' },
|
||
{ id: '5', name: '湿度传感器实验', icon: Droplets, description: '研究湿度传感器的测量技术' },
|
||
]);
|
||
|
||
const sensors = useSensors(
|
||
useSensor(PointerSensor),
|
||
useSensor(KeyboardSensor, {
|
||
coordinateGetter: sortableKeyboardCoordinates,
|
||
})
|
||
);
|
||
|
||
function handleDragEnd(event) {
|
||
const { active, over } = event;
|
||
|
||
if (over && active.id !== over.id) {
|
||
setExperiments((items) => {
|
||
const oldIndex = items.findIndex((item) => item.id === active.id);
|
||
const newIndex = items.findIndex((item) => item.id === over.id);
|
||
return arrayMove(items, oldIndex, newIndex);
|
||
});
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
||
<div className="container mx-auto px-4 py-8">
|
||
<header className="text-center mb-12">
|
||
<div className="flex items-center justify-center gap-3 mb-4">
|
||
<Cpu className="w-10 h-10 text-indigo-600" />
|
||
<h1 className="text-4xl font-bold text-gray-800">
|
||
传感器及检测技术
|
||
</h1>
|
||
</div>
|
||
<p className="text-gray-600 text-lg">实验课件交互式平台</p>
|
||
</header>
|
||
|
||
<div className="max-w-3xl mx-auto">
|
||
<div className="bg-white rounded-xl shadow-lg p-6 mb-6">
|
||
<h2 className="text-2xl font-semibold text-gray-800 mb-4">
|
||
实验项目列表
|
||
</h2>
|
||
<p className="text-gray-600 mb-6">
|
||
拖动实验项目可以调整顺序,规划您的学习路径
|
||
</p>
|
||
|
||
<DndContext
|
||
sensors={sensors}
|
||
collisionDetection={closestCenter}
|
||
onDragEnd={handleDragEnd}
|
||
>
|
||
<SortableContext
|
||
items={experiments}
|
||
strategy={verticalListSortingStrategy}
|
||
>
|
||
{experiments.map((experiment, index) => {
|
||
const Icon = experiment.icon;
|
||
return (
|
||
<DraggableItem key={experiment.id} id={experiment.id}>
|
||
<div className="flex items-center gap-4">
|
||
<div className="flex-shrink-0 w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center">
|
||
<Icon className="w-6 h-6 text-indigo-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-800">
|
||
{index + 1}. {experiment.name}
|
||
</h3>
|
||
<p className="text-sm text-gray-600">
|
||
{experiment.description}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</DraggableItem>
|
||
);
|
||
})}
|
||
</SortableContext>
|
||
</DndContext>
|
||
</div>
|
||
|
||
<div className="text-center text-gray-600 text-sm">
|
||
<p>使用现代化技术构建 • React + Vite + Tailwind CSS</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default App;
|