1、正常上傳
<template> <div class="upload-wrapper"> <div v-if="!imgUrl" class="noneData"> <div @click="openLocals"> <img src="./imgs/icon_jh.png" alt=""> <div>上傳圖片</div> </div> <form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;"> <input ref="pathClear" type="file" accept="image/*" :name="fileName" @change="fileChanged"/> </form> </div> <div v-else class="havaData"> <img :src="imgUrl" alt="" @click="actImg"> </div> </div> </template> <script> import $ from 'jquery'; import { Indicator, Toast } from 'mint-ui'; import { webPostObject } from './ossUpload/index.js'; export default { data() { return { }; }, props: { // file控件名稱 fileName: { type: String, required: true }, // 圖片地址 imgUrl: { type: String, default: '', required: true }, }, methods: { // 點擊圖片 actImg() { console.log('點擊圖片'); }, // 刪除圖片 removePackage() { let _self = this; _self.$emit('removeImg'); }, // 上傳圖片 openLocals() { $(`input[type='file'][name='${this.fileName}']`).click(); }, fileChanged() { this.uploadImg(); }, uploadImg() { let _self = this; let fileElement = $(`input[type='file'][name='${_self.fileName}']`); let filename = fileElement.val(); let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase(); if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') { Toast({ message: '僅支持.jpg、.png、.jpeg、.bmp的圖片格式', position: 'bottom', duration: 2000 }); return false; } let file = fileElement[0].files[0]; let imgSize = Math.ceil(file.size / 1024 / 1024); if (imgSize > 20) { Toast({ message: '文件不能大於20MB,重新選擇文件', position: 'bottom', duration: 2000 }); _self.$refs.pathClear.value = ''; return false; } Indicator.open('圖片正在上傳中...'); // 服務器上傳 // let formdata1 = new FormData(); // formdata1.append('file', file, file.name); // let config = { // headers: { 'Content-Type': 'multipart/form-data' } // }; // axios.post(`${process.env.UPLOAD_HOST}`, formdata1, config).then((res) => { // console.log(res); // let data = res.data; // Indicator.close(); // if (data) { // _self.$emit('uploadSuccess', data[0]); // } // }).catch(() => { // Indicator.close(); // Toast({ // message: '圖片上傳失敗', // position: 'bottom', // duration: 2000 // }); // }); // oss web直傳 webPostObject(file, file.name).then(data => { console.log('oss web直傳', data); Indicator.close(); _self.$emit('uploadSuccess', data); }).catch(() => { Indicator.close(); Toast({ message: '圖片上傳失敗', position: 'bottom', duration: 2000 }); }); }, }, }; </script> <style lang="less" scoped> .upload-wrapper{ height: 100%; } .noneData,.havaData{ position: relative; height: 100%; } .noneData{ background-color: #eeeeee; color: #999999; font-size: 12px; text-align: center; padding-top: 15px; img{ width: 26px; height: 26px; } } .havaData{ img{ width: 100%; height: 100%; } } </style>
2、壓縮圖片上傳
<template> <div class="upload-wrapper"> <div v-if="!imgUrl" class="noneData"> <div class="uploadImg" @click="openLocals"> </div> <form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;"> <input ref="pathClear" type="file" accept="image/*" :name="fileName" @change="fileChanged"/> </form> </div> <div v-else class="havaData"> <div class="havaDataimg"> <div class="img_wap"> <img :src="imgUrl" alt="" @click.stop="bigPicture"> </div> <div class="remove" @click.stop="removePackage"></div> </div> </div> <div class="maxImg" @click="minImg" v-if="maxImg"> <img :src="imgUrl" alt=""> </div> </div> </template> <script> import $ from 'jquery'; import { Indicator, Toast } from 'mint-ui'; import axios from 'axios'; export default { data() { return { maxImg: false, xhr: null, ot: null, oloaded: null, }; }, props: { // file控件名稱 fileName: { type: String, required: true }, // 圖片地址 imgUrl: { type: String, default: '', required: true }, // 圖片地址 isMaxIMg: { type: String, default: '', required: true }, }, methods: { // 查看大圖 bigPicture() { console.log(this.isMaxIMg); if (this.isMaxIMg === '0') { return false; } this.maxImg = true; }, // 恢復小圖 minImg() { this.maxImg = false; }, // 刪除圖片 removePackage() { let _self = this; _self.$emit('removeImg'); }, // 上傳圖片 openLocals() { $(`input[type='file'][name='${this.fileName}']`).click(); }, fileChanged() { this.UpladFile(); }, // 三個參數 // file:一個是文件(類型是圖片格式), // w:一個是文件壓縮的后寬度,寬度越小,字節越小 // objDiv:一個是容器或者回調函數 // photoCompress() photoCompress(file, w, objDiv) { let that = this; let ready = new FileReader(); // 開始讀取指定的Blob對象或File對象中的內容. 當讀取操作完成時,readyState屬性的值會成為DONE,如果設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容. ready.readAsDataURL(file); ready.onload = function() { let re = this.result; that.canvasDataURL(re, w, objDiv); }; }, canvasDataURL(path, obj, callback) { let img = new Image(); img.src = path; img.onload = function() { let that = this; // 默認按比例壓縮 let w = that.width; let h = that.height; let scale = w / h; w = obj.width || w; h = obj.height || (w / scale); let quality = 0.7; // 默認圖片質量為0.7 // 生成canvas let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); // 創建屬性節點 let anw = document.createAttribute('width'); anw.nodeValue = w; let anh = document.createAttribute('height'); anh.nodeValue = h; canvas.setAttributeNode(anw); canvas.setAttributeNode(anh); ctx.drawImage(that, 0, 0, w, h); // 圖像質量 if (obj.quality && obj.quality <= 1 && obj.quality > 0) { quality = obj.quality; } // quality值越小,所繪制出的圖像越模糊 let base64 = canvas.toDataURL('image/jpeg', quality); // 回調函數返回base64的值 callback(base64); }; }, /** * 將以base64的圖片url數據轉換為Blob * @param urlData * 用url方式表示的base64圖片數據 */ convertBase64UrlToBlob(urlData) { let arr = urlData.split(','); let mime = arr[0].match(/:(.*?);/)[1]; let bstr = atob(arr[1]); let n = bstr.length; let u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, // 上傳文件方法 UpladFile() { let that = this; let fileElement = $(`input[type='file'][name='${that.fileName}']`); let filename = fileElement.val(); let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase(); if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') { Toast({ message: '僅支持.jpg、.png、.jpeg、.bmp的圖片格式', position: 'bottom', duration: 2000 }); return false; } let fileObj = fileElement[0].files[0]; let form = new FormData(); // FormData 對象 if (fileObj.size / 1024 > 1025) { // 大於1M,進行壓縮上傳 that.photoCompress(fileObj, { quality: 0.2 }, function(base64Codes) { let bl = that.convertBase64UrlToBlob(base64Codes); form.append('file', bl, 'file_' + Date.parse(new Date()) + '.jpg'); // 文件對象 let config = { headers: { 'Content-Type': 'multipart/form-data' } }; Indicator.open('圖片正在上傳中...'); axios.post(`${process.env.UPLOAD_HOST}`, form, config).then((res) => { console.log(res); let data = res.data; Indicator.close(); if (data) { that.$emit('uploadSuccess', data[0]); } }).catch(() => { Indicator.close(); Toast({ message: '圖片過大上傳失敗', position: 'bottom', duration: 2000 }); }); }); } else { // 小於等於1M 原圖上傳 Indicator.open('圖片正在上傳中...'); form.append('file', fileObj); // 文件對象 axios.post(`${process.env.UPLOAD_HOST}`, form).then((res) => { console.log(res); let data = res.data; Indicator.close(); if (data) { that.$emit('uploadSuccess', data[0]); } }).catch(() => { Indicator.close(); Toast({ message: '圖片過大上傳失敗', position: 'bottom', duration: 2000 }); }); } }, } }; </script> <style lang="less" scoped> .upload-wrapper{ position: relative; height: 172px; } .noneData,.havaData{ height: 100%; padding: 15px 16vw; position: relative; display: flex; justify-content: center; align-items: center; .uploadImg{ width: 102px; height: 102px; background-size: 100% 100%; background-image: url(./imgs/xh_pfgy_upload.png); } .havaDataimg{ position: relative; width: 100%; height: 100%; border: 1px solid #eeeeec; overflow: hidden; .img_wap{ width: 100%; height: 0px; padding-bottom: 56%; position: relative; img{ width: 100%; position: absolute; top: -30%; left: 0px; } } .remove{ position: absolute; top: 0; right: 0; width: 18px; height: 18px; background: url('./imgs/icon_close.png') rgba(255, 255, 255, 0.8) center center no-repeat; background-size: cover; border-radius: 50%; } } } // 大圖效果 .maxImg{ position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px; overflow: auto; background-color:rgba(0, 0, 0, 0.5); z-index: 100; padding: 20px; display: flex; justify-content: center; align-items: center; img{ max-width: 100%; max-height: 100%; } } </style>
3、轉為base64上傳
<template> <div> <div style="padding:20px;"> <!-- <div class="show"> <div class="picture" :style="'backgroundImage:url('+headerImage+')'"></div> </div> --> <div class="havaDataimg"> <div class="img_wap"> <img :src="headerImage" alt=""> </div> <div class="remove"></div> </div> <div style="margin-top:20px;"> <input type="file" id="upload" accept="image/*" @change="upload"> <label for="upload"></label> </div> </div> </div> </template> <script> import Exif from 'exif-js'; import { Toast } from 'mint-ui'; export default { data() { return { headerImage: '', picValue: '' }; }, methods: { upload(e) { let files = e.target.files || e.dataTransfer.files; if (!files.length) return; this.picValue = files[0]; let filename = this.picValue.name; let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase(); if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') { Toast({ message: '僅支持.jpg、.png、.jpeg、.bmp的圖片格式', position: 'bottom', duration: 2000 }); return false; } this.imgPreview(this.picValue); }, imgPreview(file) { let self = this; let Orientation; // 去獲取拍照時的信息,解決拍出來的照片旋轉問題 Exif.getData(file, function() { Orientation = Exif.getTag(this, 'Orientation'); }); // 看支持不支持FileReader if (!file || !window.FileReader) return; if (/^image/.test(file.type)) { // 創建一個reader let reader = new FileReader(); // 將圖片2將轉成 base64 格式 reader.readAsDataURL(file); // 讀取成功后的回調 reader.onloadend = function () { let result = this.result; let img = new Image(); img.src = result; // 判斷圖片是否大於100K,是就直接上傳,反之壓縮圖片 if (this.result.length <= (100 * 1024)) { self.headerImage = this.result; self.postImg(); } else { img.onload = function () { let data = self.compress(img, Orientation); self.headerImage = data; self.postImg(); }; } }; } }, postImg() { // 這里寫接口 }, rotateImg(img, direction, canvas) { // 最小與最大旋轉方向,圖片旋轉4次后回到原方向 const min_step = 0; const max_step = 3; if (img == null) return; // img的高度和寬度不能在img元素隱藏后獲取,否則會出錯 let height = img.height; let width = img.width; let step = 2; if (step == null) { step = min_step; } if (direction === 'right') { step++; // 旋轉到原位置,即超過最大值 step > max_step && (step = min_step); } else { step--; step < min_step && (step = max_step); } // 旋轉角度以弧度值為參數 let degree = step * 90 * Math.PI / 180; let ctx = canvas.getContext('2d'); switch (step) { case 0: canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0); break; case 1: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, 0, -height); break; case 2: canvas.width = width; canvas.height = height; ctx.rotate(degree); ctx.drawImage(img, -width, -height); break; case 3: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, -width, 0); break; } }, compress(img, Orientation) { let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); // 瓦片canvas let tCanvas = document.createElement('canvas'); let tctx = tCanvas.getContext('2d'); let initSize = img.src.length; let width = img.width; let height = img.height; // 如果圖片大於四百萬像素,計算壓縮比並將大小壓至400萬以下 let ratio; if ((ratio = width * height / 4000000) > 1) { console.log('大於400萬像素'); ratio = Math.sqrt(ratio); width /= ratio; height /= ratio; } else { ratio = 1; } canvas.width = width; canvas.height = height; // 鋪底色 ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 如果圖片像素大於100萬則使用瓦片繪制 let count; if ((count = width * height / 1000000) > 1) { console.log('超過100W像素'); count = ~~(Math.sqrt(count) + 1); // 計算要分成多少塊瓦片 // 計算每塊瓦片的寬和高 let nw = ~~(width / count); let nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (let i = 0; i < count; i++) { for (let j = 0; j < count; j++) { tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, width, height); } // 修復ios上傳圖片的時候 被旋轉的問題 if (Orientation !== '' && Orientation !== 1) { switch (Orientation) { case 6:// 需要順時針(向左)90度旋轉 this.rotateImg(img, 'left', canvas); break; case 8:// 需要逆時針(向右)90度旋轉 this.rotateImg(img, 'right', canvas); break; case 3:// 需要180度旋轉 this.rotateImg(img, 'right', canvas);// 轉兩次 this.rotateImg(img, 'right', canvas); break; } } // 進行最小壓縮 let ndata = canvas.toDataURL('image/jpeg', 0.7); console.log('壓縮前:' + initSize); console.log('壓縮后:' + ndata.length); console.log('壓縮率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%'); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; }, } }; </script> <style lang="less" scoped> *{ margin: 0; padding: 0; } /* .show { width: 100px; height: 100px; overflow: hidden; position: relative; border-radius: 50%; border: 1px solid #d5d5d5; } .picture { width: 100%; height: 100%; overflow: hidden; background-position: center center; background-repeat: no-repeat; background-size: cover; } */ .havaDataimg{ position: relative; width: 100%; height: 100%; border: 1px solid #eeeeec; overflow: hidden; .img_wap{ width: 100%; height: 0px; position: relative; padding-bottom: 56.25%; img{ width: 100%; position: absolute; top: -30%; left: 0px; } } } </style>
4引入組件使用
import uploadImg from '@/components/upload/prescriptionUploadImg'; components: { 'uploadImg': uploadImg, }, <uploadImg :imgUrl="pic_url" :fileName="'Image'" @uploadSuccess="addImgUrl" @removeImg="removeImgUrl"></uploadImg>