You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.6 KiB
6.6 KiB
🔄 SelectFile组件拖拽调整顺序功能演示
🎯 功能概述
我已经成功为SelectFile组件添加了拖拽调整顺序的功能,让用户可以通过拖拽来重新排列文件的顺序。
✨ 核心功能
-
🔄 拖拽排序
- 支持鼠标拖拽调整文件顺序
- 实时视觉反馈和拖拽指示器
- 顺序指示器显示当前位置
-
🎯 智能交互
- 拖拽时显示拖拽指示器
- 悬停时显示拖拽提示
- 拖拽完成后自动更新数据
-
📍 视觉反馈
- 顺序指示器显示文件位置
- 拖拽时的视觉效果
- 悬停时的交互提示
🔧 技术实现
1. 组件模板更新
<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. 拖拽逻辑实现
// 🔄 拖拽相关状态
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. 事件定义更新
const emit = defineEmits<{
(e: 'done', data: FileRecord): void;
(e: 'del', index: number): void;
(e: 'clear'): void;
(e: 'reorder', data: any[]): void; // 新增重新排序事件
}>();
4. 样式设计
// 🔄 可拖拽项目样式
.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事件的处理:
<SelectFile
:placeholder="`请选择图片`"
:limit="6"
:data="files"
@done="chooseFile"
@del="onDeleteFile"
@reorder="onReorderFiles"
/>
// 🔄 处理文件重新排序
const onReorderFiles = (newData: any[]) => {
files.value = newData;
form.files = JSON.stringify(files.value.map((d) => d.url));
message.success('文件顺序已更新');
};
🎨 用户体验
- 直观操作:用户可以直接拖拽文件来调整顺序
- 视觉反馈:拖拽时有清晰的视觉指示
- 顺序显示:每个文件都有序号显示当前位置
- 即时更新:拖拽完成后立即更新数据和UI
📊 功能特点
特性 | 描述 | 状态 |
---|---|---|
拖拽排序 | 支持鼠标拖拽调整顺序 | ✅ |
视觉反馈 | 拖拽时的动画和指示器 | ✅ |
顺序指示 | 显示文件的当前位置 | ✅ |
数据同步 | 拖拽后自动更新数据 | ✅ |
事件通知 | 触发reorder事件通知父组件 | ✅ |
响应式设计 | 适配不同屏幕尺寸 | ✅ |
🚀 使用场景
- 文章封面图排序:调整封面图的显示顺序,第一张作为主封面
- 图片轮播排序:调整轮播图片的播放顺序
- 文件优先级:根据重要性调整文件的排列顺序
- 展示顺序:调整图片在前端的展示顺序
💡 技术亮点
- 原生HTML5拖拽API:使用标准的拖拽事件
- Vue3响应式:利用Vue3的响应式系统
- 数据双向绑定:保持组件内外数据同步
- 优雅的动画效果:提供流畅的用户体验
- 类型安全:完整的TypeScript类型定义
这个功能让用户可以更直观地管理文件顺序,特别是在处理多个封面图时,可以轻松调整哪张图片作为主封面显示!🎉