1. 效果图:
2. 复制图片使用的方法:
- 1.通过监听
paste
方法,获取复制内容 - 2.获取复制内容中的
clipboardData
- 3.获取
file
文件进行上传
<input @paste.native="handlePaste" />
handlePaste(value){
let files = value.clipboardData.files
if(files){
files=files[0]
}else{
files=value.clipboardData.items[0].getAsFile()
}
console.log(files)
}
3. 拖拽使用的方法:
- 1.通过监听
dragover
、drop
、dragleave
事件,进行判断拖拽 - 2.
drop
释放鼠标时,获取对应文件的file并上传
const e=Dom //节点
// 挂载监听拖拽
e.removeEventListener('dragover',this.handletDragover,false)
e.addEventListener('dragover',this.handlePaste,false)
// 挂载监听释放
e.removeEventListener('drop',this.handletDrop,false)
e.addEventListener('drop',this.handletDrop,false)
// 挂载监听离开
e.removeEventListener('dragleave',this.handletDragleave,false)
e.addEventListener('dragleave',this.handletDragleave,false)
const handletDragover(e)=>{
e.preventDefault();
// 当拖拽到对应元素是设置样式
}
const handletDragleave(e)=>{
// 离开对应元素是设置样式
}
const handletDrop(e)=>{
const files = e.dataTransfer.files;
// 获取对应的files,并进行上传
e.preventDefault();
e.stopPropagation();
}
4. el-upload封装对应方法,并实现限制种类、大小等
-
1.组件(copy-upload.vue):
<template> <el-upload :action="sendUrl" :accept="acceptArray.length>0?acceptArray.map(n=>this.acceptType[n]).join(',') :'*'" class="upload-demo" :http-request="handleFileUpload" :headers="headers" :data="data" :on-preview="handlePreview" :on-remove="handleRemove" :before-upload="beforeUpload" :before-remove="beforeRemove" :on-success="handleSuccess" :on-erroe="handleError" :multiple="multiple" :limit="limit" :on-exceed="handleExceed" :file-list="fileList"> <el-button size="small" type="primary">点击上传</el-button> <div v-if="size>0" slot="tip" class="el-upload__tip">{{ acceptTitle!=''?acceptTitle :`只能上传${(acceptArray.map(n=>n=='image'?'图片':n).join('/'))}文件` }},且不超过{{ filterSize(size) }}</div> </el-upload> </template> <script> export default { model:{ prop:'parentFileList', event:'change-fileList' }, props: { // 请求头 headers:{ type:Object, default:()=>{} }, // 大小限制:10 * 1024 * 1024 = 10MB size:{ type:Number, default:-1 }, // 展示的文字 acceptTitle:{ type:String, default:'' }, // 限制类型,按照acceptType数组里面来 acceptArray:{ type:Array, default(){ return ['doc', 'docx', 'pdf', 'xls', 'xlsx','png','jpg','jpeg','gif'] } }, // 数量 limit:{ type:Number, default:null }, // 是否可以多选 multiple:{ type:Boolean, default:false }, // 额外数据 data:{ type:Object, default() { return { uploadType: 'common', security:'public', module:'common', } } }, // 存在的数据(v-model关联的) parentFileList:{ type:Array, default(){ return [] } }, // 请求头 sendUrl:{ type:String, default:'' } }, data() { return { acceptType:{ 'doc':'application/msword', 'docx':'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'ppt':"application/vnd.ms-powerpoint", 'pptx':'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'xls':'application/vnd.ms-excel', 'xlsx':'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'pdf':'application/pdf', 'csv':'.csv', 'txt':'text/plain', 'image':'image/*', 'png':'image/png', 'gif':'image/gif', 'jpg':'image/jpg', 'jpeg':'image/jpeg' }, fileList:[], isClearTitle:true }; }, watch: { parentFileList:{ handler(value){ this.fileList=value }, deep:true, immediate:true }, fileList:{ handler(value){ this.$emit('change-fileList',value) }, deep:true, } }, created(){ // 抛处监听请求 this.$emit('inpuPaste',(e)=>{ if(e){ // 挂载监听复制 e.removeEventListener('paste',this.handlePaste,false) e.addEventListener('paste',this.handlePaste,false) } }) this.$emit('inpuDrag',(e)=>{ if(e){ // 挂载监听拖拽 e.removeEventListener('dragover',this.handletDragover,false) e.addEventListener('dragover',this.handlePaste,false) // 挂载监听释放 e.removeEventListener('drop',this.handletDrop,false) e.addEventListener('drop',this.handletDrop,false) // 挂载监听离开 e.removeEventListener('dragleave',this.handletDragleave,false) e.addEventListener('dragleave',this.handletDragleave,false) } }) }, methods: { handletDragover(e){ e.preventDefault(); }, handletDragleave(e){ }, handletDrop(e){ const files = e.dataTransfer.files; this.copyUp(files) e.preventDefault(); e.stopPropagation(); }, filterSize(size){ const pow1024=(num)=>{ return Math.pow(1024, num) } if (!size) return '' if (size < pow1024(1)) return size + ' B' if (size < pow1024(2)) return (size / pow1024(1)).toFixed(0) + ' KB' if (size < pow1024(3)) return (size / pow1024(2)).toFixed(0) + ' MB' if (size < pow1024(4)) return (size / pow1024(3)).toFixed(0) + ' GB' return (size / pow1024(4)).toFixed(2) + ' TB' }, // 判断 judegFileSize(file){ let retunBoolean=true let fileSize = file.size //判断文件类型 const fileExtArray=file.name.split('.') const judegFn=()=>{ if(this.acceptArray.indexOf(fileExtArray.at(-1))==-1){ this.$message.error(`${file.name}上传失败,只能上传${this.acceptArray.join('、')}`) retunBoolean=false } } if(this.acceptArray.length>0){ if(this.acceptArray.indexOf('image')!=-1){ var pattern = /(\.jpg|\.jpeg|\.png|\.gif)$/i; // 判断文件名是否匹配图片格式的正则表达式 if (!pattern.test(`.${fileExtArray.at(-1)}`)) { judegFn() } }else{ judegFn() } } if(retunBoolean){ if (this.size>0 && fileSize > this.size) { this.$message.error(`最大上传${this.filterSize(this.size)}`) retunBoolean=false } } if(!retunBoolean){ this.isClearTitle=false } return retunBoolean }, postUpObject(file){ return { action:this.sendUrl, data:this.data, file:file, headers:this.headers, onSuccess:this.handleSuccess, onError:this.handleError } }, // 自定义上传 handleFileUpload(data) { const formData = new FormData(); formData.append("file", data.file); if(data.data){ Object.keys(data.data).forEach(key => { formData.append(key, data.data[key]); }) } fetch(data.action, { method: "POST", body: formData, headers: data.headers, 'Content-type': 'multipart/form-data' }) .then(respone => respone.json()) .then(res=>{ if (data.onSuccess) data.onSuccess(res, data.file, this.fileList) }).catch(error=>{ if (data.onError) data.onError({message:'上传失败'}, data.file, this.fileList) }) }, // 上传之前,需要将数据追加到fileList,复制图片是存在复制 beforeUpload(file){ const isFile=this.judegFileSize(file) if(isFile){ if(this.multiple){ this.fileList.push(file) }else{ this.fileList=[file] } } return isFile }, // 点击(预览),需要在成功后将url放入file里面 handlePreview(file) { if(file.status=="success" && file.url){ const extArray=file.url.split('.') const extArrayAll=['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'] if(extArrayAll.indexOf(extArray.at(-1))!=-1){ window.open(`https://view.officeapps.live.com/op/view.aspx?src=${file.url}`) }else{ window.open('http://www.pfile.com.cn/api/profile/onlinePreview?url='+encodeURIComponent(file.url)); } } }, // 超过限制 handleExceed(files, fileList) { this.$message.warning(`当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`); }, // 删除 handleRemove(file, fileList) { const index=this.fileList.findIndex(n=>n.uid==file.uid) if(index!=-1){ this.fileList.splice(index,1) this.isClearTitle=true } }, // 删除之前 beforeRemove(file, fileList) { if(this.isClearTitle){ return this.$confirm(`确定移除 ${ file.name }?`); } }, // 成功&&插入对应的url handleSuccess(res,file,fileList){ if(res.code && res.code==200){ const resData=res.data const index=this.fileList.findIndex(n=>n.uid==file.uid) if(index!=-1){ const fileData=this.fileList[index] this.fileList.splice(index,1,Object.assign(fileData,{url:resData.url})) // console.log(this.fileList,'---handleSuccess') console.log(res,'handleSuccess') } }else{ this.handleError({message:'上传失败'},file,fileList) } }, // 失败 handleError(error,file,fileList){ const index=this.fileList.findIndex(n=>n.uid==file.uid) if(index!=-1){ this.fileList.splice(index,1) this.$message.error(`${file.name}上传失败`) } console.log(error,'handleError') }, copyUp(files){ if(files && files.length>0){ if(!this.multiple){ const file=files[0] if(this.judegFileSize(file)){ this.fileList=[file] this.handleFileUpload(this.postUpObject(file)) } }else{ for(let x=0;x<files.length;x++){ const file=files[x] if(this.fileList.length<this.limit || !this.limit){ if(this.judegFileSize(file)){ this.fileList.push(file) this.handleFileUpload(this.postUpObject(file)) } }else{ this.handleExceed(files,fileList) break; } } } } }, handlePaste(value){ if(value.clipboardData){ const fileList=[...this.fileList] let files = value.clipboardData.files if(!files){ files=Array.from(value.clipboardData.items).map(n=>n.getAsFile()).filter(n=>n) } this.copyUp(files) } }, }, }; </script> <style scoped> ::v-deep .el-upload-list__item:first-child{ margin-left: 0 !important; } </style>
-
2.使用:
- 1.引入
copy-upload
组件,并关联对应的v-model
- 2.监听组件抛出的方法
inpuDrag->拖拽相关方法
,inpuPaste->复制相关方法
- 3.对应的
input
定义ref
,然后监听的方法使用,并传入对应的Dom节点,@inpuDrag="$event(input的Dom节点)"
,@inpuPaste="$event(input的Dom节点)"
<div style='width:600px'> <el-input v-model='txt' ref="copyUploadRef" style='margin-bottom:10px' type="textarea" :rows="5"></el-input> <copy-upload v-model="fileList" :size="10 * 1024 * 1024" acceptTitle="pdf或word或Excel或常见图片格式" :multiple="true" :headers='{}' @inpuDrag="$event($refs.copyUploadRef.$el)" @inpuPaste="$event($refs.copyUploadRef.$el)" sendUrl="/api/posts/" :data="{}"></copy-upload> </div>
- 1.引入