vue实现拖拽或点击上传图片

本文实例为大家分享了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>

注:以上代码用到了我们自己封装的组件库和自己封装的一些方法,请根据具体场景进行相关的修改。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 vue实现拖拽或点击上传图片 的全部内容, 来源链接: utcz.com/p/239684.html

回到顶部