VUE2+ElementUI list-type類型照片牆上傳爬坑記錄


1.說明

空間第一篇技術總結,給我的ElementUI圖片上傳。最近被安排使用ElementUI+VUE2來開發一個PC的應聘申請界面,在寫上傳多個圖片的效果時,遇到許多問題,在這里記錄一下。

2.問題總覽

2.1 通過自定義方法上傳圖片
2.2 JavaScript Array的對象屬性
2.3 this.$refs使用
2.4 上傳、刪除圖片數據集合數據問題
2.5 this[] 類似java的反射賦值
2.6 通過http-request自定義方法上傳圖片
2.7 獲取當前文件在數組中的下標
2.8 對象自定義方法
2.9 隱藏圖片上傳框
2.10 視圖更新$set和強制更新視圖this.$forceUpdate()頁面

3.最終實現代碼

<!--標簽實現-->
<div class="div-title-two" ><i class="i-btx" ></i>身份證正面照</div>
<div>
    <el-upload
      action=""
      class="upload-idCard"
      list-type="picture-card"
      :headers="{'Content-Type':'application/json'}"
      :http-request="function(val){ customPictureUpload('idCard',val,1) }"
      :file-list="idCardImageList"
      ref="imgRef"
      :on-remove="function(file ,raw){ handleRemovePic('idCard',file ,raw) }">
      <i class="el-icon-plus"></i>
    </el-upload>
</div>

//自定義上傳方法
customPictureUpload (name , obj ,limit) {
    //校驗圖片格式、size
    let flag = this.beforePictureUpload(obj.file);
    if(!flag) return;
    //因為有多個模塊上傳框,所以這兒寫成通過傳入類型動態判斷類型
    //動態拼接ClassName; 即 .upload-idCardImageList
    let className  = '.upload-'+name;
    //動態拼接數組名稱 即:idCardImageList
    let arrayName = name+"ImageList";
    //動態拼接ref引用 : idCardRef
    let refName  = name+"Ref"
    //獲取當前上傳文件數組里當前文件的下標序號
    let index = this.$refs[refName].uploadFiles.indexOf(this.$refs[refName].getFile(obj.file))
    //判斷圖片是否已到達上限limit
    var imgs = this.$refs[refName].uploadFiles.length;
    limit = limit -1 ;
    //如果達到上限,則隱藏上傳的框框
    if(imgs == limit){
        document.querySelector(className+" .el-upload--picture-card").style.display = 'none'
    }
    readerFile(obj.file).then(fileResult => {
        //調用上傳圖片方法
        uploadImg({
          data: {
            imgInfo: fileResult.base64,
            token: sessionStorage.getItem('hr_apply_token'),
            phone: this.ruleForm.phone
          }
        }).then(res=>{
            if (+res['responseCode'] === 0) {
                //給當前文件設置返回的res_path值
                this.$refs[refName].uploadFiles[index].res_path =res.path
                //判斷當前文件前面是否有還在上傳的文件,若有則等待
                while(index == this[arrayName].length){
                    this[arrayName]= this.$refs[refName].uploadFiles
                }
            } else if(+res['responseCode'] === 5555){
              this.$message({
                showClose: true,
                message: res['responseMsg'],
                type: 'error'
              });
              this.$router.replace('/login');
            } else{
              this.$message({
                showClose: true,
                message: res['responseMsg'],
                type: 'error'
              });
            document.querySelector(className+' .el-upload--picture-card').style.display = ''
            }
        })
    })
},
//刪除方法
handleRemovePic(name, file ,fileList) {
    //拼接calssName
    let className  = '.upload-'+name;
    //拼接數組名字
    let arrayName = name+'ImageList';
    //將刪除后的fileList賦給數組
    this[arrayName] = fileList
    document.querySelector(className+' .el-upload--picture-card').style.display = ''
},

4.經驗總結

4.1 通過自定義方法上傳圖片

ElementUI默認是通過action去調用圖片上傳,但是在實際使用中action在傳數據方面比較麻煩,所以這兒可以通過 :http-request來自定義一個方法來上傳圖片。

4.2 JavaScript Array的對象屬性

splice:splice在js中是用來對數組進行刪除、替換操作,具體實現:
刪除:
    index代表要刪除的數組的下標, num代表刪除的數量
    this.idCardImageList.splice(index,num)
替換:
    item*可以有多個,當item的值為null時,即可置空index下標的值
    this.idCardImageList.splice(index,num,item*)
every:用於遍歷數組中元素是否都符合條件,若存在不符合元素則直接返回,不繼續往下遍歷
let picFlag = this.idCardImageList.every( item => {
    if(item.res_path){
        return true;
    }else{
        return false;
    }
});
some: 與every正好相反,遍歷數組中元素是否符合條件,若存在則直接返回,不繼續往下遍歷
let picFlag = this.idCardImageList.some( item => {
    if(item.res_path){
        return true;
    }else{
        return false;
    }
});
forEach:遍歷數組中的所有數據,並且會遍歷遍歷完
this.idCardImageList.forEach(item => {
  item.validate((valid) => {
    if (!valid) {
      flagForm = false;
    };;
  })
});
indexOf: 獲取當前元素數組中的下標
this.idCardImageList.forEach(item => let index = this.idCardImageList.indexOf(item))
filter():過濾,即返回符合條件的所有元素數組
this.idCardImageList.filter(item => item.age >18 );
push:向數組的最后面插入一/多個元素,並返回新數組的長度
this.idCardImageList.push({age:18,idcard:'www.baidu.com'});
[].forEach.call():是一種快速的方法訪問forEach,並將空數組的this換成想要遍歷的list
這個方法的使用,拿到querySelectorAll時需要遍歷數組,具體看示例:
//將所有className為must的元素display樣式設置為 block
[].forEach.call(document.querySelectorAll(".must"), item => item.style.display="block" );    

4.3 this.$refs使用

首先說明下ref
ref:被用來給元素或子組件注冊引用信息。引用信息將會注冊在父組件的$refs對象上。如果在普通Dom元素上使用,引用指向的就是Dom元素,如果用在自組件上,就引用指向組件實例。

在業務處理中,我需要拿到ElementUI封裝的uploadFiles對象,所以通過this.$refs.imgRef.uploadFiles,就能拿到實例中uploadFiles對象的數據然后賦值給我的this.imgList 就拿到了上傳圖片的數組。

4.4 上傳、刪除圖片數據集合數據問題

在處理中會出現以下情況

情景一:
連續上傳兩張圖片,第一張大,第二張小
問題:
小圖上傳成功並且大圖消失,然后過了幾秒大圖出現

情景二:
上傳一張大圖,並且迅速刪除一個已上傳成功的圖
問題:
已上傳的圖和正在上傳的大圖會同時被刪掉,並且過了一會兒大圖又重新加載出來。

情景三:
上傳一張大圖,並且迅速刪除正在上傳的圖
問題:
正在上傳的大圖被刪掉,並且過了一會兒大圖又重新加載出來。
this.imgList.push(file) 引起的錯亂
以上三個錯誤問題都是由於對 imgList賦值引起的,以情景一為例。
首先一個前提,上傳圖片是異步的。
我的處理邏輯是:
1、調用自定義上傳圖片方法
2、后台返回上傳圖片路徑,進行this.imgList.push(file)
但是這樣處理有一個問題,如果按情景一走就會出現
3、小圖上傳完成push進imgList,接着刷新視圖大圖消失
4、大圖上傳完,大圖push進imgList,這時大圖才顯示
請求前就push?

出現問題后,猜想既然是因為異步問題引起,那么在請求之前就把數據push這種方法可行嗎,接着按此操作結果:push之后視圖樣式就直接顯示上傳完成,猜想不可行。

拿到父組件的fileList集合

既然這條路走不同,那么把push代碼注釋掉再嘗試,發現不會出現圖片錯亂的問題。於是猜有一個對象存了當前正在上傳和已上傳的圖片的數據,查看源碼發現有一個fileList對象,結合4.3 ref的使用,通過this.$ref.imgList.uploadFiles拿到完成圖片上傳后的FileList的文件和狀態,不需要每次上傳成功才push,可以直接把將當前的fileList集合賦給imgList。

push前判斷一下

賦值給項目后,發現情景一情況並沒有解決,於是再仔細分析發現:大圖的位置還是被小圖占了,因為不管如何處理肯定是小圖先返回,那么就給當前的fileList與我的imgList的長度做一個判斷,如果長度相等了代表前面沒有待上傳的圖片,那么就不會把他的坑給占了。

    //判斷當前文件前面是否有還在上傳的文件,若有則等待
    while(index == this[arrayName].length){
        this[arrayName]= this.$refs[refName].uploadFiles
    }

4.5 this[] 類似java的反射賦值

這個方法是類似於java的反射實現對元素賦值取值,例如:this.imgList = this["imgList"], 有了這個就可以動態的設置進來的方法參數了。

4.6 通過http-request自定義方法上傳圖片

在整個方法http-request的方法執行中,on-change、on-progress、on-success等方法都會無效掉。

4.7 獲取當前文件在數組中的下標

let index = this.imgList.indexOf(img);

4.8 方法處理中自定義方法

這個的處理是在array數組上增加刪除的方法
Array.prototype.add = (item =>{
    let index = this.indexOf(item)     
    this.splice(index,1)
    return this;
})

4.9 隱藏圖片上傳框

有時圖片上傳會有個數限制,在達到上限后,上傳框框就應該隱藏掉,目前用的是最笨的辦法

document.querySelector(className+'.el-upload--picture-card').style.display = 'none'

有時間得去找找有沒有vue的屬性可以直接隱藏的。    

4.10 視圖更新$set和強制更新視圖this.$forceUpdate()頁面

this.$forceUpdate():強制更新視圖

當自己設置的元素因為層次太深而無法更新時,可以通過調用this.$forceUpdate()來實現強制視圖更新

$set:如果對象是響應式的,確保屬性被創建后也是響應式的,同時觸發視圖更新。

this.$set(target, key, value) 等同於Vue.set( target, key, value )

{Object | Array} target  對象/數組
{string | number} key  設置的元素
{any} value  設置的值


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM