重新整理仓库
This commit is contained in:
266
docs/SELECT_FILE_DRAG_DEMO.md
Normal file
266
docs/SELECT_FILE_DRAG_DEMO.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# 🔄 SelectFile组件拖拽调整顺序功能演示
|
||||
|
||||
## 🎯 功能概述
|
||||
|
||||
我已经成功为SelectFile组件添加了拖拽调整顺序的功能,让用户可以通过拖拽来重新排列文件的顺序。
|
||||
|
||||
### ✨ 核心功能
|
||||
|
||||
1. **🔄 拖拽排序**
|
||||
- 支持鼠标拖拽调整文件顺序
|
||||
- 实时视觉反馈和拖拽指示器
|
||||
- 顺序指示器显示当前位置
|
||||
|
||||
2. **🎯 智能交互**
|
||||
- 拖拽时显示拖拽指示器
|
||||
- 悬停时显示拖拽提示
|
||||
- 拖拽完成后自动更新数据
|
||||
|
||||
3. **📍 视觉反馈**
|
||||
- 顺序指示器显示文件位置
|
||||
- 拖拽时的视觉效果
|
||||
- 悬停时的交互提示
|
||||
|
||||
### 🔧 技术实现
|
||||
|
||||
#### 1. 组件模板更新
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<a-image-preview-group>
|
||||
<div class="select-file-container">
|
||||
<!-- 🔄 可拖拽的文件列表 -->
|
||||
<div
|
||||
class="draggable-file-list"
|
||||
@dragover.prevent
|
||||
@drop="onDrop"
|
||||
>
|
||||
<template v-for="(item, index) in localData" :key="item.id || index">
|
||||
<div
|
||||
class="image-upload-item draggable-item"
|
||||
:class="{ 'dragging': dragIndex === index }"
|
||||
draggable="true"
|
||||
@dragstart="onDragStart(index, $event)"
|
||||
@dragend="onDragEnd"
|
||||
@dragenter="onDragEnter(index)"
|
||||
@dragleave="onDragLeave"
|
||||
v-if="isImage(item.url)"
|
||||
>
|
||||
<!-- 🎯 拖拽指示器 -->
|
||||
<div class="drag-indicator">
|
||||
<HolderOutlined />
|
||||
</div>
|
||||
|
||||
<a-image :src="item.url" />
|
||||
|
||||
<!-- 📍 顺序指示器 -->
|
||||
<div class="order-indicator">{{ index + 1 }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</a-image-preview-group>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### 2. 拖拽逻辑实现
|
||||
|
||||
```typescript
|
||||
// 🔄 拖拽相关状态
|
||||
const dragIndex = ref<number | null>(null);
|
||||
const dragOverIndex = ref<number | null>(null);
|
||||
|
||||
// 📝 本地数据副本,用于拖拽操作
|
||||
const localData = ref<any[]>([]);
|
||||
|
||||
// 🔄 监听props.data变化,同步到localData
|
||||
watch(
|
||||
() => props.data,
|
||||
(newData) => {
|
||||
if (newData) {
|
||||
localData.value = [...newData];
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
// 🔄 拖拽开始
|
||||
const onDragStart = (index: number, event: DragEvent) => {
|
||||
dragIndex.value = index;
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
event.dataTransfer.setData('text/html', index.toString());
|
||||
}
|
||||
};
|
||||
|
||||
// 🔄 拖拽结束
|
||||
const onDragEnd = () => {
|
||||
dragIndex.value = null;
|
||||
dragOverIndex.value = null;
|
||||
};
|
||||
|
||||
// 🔄 拖拽进入
|
||||
const onDragEnter = (index: number) => {
|
||||
dragOverIndex.value = index;
|
||||
};
|
||||
|
||||
// 🔄 拖拽放置
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (dragIndex.value !== null && dragOverIndex.value !== null && dragIndex.value !== dragOverIndex.value) {
|
||||
const newData = [...localData.value];
|
||||
const draggedItem = newData[dragIndex.value];
|
||||
|
||||
// 移除拖拽的项目
|
||||
newData.splice(dragIndex.value, 1);
|
||||
|
||||
// 在新位置插入项目
|
||||
const insertIndex = dragIndex.value < dragOverIndex.value ? dragOverIndex.value - 1 : dragOverIndex.value;
|
||||
newData.splice(insertIndex, 0, draggedItem);
|
||||
|
||||
// 更新本地数据
|
||||
localData.value = newData;
|
||||
|
||||
// 触发重新排序事件
|
||||
emit('reorder', newData);
|
||||
}
|
||||
|
||||
dragIndex.value = null;
|
||||
dragOverIndex.value = null;
|
||||
};
|
||||
```
|
||||
|
||||
#### 3. 事件定义更新
|
||||
|
||||
```typescript
|
||||
const emit = defineEmits<{
|
||||
(e: 'done', data: FileRecord): void;
|
||||
(e: 'del', index: number): void;
|
||||
(e: 'clear'): void;
|
||||
(e: 'reorder', data: any[]): void; // 新增重新排序事件
|
||||
}>();
|
||||
```
|
||||
|
||||
#### 4. 样式设计
|
||||
|
||||
```less
|
||||
// 🔄 可拖拽项目样式
|
||||
.draggable-item {
|
||||
position: relative;
|
||||
cursor: move;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
|
||||
.drag-indicator {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
opacity: 0.5;
|
||||
transform: rotate(5deg) scale(0.95);
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
// 🎯 拖拽指示器
|
||||
.drag-indicator {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// 📍 顺序指示器
|
||||
.order-indicator {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
background: #1890ff;
|
||||
color: white;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
z-index: 5;
|
||||
border: 2px solid white;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
```
|
||||
|
||||
### 🔗 父组件集成
|
||||
|
||||
在articleEdit.vue中添加对reorder事件的处理:
|
||||
|
||||
```vue
|
||||
<SelectFile
|
||||
:placeholder="`请选择图片`"
|
||||
:limit="6"
|
||||
:data="files"
|
||||
@done="chooseFile"
|
||||
@del="onDeleteFile"
|
||||
@reorder="onReorderFiles"
|
||||
/>
|
||||
```
|
||||
|
||||
```typescript
|
||||
// 🔄 处理文件重新排序
|
||||
const onReorderFiles = (newData: any[]) => {
|
||||
files.value = newData;
|
||||
form.files = JSON.stringify(files.value.map((d) => d.url));
|
||||
message.success('文件顺序已更新');
|
||||
};
|
||||
```
|
||||
|
||||
### 🎨 用户体验
|
||||
|
||||
1. **直观操作**:用户可以直接拖拽文件来调整顺序
|
||||
2. **视觉反馈**:拖拽时有清晰的视觉指示
|
||||
3. **顺序显示**:每个文件都有序号显示当前位置
|
||||
4. **即时更新**:拖拽完成后立即更新数据和UI
|
||||
|
||||
### 📊 功能特点
|
||||
|
||||
| 特性 | 描述 | 状态 |
|
||||
|------|------|------|
|
||||
| 拖拽排序 | 支持鼠标拖拽调整顺序 | ✅ |
|
||||
| 视觉反馈 | 拖拽时的动画和指示器 | ✅ |
|
||||
| 顺序指示 | 显示文件的当前位置 | ✅ |
|
||||
| 数据同步 | 拖拽后自动更新数据 | ✅ |
|
||||
| 事件通知 | 触发reorder事件通知父组件 | ✅ |
|
||||
| 响应式设计 | 适配不同屏幕尺寸 | ✅ |
|
||||
|
||||
### 🚀 使用场景
|
||||
|
||||
1. **文章封面图排序**:调整封面图的显示顺序,第一张作为主封面
|
||||
2. **图片轮播排序**:调整轮播图片的播放顺序
|
||||
3. **文件优先级**:根据重要性调整文件的排列顺序
|
||||
4. **展示顺序**:调整图片在前端的展示顺序
|
||||
|
||||
### 💡 技术亮点
|
||||
|
||||
- **原生HTML5拖拽API**:使用标准的拖拽事件
|
||||
- **Vue3响应式**:利用Vue3的响应式系统
|
||||
- **数据双向绑定**:保持组件内外数据同步
|
||||
- **优雅的动画效果**:提供流畅的用户体验
|
||||
- **类型安全**:完整的TypeScript类型定义
|
||||
|
||||
这个功能让用户可以更直观地管理文件顺序,特别是在处理多个封面图时,可以轻松调整哪张图片作为主封面显示!🎉
|
||||
Reference in New Issue
Block a user