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

vue3 + ts + element-plus(el-upload + vuedraggable实现上传OSS并排序)

这里创建项目就不多说了

安装element-plus

npm install element-plus

安装vuedraggable

npm install vuedraggable

安装ali-oss

npm install ali-oss

这里是封装一下:在components创建文件夹jc-upload>jc-upload.vue

在封装的过程中遇到了一个问题就是draggable和el-upload上传按钮独占一行,显然不是我们需要的效果,先看问题

百度了一下,没有找到什么解决办法,这里通过一行css解决以上问题,如有大佬有更好的方案可以分享一下

.draggable-container {display: contents;}

 完整代码

<template><div class="upload-container"><draggable class="draggable-container" v-model="newsFileList" itemKey="url" ghost-class="ghost" animation="300"><template #item="{ element }"><ul class="el-upload-list el-upload-list--picture-card"><li :key="element.url" class="el-upload-list__item is-success animated"><img class="el-upload-list__item-thumbnail" :src="element.url" alt=""><label class="el-upload-list__item-status-label"><i class="el-icon el-icon--upload-success el-icon--check"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor"d="M406.656 706.944 195.84 496.256a32 32 0 1 0-45.248 45.248l256 256 512-512a32 32 0 0 0-45.248-45.248L406.592 706.944z"></path></svg></i></label><i class="el-icon-close"></i><span class="el-upload-list__item-actions"><!-- 预览 --><span class="el-upload-list__item-preview"@click="handlePictureCardPreview(element)"><i class="el-icon el-icon--zoom-in"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor"d="m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704zm-32-384v-96a32 32 0 0 1 64 0v96h96a32 32 0 0 1 0 64h-96v96a32 32 0 0 1-64 0v-96h-96a32 32 0 0 1 0-64h96z"></path></svg></i></span><!-- 删除 --><span class="el-upload-list__item-delete" @click="handleRemove(element)"><i class="el-icon el-icon--zoom-in"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor"d="M160 256H96a32 32 0 0 1 0-64h256V95.936a32 32 0 0 1 32-32h256a32 32 0 0 1 32 32V192h256a32 32 0 1 1 0 64h-64v672a32 32 0 0 1-32 32H192a32 32 0 0 1-32-32V256zm448-64v-64H416v64h192zM224 896h576V256H224v640zm192-128a32 32 0 0 1-32-32V416a32 32 0 0 1 64 0v320a32 32 0 0 1-32 32zm192 0a32 32 0 0 1-32-32V416a32 32 0 0 1 64 0v320a32 32 0 0 1-32 32z"></path></svg></i></span></span></li></ul></template></draggable><el-upload ref="uploadRef" :show-file-list="false" :class="newsFileList.length >= limit ? 'upload-hide' : ''":action="action" :accept="accept" list-type="picture-card" :file-list="newsFileList" :on-remove="handleRemove" :on-success="onSuccess" :limit="limit":disabled="disabled"with-credentials :multiple="limit > 1? true : false"drag><el-icon><Plus /></el-icon></el-upload><el-dialog v-model="dialogVisible"><img class="uy-w-p-100" w-full :src="dialogImageUrl" alt="Preview Image" /></el-dialog></div>
</template><script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { ElNotification, type UploadFile } from 'element-plus'
import OSS from 'ali-oss';
import draggable from 'vuedraggable';const $emit = defineEmits(['success'])/*** 组件props*/
const props = defineProps({action: {type: String,// default: `${import.meta.env.VITE_SERVE}/api/Osstoken/getToken`default: `/api/api/Osstoken/getToken`},fileList: {type: Array as () => UploadFile[],default: () => []},limit: {type: Number,default: 1},accept: {type: String,default: 'image/*'},disabled: {type: Boolean,default: false}
})// data数据
const uploadRef = ref()
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const disabled = ref(false)
let newsFileList = ref(props.fileList);// methods方法
const handleRemove = (file: UploadFile) => {const index = newsFileList.value.findIndex(item => item.url === file.url);newsFileList.value.splice(index, 1);$emit('success', newsFileList)
};const handlePictureCardPreview = (file: UploadFile) => {dialogImageUrl.value = file.url!dialogVisible.value = true
};const uploadAliyun = async (res: any, file: UploadFile, fileList: UploadFile[]) => {if (res.code === 0) {let date = new Date();let year = date.getFullYear();let month = date.getMonth() + 1;let day = date.getDate();let formattedMonth = month.toString().padStart(2, '0');let formattedDay = day.toString().padStart(2, '0');const filePath = `/uploads/${year}/${formattedMonth}/${formattedDay}/${Date.parse(date.toString()) + parseInt((Math.random() * (100000 - 10000 + 1) + 10000).toString(), 10).toString()}.${file.raw?.name.split('.').pop()}`let client = new OSS({accessKeyId: res.data.AccessKeyId, //OSS的用户名accessKeySecret: res.data.AccessKeySecret, //OSS密钥region: res.data.region, //域名是创建Buckiet,时选择的服务器地址 比如选择 华南3(广州):oss-cn-guangzhoubucket: res.data.bucket,  //创建Buckiet的名称stsToken: res.data.SecurityToken //临时Token})const put = async () => {try {const result = await client.put(filePath, file.raw!);if(result.res.status === 200) {if(props.accept === 'video/*') {file.url = (result.res as any).requestUrls[0] + '?x-oss-process=video/snapshot,t_0,f_jpg';}newsFileList.value.push({url: (result.res as any).requestUrls[0],name: '',status: 'success',uid: 0})$emit('success', newsFileList)}} catch (err) {ElNotification.success({ message: '上传失败~' });}}put();} else {ElNotification.success({ message: res.msg });}
};const onSuccess = (res: any, file: UploadFile, fileList: UploadFile[]) => {uploadAliyun(res, file, fileList)
};watch(() => props.fileList, (newVal) => {newsFileList.value = newVal
}, { deep: true })watch(() => newsFileList.value, (newVal) => {if(JSON.stringify(newVal) !== JSON.stringify(props.fileList)) {$emit('success', newVal)}
}, { deep: true })
</script><style lang="scss" scoped>
:deep(.el-upload-dragger) {padding: 56px 0;background-color: transparent;border: none;
}.upload-hide {position: relative;:deep(.el-upload--picture-card) {display: none;}
}.upload-container {display: flex;flex-wrap: wrap;.draggable-container {display: contents;}
}
</style>

对以上代码解释一下

重点解决el-upload上传按钮独占一行问题

.upload-container {display: flex;flex-wrap: wrap;.draggable-container {display: contents;}
}

主要对limit最大限制对上传按钮隐藏 

.upload-hide {position: relative;:deep(.el-upload--picture-card) {display: none;}
}

action主要获取OSS上传凭证这里用了代理,通过前端请求后端接口会拒绝访问,线上不需要代理

这段代码主要为了更新排序后的数组

watch(() => newsFileList.value, (newVal) => {if(JSON.stringify(newVal) !== JSON.stringify(props.fileList)) {$emit('success', newVal)}
}, { deep: true })

这里为什么选用ref并不是为了省事ref一把梭,刚开始我用的 reactive但是在排序的时候一直回弹,具体原因没有深究,换成ref就没问题了

let newsFileList = ref(props.fileList);

就解释这么多吧,有什么疑问或不明白的地方可以留言,有什么更好的方案请大佬们赐教,写的不好请多多担待

相关文章:

vue3 + ts + element-plus(el-upload + vuedraggable实现上传OSS并排序)

这里创建项目就不多说了 安装element-plus npm install element-plus 安装vuedraggable npm install vuedraggable 安装ali-oss npm install ali-oss 这里是封装一下&#xff1a;在components创建文件夹jc-upload>jc-upload.vue 在封装的过程中遇到了一个问题就是dr…...

SQL开窗函数相关的面试题和答案

基本排序与分组问题 题目&#xff1a;有学生成绩表tb_score&#xff0c;包含字段SNO&#xff08;学号&#xff09;、SCLASS&#xff08;班级&#xff09;、CHINESE&#xff08;语文成绩&#xff09;、ENGLISH&#xff08;英语成绩&#xff09;、ARITH&#xff08;数学成绩&…...

【数据分析(一)】初探 Numpy

目录 前言1. 一维 array 的生成2. 一维 array 的基本操作2.1. 查看属性2.2. 花式索引2.3. 条件筛查2.4. 数据统计 3. n 维 array 的生成4. n 维 array 的基本操作4.1. 查看属性4.2. 查询和切片4.3. 花式索引4.4. 矩阵 前言 Numpy是Python的常用开源数值计算扩展库&#xff0c;用…...

国产化ARM平台-飞腾派开发板硬件与系统

国产化ARM平台-飞腾派开发板硬件与系统 一、飞腾E2000处理器 飞腾腾珑E2000系列包括E2000Q、E2000D、E2000S三个系列&#xff0c;芯片集成飞腾自主研发的高能效和低功耗处理器核&#xff0c;E2000Q集成2个FTC664和2个FTC310处理器核&#xff0c;E2000D集成2个FTC310处理器核&…...

[ LeetCode 75 ] 283 移动零(JavaScript)

283 移动零 题目描述解题思路步骤解析时间和空间复杂度代码实现 题目描述 LeetCode 283 移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操…...

前端学习汇总

一、打包工具 1.1、vite vite&#xff1a;vite -- 开发环境 热更新_vite 热更新-CSDN博客 1.2、webpack 常用loader&#xff1a;webpack基础---常用loader_webpack 常用loader-CSDN博客 loader&#xff1a;webpack4和webpack5区别1---loader_webpack4与webpack5处理图片的…...

蓝笔科技 | 超凡妈妈赋能计划-【北大生涯规划师特别企划】

12月27日&#xff0c;“超凡妈妈赋能计划-北大生涯规划师特别企划”在广州正式启动&#xff0c;据了解&#xff0c;本次超凡妈妈赋能计划是由广州蓝笔科技信息有限公司牵头发起并主办&#xff0c;中国关心下一代健康体育基金会作为公益支持单位&#xff0c;北京大学作为项目技术…...

【电路笔记 TMS320C6***DSP】C6748 EDMA3配置笔记 寄存器配置+影子通道寄存器+配置示例

目录 参照资料内存映射寄存器分类影子通道寄存器传输中断PaRAM参数SRC、DSTA_B_CNT、CCNTSRC_DST_BIDXSRC_DST_CIDXOPTopt示例 链接传输LINK_BCNTRLD (LinkAddress/BCountReloadParameter)示例代码示例配置&#xff1a;块传输示例配置&#xff1a;矩阵转置示例配置&#xff1a;…...

2025新春烟花代码(二)HTML5实现孔明灯和烟花效果

效果展示 源代码 <!DOCTYPE html> <html lang"en"> <script>var _hmt _hmt || [];(function () {var hm document.createElement("script");hm.src "https://hm.baidu.com/hm.js?45f95f1bfde85c7777c3d1157e8c2d34";var …...

apollo内置eureka dashboard授权登录

要确保访问Eureka Server时要求输入账户和密码&#xff0c;需要确保以下几点&#xff1a; 确保 eurekaSecurityEnabled 配置为 true&#xff1a;这个配置项控制是否启用Eureka的安全认证。如果它被设置为 false&#xff0c;即使配置了用户名和密码&#xff0c;也不会启用安全认…...

后台管理系统全屏功能实现

后台管理系统中有一个比较常见的功能就是全屏显示&#xff0c;以方便用最大的屏幕查看系统&#xff0c;特别是在小屏模式下。 对于 screenfull 而言&#xff0c;浏览器本身已经提供了对用的 API&#xff0c;点击这里即可查看&#xff0c;这个 API 中&#xff0c;主要提供了两个…...

风电叶片市场竞争激烈:开启绿色能源新篇章的巨大潜力

一、引言 面对全球气候变化的严峻挑战&#xff0c;可再生能源的开发与利用已成为各国共识。风电&#xff0c;作为技术最成熟、最具规模化开发条件的可再生能源之一&#xff0c;正以前所未有的速度发展。而风电叶片&#xff0c;作为风电机组的核心部件&#xff0c;其技术创新与…...

【Unity3D日常开发】Unity3D中适用WEBGL打开Window文件对话框打开/上传文件

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 Unity3D发布的WEBGL程序是不支持直接的I/O操…...

C# 或 .NetCore 如何使用 NPOI 导出图片到 Excel 文件

今天在本文中&#xff0c;我们将尝试使用NPOI库将图像插入到 Excel 文件的特定位置。请将以下逻辑添加到您的写作方法中&#xff0c;在 Excel 文件中添加图像&#xff08;JPEG、PNG&#xff09;,我已经有一个示例 jpeg 文件 - Read-write-excel-npoi.jpg &#xff0c;我们将尝试…...

Lambda expressions in C++ (C++ 中的 lambda 表达式)

Lambda expressions in C {C 中的 lambda 表达式} 1. Parts of a lambda expression (Lambda 表达式的各个部分)1.2. Parameter list (Optional) References lambda /ˈlm.də/&#xff1a;the 11th letter of the Greek alphabet (希腊语字母表的第 11 个字母)https://learn.m…...

【Rust自学】11.4. 用should_panic检查恐慌

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.4.1. 验证错误处理的情况 测试函数出了验证代码的返回值是否正确&#xff0c;还需要验证代码是否如预期的去处理了发生错误的情况。比…...

高斯函数Gaussian绘制matlab

高斯 约翰卡尔弗里德里希高斯&#xff0c;&#xff08;德语&#xff1a;Johann Carl Friedrich Gau&#xff0c;英语&#xff1a;Gauss&#xff0c;拉丁语&#xff1a;Carolus Fridericus Gauss&#xff09;1777年4月30日–1855年2月23日&#xff0c;德国著名数学家、物理学家…...

获取客户端真实IP地址

当处理来自客户端的请求时&#xff0c;尤其是在存在代理服务器的情况下&#xff0c;可能需要考虑多种HTTP请求头&#xff0c;以尽可能准确地获取用户的真实IP地址。以下是考虑了X-Forwarded-For、Proxy-Client-IP、WL-Proxy-Client-IP、HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR的…...

Kotlin学习(一)

1. Kotlin 作用域函数 如果同学们已经在项目中用过 Kotlin 语言&#xff0c;那么一定见过 let 函数&#xff01;因为每当 Kotlin 检测到某个对象可能为空时&#xff0c;会自动帮我们修改为用 let 函数实现&#xff1a;user.name?.let{ textView.text it }。这里的 let 函数就…...

鸿蒙UI开发——日历选择器

1、概 述 在项目开发中&#xff0c;我们时常会用到日历选择器&#xff0c;效果如下&#xff1a; ArkUI已经为我们提供了组件&#xff0c;我们可以直接使用&#xff0c;下面针对日历组件做简单介绍。 2、CalendarPickerDialog 接口定义如下&#xff1a; // 定义日历选择器弹…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

Mysql故障排插与环境优化

前置知识点 最上层是一些客户端和连接服务&#xff0c;包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念&#xff0c;为通过安全认证接入的客户端提供线程。同样在该层上可…...