1. 效果图:
2. 复制图片使用的方法:
paste
方法,获取复制内容clipboardData
file
文件进行上传
handlePaste(value){
let files = value.clipboardData.files
if(files){
files=files[0]
}else{
files=value.clipboardData.items[0].getAsFile()
}
console.log(files)
}
3. 拖拽使用的方法:
dragover
、drop
、dragleave
事件,进行判断拖拽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.使用:
copy-upload
组件,并关联对应的v-model
inpuDrag->拖拽相关方法
,inpuPaste->复制相关方法
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>