在前端專案中,附件上傳是很常用的功能,幾乎所有的app相關專案中都會使用到,一般在選擇使用某個前端UI框架時,可以查詢其內封裝好的圖片上傳元件,但某些情況下可能並不適用於自身的專案需求,本文中實現的附件上傳區域支援超多型別附件分型別上傳,並且可根據特定條件具體展示某些型別的附件上傳,本文中是直接摘自具體的頁面,後面會抽時間單獨封裝出來一個附件上傳的元件。
一、Vue頁面內附件展示區域程式碼
1 <div class="retuinfo"> 2 <div class="theadInfo-headline"> 3 <span></span> 4 {{FileDivName}} 5 </div> 6 <Collapse v-model="defaultCollapse"> 7 <Panel v-for="(item,pngIndex) in pngFileArray" v-bind:key="pngIndex" :name="item.num" v-show="item.isshow"> 8 {{item.name}} 9 <div class="obsfilesdiv" slot="content"> 10 <div v-for="(obs,index) in item.files" v-bind:key="index" class="obsfileslist"> 11 <input ref="fileImg" type="file" accept="image/*;capture=camera" style="display: none;" 12 @change="setObsFile(item.num,1,obs.FileType,obs.Num,obs.Code)"> 13 <label style="color:#6d7180; font-size: 20px;">{{obs.FileType}}<span style="color:red;" 14 v-show="obs.FileType!='其他'">*</span></label> 15 <ul class="obsfilesul"> 16 <li v-for="(objitem,objindex) in obs.FileObj" v-bind:key="objindex"> 17 <img :src="objitem.imgurl ? objitem.imgurl : fileUrl" 18 @click="showObsFiles(obs.FileFlag,objitem.imgurl)" /> 19 <img src="../../../img/other/wrong.png" v-show="objitem.IsCanEdit" class="wrong_class" 20 @click="deleteObsFlie(item.num,index,objindex,objitem.imgid,objitem.imgurl)" /> 21 </li> 22 <li style="border: 4px solid #f3f3f3;" @click="PlusClick(obs.FileType,obs.FileFlag,obs.Num)"> 23 <img src="../../../img/icon-adds.png" alt="" /> 24 </li> 25 <div style="clear:both;"></div> 26 </ul> 27 </div> 28 </div> 29 </Panel> 30 </Collapse> 31 </div> 32 <div class="modal" v-show="viewBigImg"> 33 <div class="img-view-modal" style="text-align: right;"> 34 <img :src="viewImgURL" style="width: 100%;" @click="hideShow(0)"> 35 <Icon type="md-close" style="margin-right: 20px;" size='20' @click="hideShow(0)" /> 36 </div> 37 </div> 38 </div>
Vue專案引入了以下UI框架:(若想拿來即用 需要先在main.js中引入)
IView、MintUI、Vant 此段程式碼只要確保引入IView即可正常使用
二、資料繫結設計
具體的不詳細展開說,陣列與通過屬性控制,很好理解。
pngFileArray: [{ num: '0', name: '整車', isshow: localStorage.getItem("RoleName").indexOf('銘牌質檢員') != -1 ? true : false, files: [ //FileFlag://1:圖片;2:視訊 3.其他 { FileType: '整車銘牌圖片', Code: '201', Num: 0, FileFlag: 1, FileObj: [], IsNoFile: true }, { FileType: '車架VIN圖片', Code: '207', Num: 1, FileFlag: 1, FileObj: [], IsNoFile: true }, { FileType: '終端圖片', Code: '301', Num: 2, FileFlag: 1, FileObj: [], IsNoFile: true } ] }, { num: '1', name: '里程', isshow: localStorage.getItem("RoleName").indexOf('客戶經理') != -1 ? true : false, files: [{ FileType: '里程錶照片', Code: '701', Num: 3, FileFlag: 1, FileObj: [], IsNoFile: true } ] } ],
三、繫結的方法
1.圖片載入方法:
1 //獲取圖片列表 2 getImageList() { 3 this.$indicator.open({ 4 text: '圖片載入中...', 5 spinnerType: 'snake' 6 }); 7 let _this = this; 8 let downRequest ={ 9 'crm_vin': this.parms.crm_vin, 10 'crm_vehiclenumber': this.parms.crm_vehiclenumber 11 }; 12 let imgListParams = { 13 "ImageDownRequest": JSON.stringify(downRequest), 14 "username": localStorage.getItem("usernameone"), 15 "password": localStorage.getItem("password") 16 }; 17 console.log("獲取圖片列表引數:", imgListParams); 18 _this.$ajax.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded;'; //配置請求頭 19 this.$ajax.post(this.imageListUrl, this.$qs.stringify(imgListParams)).then(resdata => { 20 _this.$indicator.close(); 21 console.log("獲取到的圖片列表資料:", resdata); 22 let data = resdata.data; 23 console.log("轉換後的圖片列表資料:", data); 24 if (resdata.status != 200) { 25 _this.$toast({ 26 message: '獲取圖片列表失敗!', 27 duration: 3000 28 }); 29 return; 30 } 31 //先清空原有的圖片列表 32 _this.pngFileArray.forEach((rr,index,array) =>{ 33 for(var file=0;file<rr.files.length;file++){ 34 _this.pngFileArray[index].files[file].FileObj = []; 35 _this.pngFileArray[index].files[file].IsNoFile = true; 36 } 37 }); 38 //將圖片列表寫入頁面各圖片分類區域 39 for(var i=0;i<data.length;i++){ 40 _this.pngFileArray.forEach((rr,index,array) =>{ 41 for(var file=0;file<rr.files.length;file++){ 42 if(data[i].crm_imagetypeno==rr.files[file].Code){ 43 let putparm = { 44 "IsCanEdit":false, 45 "imgid": data[i].crm_careimageId, 46 "imgurl": data[i].ImageUrl 47 }; 48 _this.pngFileArray[index].files[file].FileObj.push(putparm); 49 _this.pngFileArray[index].files[file].IsNoFile = false; 50 } 51 } 52 }); 53 54 } 55 }).catch(function(error) { 56 _this.$indicator.close(); 57 _this.$toast({ 58 message: error, 59 duration: 3000 60 }); 61 }); 62 },
2.圖片展示方法
showObsFiles(type, url) { //展示圖片或視訊 console.log("展示附件:" + type); if (type == 1) { //圖片 this.viewBigImg = true; this.viewImgURL = url; } else { //檔案 this.$messagebox.alert("不支援檢視檔案,請到PC端操作!", "提示"); return; } },
3.上傳圖片相關方法
(最開始設計的是支援圖片、視訊和其他型別檔案等上傳,專案中已實現,本文中不做擴充)
1 PlusClick(type, flag, num) { 2 console.log("當前附件型別:" + type); 3 console.log("當前附件序號:" + num); 4 this.currentFileType = type; 5 if (flag == 1) { // 圖片上傳 6 this.$refs.fileImg[num].dispatchEvent(new MouseEvent('click')); 7 } else if (flag == 2) { // 視訊上傳 8 this.$refs.fileVideo[num].dispatchEvent(new MouseEvent('click')); 9 } else { // 其他型別檔案 10 this.$refs.filElem[num].dispatchEvent(new MouseEvent('click')); 11 } 12 }, 13 setObsFile(classify, type, obsFileType, num, code) { //儲存圖片到crm中 14 var _this = this; 15 var inputFile; //檔案流 16 console.log("圖片大分類:" + classify + " " + obsFileType + " " + num) + " 圖片編碼:" + code; 17 if (type == 1) { 18 inputFile = this.$refs.fileImg[num].files[0]; 19 this.$refs.fileImg[num].value = ''; 20 } 21 var fileName = inputFile.name; 22 if (!inputFile) { 23 return; 24 } 25 if (inputFile.type == 'image/jpg' || inputFile.type == 'image/jpeg' || inputFile.type == 'image/png' || 26 inputFile.type == 27 'image/gif') {} else { 28 this.$messagebox.alert("請上傳圖片", "提示"); 29 return; 30 } 31 _this.$indicator.open({ 32 text: '檔案上傳中,請稍候...', 33 spinnerType: 'snake' 34 }); 35 //圖片壓縮與轉換成base64檔案流 36 var reader = new FileReader(); 37 reader.readAsDataURL(inputFile); 38 reader.onloadend = function(e) { 39 let result = this.result; 40 console.log('********未壓縮前的圖片大小******** :' + result.length / 1024) 41 _this.pulic.dealImage(result, {}, function(base64) { 42 console.log('********壓縮後的圖片大小******** :' + base64.length / 1024) 43 _this.putObsFile(classify, fileName, base64, obsFileType, code); 44 }); 45 //reader.result.substring(this.result.indexOf(',')+1); 46 // 'data:image/png;base64,'+reader.result 47 } 48 }, 49 putObsFile(classify, fileName, base64, obsFileType, code) { //抽出公共上傳圖片檔案方法 50 var _this = this; 51 let usernameone = this.$Base64.encode("administrator"); 52 let password = this.$Base64.encode("pass@word1"); 53 let parmsImages = { 54 crm_newenergyid: localStorage.getItem("crm_newenergyid"), 55 vin: _this.parms.crm_vin, 56 crm_vehiclenumber: _this.parms.crm_vehiclenumber, 57 CareType: code, 58 CreateBy: localStorage.getItem("SystemUserId"), 59 ImageStr: base64.split(",")[1], 60 username: usernameone, 61 password: password 62 } 63 let parms = { 64 ImageMessage: JSON.stringify(parmsImages) 65 } 66 console.log(JSON.stringify(parmsImages)); 67 console.log(JSON.stringify(parms)); 68 _this.$ajax.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded;'; //配置請求頭 69 _this.$ajax.post(_this.imageSaveUrl, _this.$qs.stringify(parms)) 70 .then(resdata => { 71 _this.$indicator.close(); 72 console.log("介面響應資料:", resdata); 73 let data = resdata.data; 74 console.log("轉換後的響應資料:", data); 75 if (resdata.status != 200) { 76 _this.$toast({ 77 message: '儲存失敗!介面呼叫異常', 78 duration: 3000 79 }); 80 return; 81 } 82 //將上傳成功後的圖片url回寫到頁面的圖片分類url中 83 console.log("當前分類下的所有圖片型別:" + JSON.stringify(_this.pngFileArray[parseInt(classify)].files)); 84 for (var i = 0; i < _this.pngFileArray[parseInt(classify)].files.length; i++) { //遍歷當前分類下的圖片型別陣列 並賦值後臺返回的資料 85 if (obsFileType == _this.pngFileArray[parseInt(classify)].files[i].FileType) { 86 //設定圖片檔案路徑等 putparm 87 let putparm = { 88 "IsCanEdit":true, 89 "imgid": data.crm_careimageId, 90 "imgurl": data.ImageUrl 91 }; 92 _this.pngFileArray[parseInt(classify)].files[i].FileObj.push(putparm); 93 _this.pngFileArray[parseInt(classify)].files[i].IsNoFile = false; 94 } 95 } 96 _this.$messagebox.alert("附件上傳成功", "提示"); 97 }).catch(err => { 98 console.log(JSON.stringify(err)); 99 _this.$toast({ 100 message: '上傳失敗', 101 duration: 1500 102 }); 103 _this.$indicator.close(); 104 }); 105 },
4.刪除圖片方法
(本文中是隻有未提交的圖片可刪除,若已提交過的圖片即頁面初始載入獲取到的圖片不可以刪除)
1 deleteObsFlie(classify,num,index,id,url) { //刪除附件 2 var _this = this; 3 this.$messagebox.confirm('確定刪除該圖片嗎?', "確認").then(action => { 4 var del_param = { 5 "id": id, 6 "url": url 7 }; 8 _this.$indicator.open({ 9 text: '刪除圖片中,請稍候...', 10 spinnerType: 'snake' 11 }); 12 _this.$ajax.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded;'; //配置請求頭 13 _this.PromiseCall(_this.DelImgFilesURL, _this.$qs.stringify(del_param)) 14 .then(data => { 15 _this.$indicator.close(); 16 console.log(JSON.stringify(data)); 17 if (data.status != 200) { 18 _this.$messagebox.alert("刪除圖片失敗", "提示"); 19 return; 20 } 21 _this.pngFileArray[parseInt(classify)].files[num].FileObj.splice(index, 1); 22 _this.$toast({ 23 message: '刪除圖片成功', 24 duration: 1500 25 }); 26 }).catch(err => { 27 _this.doCatch(err); 28 _this.$toast({ 29 message: '刪除圖片失敗'+err, 30 duration: 1500 31 }); 32 _this.$indicator.close(); 33 }); 34 }); 35 },
四、CSS樣式
.retuinfo { width: 96%; height: auto; margin-top: 20px; margin-left: 2%; background-color: #F5F7FA; border-radius: 15px; } .theadInfo-headline { width: 100%; height: 80px; background: #F3F3F3; display: flex; padding-left: 30px; align-items: center; font-size: 28px; color: #666666; border-radius: 15px; } .theadInfo-headline span { width: 6px; height: 32px; background: #5576AB; border-radius: 3px; margin-right: 10px; } .ivu-collapse-header { height: 40px; align-items: center; display: flex; } .obsfilesdiv { width: 100%; height: auto; margin-top: .5rem; margin-bottom: 50px; } .obsfileslist { width: 100%; height: auto; padding: 0.5rem 0.5rem; background: #fff; } .obsfilesul { width: 100%; height: auto; padding-bottom: 8px; } .obsfilesul li { width: 120px; height: 120px; float: left; margin-top: .3rem; overflow: hidden; margin-right: .3rem; border: none; } .obsfilesul li img { width: 100%; height: 100%; } .imglist { width: 100%; margin-top: .5rem; margin-bottom: 6rem; } .modal { background-color: #A9A9A9; position: fixed; z-index: 99; left: 0; top: 0; width: 100%; height: 100%; padding-top: 4rem; /*opacity: 0.5;*/ align-items: center; /*定義body的元素垂直居中*/ justify-content: center; /*定義body的裡的元素水平居中*/ } .modal img { animation-name: zoom; animation-duration: 0.6s; display: block; padding: 10px; margin: auto; max-width: 100%; max-height: 100%; box-shadow: 0 2px 6px rgb(0, 0, 0, 0), 0 10px 20px rgb(0, 0, 0, 0); border-radius: 12px; border: 1px solid white; position: absolute; top: 50%; transform: translateY(-50%); } .showname { width: 100px; height: 60px; position: relative; top: -4.5rem; white-space: normal; word-break: break-all; word-wrap: break-word; } .wrong_class { width: 30% !important; height: 30% !important; position: relative; top: -3.8rem; left: 2.6rem; } .wrongs_class { width: 4% !important; height: 4% !important; position: relative; /*top: -5.2em;*/ left: 0.5rem; }
最後附上實際效果圖: