1. 程式人生 > 程式設計 >vue實現拖拽或點選上傳圖片

vue實現拖拽或點選上傳圖片

本文例項為大家分享了實現拖拽或點選上傳圖片的具體程式碼,供大家參考,具體內容如下

一、預覽圖

vue實現拖拽或點選上傳圖片

vue實現拖拽或點選上傳圖片

二、實現

點選上傳思路:將input的type設定為“file”型別即可上傳檔案。隱藏該input框,同時點選按鈕時,調取該input的點選上傳功能。剩下的就是優化頁面了。

拖拽上傳思路:通過給拖拽框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(); } },//監聽子元件的值 fileList(data) { this.fileInfo = data[0]; this.formData.name = this.fileInfo.title; const uploadBg = this.$refs.uploadBg; //改變背景圖片 uploadBg.style.backgroundImage = `url(${this.fileInfo.uhjqIxrl})`; },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); hjqIx 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; bawww.cppcns.comckground: url("../../../../assets/upload.png") no-repeat center center; background-size: contain; } .tip { font-size: 13px; color: rgba(0,0.87); } .tinyTip { font-size: 12px; color: #8e8f9e; } } </style>

注:以上程式碼用到了我們自己封裝的元件庫和自己封裝的一些方法,請根據具體場景進行相關的修改。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。