Appearance
Drag 拖拽组件
TIP
- 基于 HTML5 原生 DnD,零依赖
- 支持插入位置指示器
- 支持选中态、复制、删除操作
- 支持跨容器拖入(
accept配置)
基本排序
拖动行可进行排序,onChange 回调返回最新顺序的数组
tsx
tsx
import { useState } from "react";
import { Drag } from "@lite-code/pro-shineout";
const tagColors: Record<string, { bg: string; text: string }> = {
React: { bg: "#e6f4ff", text: "#1677ff" },
Vue: { bg: "#f6ffed", text: "#52c41a" },
TypeScript: { bg: "#fff7e6", text: "#fa8c16" },
Node: { bg: "#f9f0ff", text: "#722ed1" },
CSS: { bg: "#fff0f6", text: "#eb2f96" },
Webpack: { bg: "#e6fffb", text: "#13c2c2" },
};
export default () => {
const [items, setItems] = useState(
Object.keys(tagColors).map((name) => ({
key: name,
name,
content: (
<div
style={{
padding: "6px 14px",
borderRadius: 20,
background: tagColors[name].bg,
color: tagColors[name].text,
fontWeight: 600,
fontSize: 13,
whiteSpace: "nowrap",
userSelect: "none",
}}
>
{name}
</div>
),
}))
);
return (
<div>
<div style={{ color: "#888", fontSize: 12, marginBottom: 10 }}>
拖动 Tag 调整展示顺序
</div>
<div style={{ display: "flex", gap: 8 }}>
<Drag
items={items}
selected={false}
showDashedLine={false}
onChange={setItems}
style={{ gap: 8 }}
/>
</div>
<div
style={{ color: "#bbb", fontSize: 12, marginTop: 12, display: "flex" }}
>
顺序:{items.map((i) => i.key).join(" → ")}
</div>
</div>
);
};
卡片式 + 复制删除
更丰富的内容卡片,结合选中 + 拖拽演示完整交互。
tsx
tsx
import { useState } from 'react'
import { Drag } from '@lite-code/pro-shineout'
const steps = [
{ key: 's1', title: '需求评审', desc: '与产品对齐需求细节', icon: '📝' },
{ key: 's2', title: '技术方案', desc: '输出详细技术设计文档', icon: '🏗️' },
{ key: 's3', title: '编码实现', desc: '按照方案进行功能开发', icon: '💻' },
{ key: 's4', title: '测试联调', desc: 'QA 验证与问题修复', icon: '🔍' },
{ key: 's5', title: '灰度上线', desc: '小流量验证稳定性', icon: '🚀' },
]
export default () => {
const [items, setItems] = useState(
steps.map((s, i) => ({
key: s.key,
content: (
<div
style={{
padding: '12px 16px',
borderRadius: 8,
background: "var(--soui-neutral-fill-1)",
color: "var(--soui-neutral-text-5)",
display: 'flex',
alignItems: 'center',
gap: 14,
boxShadow: '0 1px 4px var(--soui-neutral-fill-3)',
}}
>
<div
style={{
width: 36,
height: 36,
borderRadius: '50%',
background: "var(--soui-neutral-fill-1)",
color: "var(--soui-neutral-text-5)",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 18,
flexShrink: 0,
}}
>
{s.icon}
</div>
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 600, fontSize: 14 }}>
Step {i + 1}:{s.title}
</div>
<div style={{ color: '#888', fontSize: 12, marginTop: 2 }}>{s.desc}</div>
</div>
</div>
),
}))
)
return (
<div style={{ maxWidth: 520 }}>
<div style={{ color: "var(--soui-neutral-text-5)", fontSize: 12, marginBottom: 12 }}>
点击选中后可使用右下角 复制 / 删除 按钮,也可拖动调整顺序
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<Drag
items={items}
selected={true}
showDashedLine={true}
onChange={setItems}
/>
</div>
</div>
)
}
跨容器拖入
tsx
tsx
import { Drag } from "@lite-code/pro-shineout";
import { CSSProperties } from "react";
const style: CSSProperties = {
display: "flex",
gap: 10,
padding: 20,
flex: 9,
flexWrap: "wrap",
alignContent: "flex-start",
backgroundColor: "var(--soui-neutral-fill-2)",
};
const itemStyle = {
width: 90,
height: 90,
background: "var(--soui-neutral-fill-1)",
color: "var(--soui-neutral-text-5)",
padding: "0 4px",
};
export default () => (
<div
style={{
display: "flex",
gap: 12,
width: "100%",
}}
>
<div
style={{
...style,
flex: 1,
height: 300,
}}
>
<Drag
accept={false}
items={["Input", "Select"].map((i) => {
return {
key: i,
content: <div style={itemStyle}>{i}</div>,
};
})}
/>
</div>
<div style={style}>
<Drag
onChange={(item) => {
console.log(item);
}}
defaultKey={5}
onSelected={(item) => {
console.log(item);
}}
items={[1, 2, 3, 4, 5, 6, 7].map((i) => {
return {
key: i,
content: <div style={itemStyle}>{i}</div>,
};
})}
/>
</div>
</div>
);
API
| 属性名 | 描述 | 类型 | 默认值 | 是否必需 |
|---|---|---|---|---|
| items | 数据配置项 | DragItemData[] | [] | 否 |
| onChange | 列表变化后的回调 | (list: DragItemData[]) => void | - | 否 |
| onDrop | 拖拽排序完成的回调 | (fromIndex: number, toIndex: number) => void | - | 否 |
| onSelected | 选中 item 的回调 | (item: DragItemData | null) => void | - | 否 |
| defaultKey | 默认选中的 item key | string | number | - | 否 |
| selected | 是否可以选中 | boolean | true | 否 |
| showDashedLine | 是否显示虚线边框高亮 | boolean | true | 否 |
| direction | 排列与拖拽检测方向 | 'vertical' | 'horizontal' | 'vertical' | 否 |
| style | 容器行内样式 | CSSProperties | - | 否 |
| accept | 是否接受外部容器拖入的 item | boolean | true | 否 |
| dragId | 容器唯一 ID(跨容器用) | string | 自动生成 | 否 |
| children | 传入 children 时直接渲染(不走 items 逻辑) | ReactNode | - | 否 |