Use the element component with FileReader to upload and display pictures, and the failures encountered in the process fail to pass variables in the onload callback function.

foreword

In the project, I hope that I can upload pictures, process them, and display the results in the preview box.
For this, I use the upload of the element component in the vue framework to realize it:
official example demo: Upload upload

In the process of using it, I need to convert the uploaded JPG format FILE file into a base64 string for the rest of the business logic processing, but in the process I encountered trouble (because I am not proficient in js), which bothered me for several hours.

I describe this fault as that FileReader.onloadthe bound callback function cannot thisbe used to refer to the global variable, and the assignment to the variable is invalid externally.

Because I was so impressed, I deliberately recorded it. This article will be divided into two parts, one part is the code that can be used in my entire process, and the other part is the thinking path and final solution when I encountered this failure.

Summary in advance : what is used inside and outside the functionthisrefer to different content, so the need forPass it in with a different variable name

function code

The actual function of this code is equivalent to uploading and previewing pictures, but in the pre-upload function, you can get the string format of the picture, which may be useful in some cases.

Control part:

<el-upload
	class="avatar-uploader"
	action=""
	:show-file-list="false"
	:on-success="handleAvatarSuccess"
	:before-upload="beforeAvatarUpload">
	<img v-if="imgsrc" :src="'data:image/jpeg;base64,' + imgsrc"  class="avatar">
	<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>

Variables section:

return {
    
    
	imgsrc:'',
}

Properties section:

<style scoped>
  .avatar-uploader .el-upload {
    
    
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader .el-upload:hover {
    
    
    border-color: #409EFF;
  }
  .avatar-uploader-icon {
    
    
    font-size: 28px;
    color: #8c939d;
    width: 240px;
    height: 240px;
    line-height: 240px;
    text-align: center;
  }
  .avatar {
    
    
    width: 240px;
    height: 240px;
    display: block;
  }
</style>

Function section:

handleAvatarSuccess(res, file) {
    
    
	//this.imageUrl = URL.createObjectURL(file.raw);
},
beforeAvatarUpload(file) {
    
    
	const isJPG = file.type === 'image/jpeg';
	const isLt10M = file.size / 1024 / 1024 < 10;

    if (!isJPG) {
    
    
    	this.$message.error('上传头像图片只能是 JPG 格式!');         
    }
    if (!isLt10M) {
    
    
        this.$message.error('上传头像图片大小不能超过 10MB!');
    }
    if(!(isJPG && isLt10M))
		return isJPG && isLt10M;

	//使用前应该判断一下FileReader是否可用,但我忘了
	let reader = new FileReader();
	
	let _this = this;
	reader.onload = function(e) {
    
                          //先绑定回调
		let base64Str = e.target.result;
		_this.imgsrc = base64Str;
	};
	reader.readAsDataURL (file);                      //再准备读取
	return isJPG && isLt10M;
},

Failure Exploration Record

The fault code was originally:

	reader.onload = function(e) {
    
                          //先绑定回调
		let base64Str = e.target.result;
		this.imgsrc = base64Str;
	};

Comparing the above code, you can see where I changed. The fault I encountered was that this.imgsrcthe assignment to was invalid, which made it impossible for me to preview the uploaded pictures.

The following is my exploration log:

Change the name of the quantity, add printing observation phenomenon

I first modified the variable name, on the one hand to reduce the influence of other factors on it, on the other hand to facilitate the restoration of the code environment, and then added the print:

      beforeAvatarUpload(file) {
    
    
        const isJPG = file.type === 'image/jpeg';
        const isLt2M = file.size / 1024 / 1024 < 2;

        if (!isJPG) {
    
    
          this.$message.error('上传头像图片只能是 JPG 格式!');
        }
        if (!isLt2M) {
    
    
          this.$message.error('上传头像图片大小不能超过 2MB!');
        }

        //this.imgsrc2 = "123";
        let reader = new FileReader();
        console.log("flag2.4-----"+this.imgsrc2);
        //this.imgsrc2 = "147";
        reader.onload = function(e) {
    
                          //先绑定回调
          let base64Str = e.target.result;
          console.log("flag2.2-----"+this.imgsrc2);
          this.imgsrc2 = "456";
          console.log("flag2.2-----"+this.imgsrc2);
        };

        reader.readAsDataURL (file);                      //再准备读取

        return isJPG && isLt2M;
      },

I declare this variable like this:

  export default {
    
    
    data() {
    
    
		return {
    
    
		        imgsrc2 : ''
		}
	}
  }

Print information:

flag2.4-----
flag2.2-----undefined
flag2.2-----456

flag2.4-----
flag2.2-----undefined
flag2.2-----456

analyze the phenomenon

The appearance of this paragraph shows the problem: flag2.2-----undefined

If the above function is executed twice, this problem should not occur (you can ensure that there is no assignment of a variable elsewhere)

In this regard, first of all, I review my understanding of the global variables of the Vue framework, which should be the attributes declared in the data part of the return attribute.

I suspect there is something wrong with my understanding of global variables, but I think that might not be the point.

I think there is nothing wrong with the way of declaration. When using it, use this.imgsrc2 to call it. In the .vue template file, the this keyword can access all objects mounted on Vue.prototype, so writing this is equivalent to writing Vue.prototype.

Under normal circumstances, it can be assigned, but after entering the function function (e), it cannot be assigned.

My guess is that this asynchronous function is probably not in the same time and space as the function that I normally run sequentially, so when I get the variable object, I actually get a mirror variable. Although it has the same name, it cannot pass the value to the outside.

I used watch, but it can be observed that the value modified inside the function is not noticeable outside.

watch: {
      imgsrc2: {
        handler(newOption, oldOption) {
          if(newOption)
            console.log("flag2.5-----"+newOption);
          else
            console.log("flag2.6-----"+oldOption);
        },
        immediate: true,
        deep: true,
      },
    }

The printing in the above function is not performed.

further analysis and resolution

I've already experimented with mangling the variable name, so the next step is to change another component of the variablethis

let _this = this;
 reader.onload = function(e) {                      //先绑定回调
          let base64Str = e.target.result;
          console.log("flag2.2-----"+_this.imgsrc2);
          _this.imgsrc2 = "456";
          console.log("flag2.2-----"+_this.imgsrc2);
        };

(From the printing point of view, the assignment is successful)

This solution is based on my guess that the time and space are different, because the inside of the function belongs to another function, so when using this for positioning, it does not coincide with the outside, so the asynchronous time is different, and the positioning space is different, which leads to the failure of value transmission, but now use an intermediate The variable transfers the this of the external environment to the interior based on the intermediate variable, so that the anchor point can be assigned. Troubleshooting.

epilogue

This fault took me about 4 hours, because I can't quite understand why the variable seems to describe the same, but the assignment is not the same. In the end, my guess is that the internal function refers to the external variable. mirror image. If there are experts who read this article and are familiar with js, please explain it when you have time, thank you.

(Accumulation of less becomes more, accumulation of less becomes more)

Guess you like

Origin blog.csdn.net/ex_xyz/article/details/118029014