vue实现拖拽或点击上传图片
程序员文章站
2022-04-11 10:33:32
本文实例为大家分享了vue实现拖拽或点击上传图片的具体代码,供大家参考,具体内容如下一、预览图二、实现点击上传思路:将input的type设置为“file”类型即可上传文件。隐藏该input框,同时点...
本文实例为大家分享了vue实现拖拽或点击上传图片的具体代码,供大家参考,具体内容如下
一、预览图
二、实现
点击上传思路:将input的type设置为“file”类型即可上传文件。隐藏该input框,同时点击按钮时,调取该input的点击上传功能。剩下的就是css优化页面了。
拖拽上传思路:通过给拖拽框dropbox绑定拖拽事件,当组件销毁时解绑事件。在拖拽结束,通过event.datatransfer.files获取上传的文件信息。然后在对文件进行上传服务器操作。
接下来请允许我简单介绍一下各个组件:
upload.vue封装了点击上传的逻辑,而进度条则没有做,后期可基于percent做参数继续完善进度条;uploadformdialog.vue是父盒子,即点击上传按钮后弹出的对话框,在该组件中需要完成页面的布局,拖拽上传等逻辑;
这样封装的意义是为了使得代码更便于维护。
upload.vue 点击上传组件
<template> <!--upload.vue 点击上传组件 --> <div class="file-selector"> <z-btn class="selector-btn" color="primary" @click="handleupclick"> 选择文件 </z-btn> <input ref="input" class="file-selector-input" type="file" :multiple="multiple" :accept="accept" @change="handlefiles" /> </div> </template> <script> import {debounce} from 'lodash/function'; export default { data() { return { accept: '.jpg,.jpeg,.png,.gif', multiple: false, list: [], // 已选择的文件对象 uploadfinished: true, // 上传状态 startindex: 0, // 开始上传的下标,用于追加文件 maxsize: 10 * 1024 * 1024, //10m(size单位为byte) // source: this.$axios.canceltoken.source(), // axios 取消请求 }; }, methods: { // 重置 reset() { this.list = []; this.source.cancel(); this.startindex = 0; this.uploadfinished = true; this.$refs.input && (this.$refs.input.value = null); }, // 调用上传功能 handleupclick: debounce(function () { // 可在此维护一个上传状态,上传过程中禁用上传按钮 // if (!this.uploadfinished) this.$message.info('即将覆盖之前的文件~'); this.$refs.input.click(); }, 300), handlefiles(e) { const files = e?.target?.files; this.readfiles(files); }, // 上传之前将文件处理为对象 readfiles(files) { if (!files || files.length <= 0) { return; } for (const file of files) { const url = window.url.createobjecturl(file); const obj = { title: file.name.replace(/(.*\/)*([^.]+).*/ig, '$2'), // 去掉文件后缀 url, file, filetype: file.type, status: 0, // 状态 -> 0 等待中,1 完成, 2 正在上传,3 上传失败 percent: 0, // 上传进度 }; // 提前在 data 中定义 list,用来保存需要上传的文件 this.list.unshift(obj); this.$emit('filelist', this.list); } // 在 data 中定义 startindex 初始值为 0,上传完成后更新,用于追加上传文件 // this.startupload(this.startindex); }, } }; </script> <style lang="scss"> .file-selector { .selector-btn { &:hover { background-color: rgba($color: #2976e6, $alpha: 0.8); transition: background 180ms; } } &-input { display: none; } } </style>
uploadformdialog.vue 上传对话框
<template> <!-- 上传dialog --> <form-dialog v-model="$attrs.value" :title="title" persistent :loading="loading" maxwidth="600px" min-height='400px' @cancel="handlecancle" @confirm="handlesubmit" > <div class="d-flex flex-row justify-space-between"> <z-form style='width: 260px; height: 100%;'> <form-item label="图片名称" required> <z-text-field v-model="formdata.name" outlined :rules="rules" :disabled='disabled' placeholder="请输入图片名称" > </z-text-field> </form-item> <form-item label="描述" required> <z-textarea v-model="formdata.description" outlined :disabled='disabled' placeholder="请输入描述" style="resize: none;" > </z-textarea> </form-item> </z-form> <div ref="pickerarea" class="rightbox"> <div class="uploadinputs d-flex flex-column justify-center align-center" :class="[ dragging ? 'dragging' : '']"> <div ref="uploadbg" class="uploadbg my-2"></div> <upload ref="uploadbtn" @filelist='filelist' ></upload> <div class="tip mt-2">点击上传按钮,或拖拽文件到框内上传</div> <div class="tinytip ">请选择不大于 10m 的文件</div> </div> </div> </div> </form-dialog> </template> <script > import {debounce} from 'lodash/function'; import upload from './upload'; import {uploadimage} from '@/wv-main-admin/apis/image'; export default { components: { upload }, props: ['dialogdata'], data() { return { dialogflag: '', title: '新增/编辑图片', loading: false, formdata: { name: '', description: '' }, disabled: false, rules: [v => !!v || '必填'], data: {}, dragging: true, //是否拖拽 binddrop: false, fileinfo: {}, }; }, mounted() { }, beforedestroy() { // 组件销毁前解绑拖拽事件 try { const dropbox = this.$refs.pickerarea; dropbox.removeeventlistener('drop', this.handledrop); dropbox.removeeventlistener('dragleave', this.handledragleave); dropbox.removeeventlistener('dragover', this.handledragover); this.binddrop = false; } catch (e) { console.log(e, '======我是组件销毁前解绑拖拽事件的异常'); } }, methods: { //取消 handlecancle() { // 关闭当前弹框 this.$emit('input', false); // 强制组件刷新 this.$forceupdate(); }, handlesubmit: debounce(function () { // 上传单个文件 const flag = this.checkmustsitem(); if (flag) { this.startupload(); // 上传完成,强制组件刷新 this.$forceupdate(); } }, 300), //监听子组件的值 filelist(data) { this.fileinfo = data[0]; this.formdata.name = this.fileinfo.title; const uploadbg = this.$refs.uploadbg; //改变背景图片 uploadbg.style.backgroundimage = `url(${this.fileinfo.url})`; }, bindevents() { const dropbox = this.$refs.pickerarea; // 防止重复绑定事件,需要在 data 中初始化 binddrop 为 false if (!dropbox || this.binddrop) { return; } // 绑定拖拽事件,在组件销毁时解绑 dropbox.addeventlistener('drop', this.handledrop, false); dropbox.addeventlistener('dragleave', this.handledragleave); dropbox.addeventlistener('dragover', this.handledragover); this.binddrop = true; }, // 拖拽到上传区域 handledragover(e) { e.stoppropagation(); e.preventdefault(); this.dragging = true; }, // 离开上传区域 handledragleave(e) { e.stoppropagation(); e.preventdefault(); this.dragging = false; }, // 拖拽结束 handledrop(e) { e.stoppropagation(); e.preventdefault(); this.dragging = false; const files = e.datatransfer.files; // 调用 <upload/> 组件的上传功能 this.$refs.uploadbtn && this.$refs.uploadbtn.readfiles(files); }, // 上传前需要校验文件 checkfile(index) { const file = this.list[index]; // 如果文件不存在,即全部文件上传完成 if (!file) { // 上传完成,向父组件抛出 success 事件 this.uploadfinished = true; this.$emit('success', this.list); // 清空上传控件中的值,保证 change 事件能正常触发 this.$refs.input.value = null; this.startindex = index > 1 ? index - 1 : 0; return false; } // 校验是否已上传 if (`${file.status}` === '1') { this.startupload(++index); return false; } // 校验文件大小 if (this.maxsize && file.file && file.file.size >= this.maxsize) { this.startupload(++index); return false; } return true; }, checkmustsitem() { if (!this.fileinfo.file) { this.$message.warning('请上传文件!'); return false; } if (!this.formdata.name) { this.$message.warning('请输入文件名称!'); return false; } if (!this.formdata.description) { this.$message.warning('请输入文件描述!'); return false; } return true; }, // 上传单个文件 startupload() { this.loading = true; const params = { type: 'image' }; this.$set(params, 'file', this.fileinfo.file); this.$set(params, 'name', this.formdata.name); this.$set(params, 'description', this.formdata.description); uploadimage(params) .then(res => { this.loading = false; if (res.code === 0) { this.$message.success('上传成功~'); this.$emit('refreshlist', false); this.$emit('input', false); } }) .catch(() => { this.loading = false; }); // this.$axios({ // url: this.url, // 上传接口,由 props 传入 // method: 'post', // data, // withcredentials: true, // canceltoken: this.source.token, // 用于取消接口请求 // // 进度条 // onuploadprogress: e => { // if (fileobj.status === 1) { return; } // 已上传 // // 限定最大值为 99% // const p = parseint((e.loaded / e.total) * 99); // if (e.total) { // fileobj.status = 2; // 正在上传 // fileobj.percent = p; // 更新上传进度 // } else { // fileobj.status = 3; // 上传失败 // } // }, // }) // .then(response => { // if (`${response.code}` === '200') { // fileobj.status = 1; // fileobj.percent = 100; // } else { // fileobj.status = 3; // } // }) // .catch(e => { // console.log(e, '====error'); // fileobj.status = 3; // }) // .finally(e => { // console.log(e, '====error'); // this.startupload(++index); // }); // 上传完成 }, }, }; </script> <style lang='scss' scoped> .rightbox { width: 260px; height: 250px; border: 1px solid #ccc; margin-top: 18px; .uploadbg { width: 150px; height: 125px; background: url("../../../../assets/upload.png") no-repeat center center; background-size: contain; } .tip { font-size: 13px; color: rgba(0, 0, 0, 0.87); } .tinytip { font-size: 12px; color: #8e8f9e; } } </style>
注:以上代码用到了我们自己封装的组件库和自己封装的一些方法,请根据具体场景进行相关的修改。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。