当前位置: 首页 > news >正文

Aupload + vuedraggable实现 上传的文件可以拖拽排序

一、问题

        1.以前的需求已经通过Aupload封装了 文件上传组件,现在希望添加 文件拖拽排序功能

        2.首先想到可以使用 vuedraggable来实现。但是 vuedraggable需要传递数组并且在插槽里面指定单个元素的渲染方式,但是原本的Aupload组件是直接渲染数组的,要怎么兼容呢?

二、解决方法

        1.方法一:不用Aupload了,自己实现单个文件的渲染fileCard以及文件上传逻辑,在vueDraggable中复用fileCard组件。之前的很多逻辑都不能用了需要重写,工作量比较大,还有可能有性能问题

        2.方法二:在当前的基础上直接添加拖拽功能。本文采用方案二,具体实现如下

        3. 实现拖拽的功能:拿到上传的文件数据就行=> 拖拽区域的数据和上传区域的数据共用,拖拽结束后同步修改父组件传入的数据

        

<Draggablev-model="innerFileList"item-key="uid":animation="animation"tag="div"class="drag-list"@end="handleDragEnd"><!-- 拖拽区域 --><template #item="{ element }"><div class="drag-item"><AUpload:file-list="[element]":list-type="listType"@remove="handleRemove"@preview="handlePreview"></AUpload></div></template></Draggable><div><template v-if="!maxCount || innerFileList.length < maxCount"><AUploadv-bind="bind"v-model:file-list="innerFileList":beforeUpload="handleBeforeUpload":showUploadList="false"@remove="handleRemove"@change="handleChange"><!-- 添加图片 --><PlusOutlined /><div class="ml-1">{{ uploadText }}</div></AUpload></template></div>

        4. 现在上传图片后会显示两份数据:Draggable和Aupload各一份,如何只显示拖拽区域的数据呢? 

          AUpload添加配置不显示上传数据: :showUploadList="false"

        5. 当前的样式是:拖拽区域和上传区域 上下布局,如何让 上传区域紧跟在 Draggable渲染的列表后面呢? 

         把Aupload那部分放在 Draggable组件的 footer插槽中

      6. 对于图片希望可以直接预览,不打开新窗口

        使用AImage组件自定义预览渲染时机,默认样式设置为不显示

      7.支持批量上传,但是超过最大上传数量时,本次上传失败

        用当前所有的文件数量和最大上传数量比较。

        注意:beforeUpload中取到的只是本次上传的数量,需要加上 之前的数量,才是总的上传数量

async function handleBeforeUpload(file: UploadFile, fileList: UploadFile[]) {if (!checkMaxCount(fileList)) {return false}}// 检查文件数量是否超过最大限制
function checkMaxCount(fileList: UploadFile[]) {const totalCount = fileList.length + innerFileList.value.lengthif (props.maxCount && totalCount > props.maxCount) {message.destroy()message.warning(props.checkTips?.maxCount || `最多上传${props.maxCount}张图片`)return false}return true
}

        8.完整代码 

                1)DragSort.vue

<template><div class="flex flex-wrap gap-4"><!-- Aupload上传支持拖拽排序 --><Draggablev-model="innerFileList"item-key="uid":animation="animation"tag="div"class="drag-list"@end="handleDragEnd"><template #item="{ element }"><div class="inline-flex"><div class="drag-item"><AUpload :file-list="[element]" :list-type="listType" @remove="handleRemove"> </AUpload></div></div></template><template #footer><slot name="footer"><ImgUploadv-if="innerFileList.length < maxCount"v-bind="bind":show-upload-list="false"@update:file-list="handleUpdateFileList"/></slot></template></Draggable></div>
</template>
<script setup lang="ts">
import ImgUpload from '@/components/ImgUpload.vue'
import type { UploadFile } from 'ant-design-vue'
import type { UploadListType } from 'ant-design-vue/es/upload/interface'
import Draggable from 'vuedraggable'
const props = withDefaults(defineProps<{fileList?: UploadFile[]urlList?: string[]maxCount?: number[key: string]: anysize?: numberlistType?: UploadListTypeanimation?: number}>(),{size: 100,animation: 200,listType: 'picture-card',maxCount: 0}
)
const emit = defineEmits(['update:fileList', 'update:urlList'])
const attrs: any = useAttrs()
const bind = computed(() => {return {...attrs,...props}
})const innerFileList = ref<UploadFile[]>([])function handleUpdateFileList(fileList: UploadFile[]) {innerFileList.value = fileList
}// 删除文件
function handleRemove(file: UploadFile) {innerFileList.value = innerFileList.value.filter((item) => item.uid !== file.uid)emit('update:fileList', innerFileList.value)emit('update:urlList',innerFileList.value.map((item) => item.thumbUrl))
}// 拖拽结束——更新文件顺序
function handleDragEnd() {emit('update:fileList', innerFileList.value)emit('update:urlList',innerFileList.value.map((item) => item.thumbUrl))
}// 外部修改urlList——更新文件列表
watch(() => props.urlList,(newVal) => {if (newVal && newVal.length > 0) {innerFileList.value = newVal?.map((item: string) => {let itemInfo = item.split('.')return {uid: item,name: itemInfo[0] || item,url: item,thumbUrl: item,type: itemInfo[1]}})} else {innerFileList.value = []}},{immediate: true,deep: true}
)
</script><style lang="less" scoped>
.drag-list {@apply flex flex-wrap gap-4;.drag-item {width: v-bind('`${$props.size}px`');height: v-bind('`${$props.size}px`');cursor: move;@apply rounded-lg;}
}
</style>

                2)useFileDeal.ts

export function useFileDeal() {function getBase64(file: any) {return new Promise<string>((resolve) => {const reader = new FileReader()reader.addEventListener('load', () => resolve(reader.result as string))reader.readAsDataURL(file)})}// 将 base64 数据转换为 Blobfunction dataURLtoBlob(dataURL: string): Blob {const arr = dataURL.split(',')const mime = arr[0].match(/:(.*?);/)?.[1] || 'application/pdf'const bstr = atob(arr[1])let n = bstr.lengthconst u8arr = new Uint8Array(n)while (n--) {u8arr[n] = bstr.charCodeAt(n)}return new Blob([u8arr], { type: mime })}function previewFile(fileUrl: string) {if (fileUrl.startsWith('data:')) {// 如果是 base64 数据,创建 blob URLconst blob = dataURLtoBlob(fileUrl)const blobUrl = URL.createObjectURL(blob)const newWindow = window.open(blobUrl, '_blank')if (newWindow) {// 清理 blob URL 当窗口关闭时newWindow.addEventListener('beforeunload', () => {URL.revokeObjectURL(blobUrl)})}} else {// 如果是普通 URL,直接打开window.open(fileUrl, '_blank')}}// 获取文件类型enum FileType {DOCUMENT = 'DOCUMENT',SPREADSHEET = 'SPREADSHEET',IMAGE = 'IMAGE',PDF = 'PDF',PPT = 'PPT',UNKNOWN = 'UNKNOWN',OTHER = 'OTHER'}function getFileExt(file: string) {const start = file.lastIndexOf('.')const fileExt = file.slice(start + 1).toLowerCase()if (['pdf', 'ofd'].includes(fileExt)) {return FileType.PDF} else if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExt)) {return FileType.IMAGE} else if (['xls', 'xlsx'].includes(fileExt)) {return FileType.SPREADSHEET} else if (['ppt', 'pptx'].includes(fileExt)) {return FileType.PPT} else if (['doc', 'docx'].includes(fileExt)) {return FileType.DOCUMENT} else {return FileType.OTHER}}return {getBase64,dataURLtoBlob,previewFile,getFileExt,FileType}
}

三、总结

        1.通过 AUpload和vuedraggable可以实现 上传文件拖拽功能,但是需要注意了解第三库对应组件的详细属性

        2.其实实现的过程并不复杂,但是一开始没有思路想得脑子疼。还是要先行动,一步一步的想办法接近最终结果,很有可能就完美实现了!

/*

希望对你有帮助!

如有错误,欢迎指正,谢谢!

*/

http://www.dtcms.com/a/428272.html

相关文章:

  • 邯郸做网站的公司哪家好国家备案网
  • 人工智能与小程序开发:双翼齐飞,重塑数字体验新范式
  • eNSP、HCIA学习笔记
  • 网上书城 网站建设方案高端网站服务范围
  • Geant4实例
  • 网站建设一条龙全包seowordpress动态计时
  • 【Battery】慢速和快速充电的显示逻辑
  • 一个startActivity请求是如何穿越进程边界
  • 怎么看一个网站是用什么程序做的衡水建设网站
  • 网站建设配图微商城网站建设信息
  • 富文本【表格】
  • 【Java数据结构】——堆(找出用于解决最大/最小的n个元素,或者求中位数)
  • Python快速入门专业版(五十一):Python异常处理进阶:try-except-finally与raise语句(资源释放与主动抛异常)
  • 买家秀接口深度开发:从内容解析到情感分析的全链路实现
  • 密钥管理系统KSP在智能水表行业的应用
  • 中国建设银行网站多少汕头网站建设过程
  • 基于STM32与influxDB的电力监控系统-6
  • 【教程】nvidia-smi dmon获取GPU相关的完整信息
  • wordpress 网站上传制作网站的公司叫什么
  • 服装网站建设运营规划扬州网站建设推广
  • 网站后台管理怎么进asp网站服务建设
  • 公司建网站多少钱一个免费网页代理在线
  • 大连网站建设 青鸟传媒百度云平台建设网站
  • 豆各庄做网站的公司网站版块设计是什么意思
  • 代发新闻稿的网站四大软件外包公司
  • 信用体系建设网站维运工作制度任丘建设网站制作
  • JavaBean参数校验
  • 洛阳php网站开发桂林象鼻山照片
  • 第八章 惊喜13 落子无悔
  • 手机网站开发计划门户网站平台建设的经费