angular 上传base64格式的图片

前面写的一些项目直接使用angular+ant.design就直接上传图片,使用的是ant的默认上传的组件,即提供url,然后上传的时候直接将二进制文件上传到服务器,然后服务器通过文件流的形式去接受,然后做其他的操作,上传好后返回文件的url,然后我们前端继续我们的操作。这个过程是很省心的,我们只需要提供一个上传url,然后做些上传限制,最后接收返回值。但是假如我们需要上传的是base64之后的数据,怎么办?

我们需要做的事:

  1. 接收图片文件(使用ant.design的自定义上传)
  2. 将图片文件转换为base64
  3. 将base64的图片为参数传递给接口
  4. 获得接口的返回值,并显示到前端页面

接收上传图片

使用ant.design的自定义上传模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<nz-upload
class="avatar-uploader"
nzName="avatar"
nzListType="picture-card"
[nzBeforeUpload]="beforeUpload"
[nzCustomRequest]="handleUpload"
[nzShowUploadList]="false"
>
<ng-container *ngIf="!cover">
<i class="upload-icon" nz-icon [nzType]="loading ? 'loading' : 'plus'"></i>
<div class="ant-upload-text">Upload</div>
</ng-container>
<img *ngIf="cover" [src]="cover" class="avatar" />
</nz-upload>

上面的beforUpload用来限制上传的类型以及大小,[nzCustomRequest]="handleUpload"里面的handleUpload才是上传图片的方法。

beforeUpload不用多说,ant.design的文档里面有清楚的示例,我们主要来看handleUpload方法,官网上的描述:

nzCustomRequest 通过覆盖默认的上传行为,可以自定义自己的上传实现;注意:务必使用 => 定义处理方法。 (item) => Subscription

该方法需要始终返回一个Subscription对象,nz-upload会在适当时机自动取消订阅。那么我们可以先定义一个函数的壳:

1
2
3
4
5
handleUpload = (item: UploadXHRArgs): Subscription => {
const subject = new Subject();
return subject.subscribe(res => {
item.onSuccess({}, item.file, event);
});

我们在函数里面创建了一个可订阅对象Subject,然后返回了这个可订阅对象的Subscription对象。我们只需要在特定的地方发出值:subject.next(value),就可以了。

我们可以在这个方法的item.file里取得当前上传的图片文件。所以我们第一步算是完成了。

转换图片为base64格式

如何将用户上传的图片转换为base64格式?这就需要FileRender了。

FileRender对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容。使用FileBlob对象指定要读取的文件或数据。

— MDN web docs FileRender

我们可以使用FileRender来加载用户选择上传的图片,然后进行我们需要的处理。

我们先实现一个读取图片文件的方法,由于读取文件是异步操作,所以我们使用返回Observable的方式,当读取成功,并获得base64编码的字符串后就返回Observable通知上层调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
read(file: File): Observable<string> {
return Observable.create(observer => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
// reader.result 为读取成功的base64编码的字符串。
observer.next(reader.result);
observer.complete();
};
});
}
do(file: any): Observable<string> {
return this.read(file as File);
}

然后在我们的handleUpload方法中调用:

1
2
3
4
5
6
7
8
9
10
11
handleUpload = (item: UploadXHRArgs) => {
const subject = new Subject();
this.do(item.file).subscribe(res => {
this.imgSrc = res;
subject.next();
subject.complete();
});
return subject.subscribe(res => {
item.onSuccess({}, item.file, event);
});
};

这里imgSrc的作用是在html中绑定一个img元素,当读取并转化成功后,就显示这个图片:

1
<img [src]="imgSrc" />

将base64的图片为参数传递给接口

我们已经获得到base64的图片的参数了,只需要传递给接口就可以了,接口正常调用。不过需要注意的是,采用formData形式传递参数的时候需要对参数进行urlencode,要不然服务器就乱套了。

正常调用接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
handleUpload = (item: UploadXHRArgs) => {
const subject = new Subject();
this.do(item.file).subscribe(img => {
this.http.post('http://www.baidu.com', {img}).subscribe((res: {code: number}) => {
subject.next('success');
subject.complete();
if (res.code === 0) {
}
}, err => {
subject.next('error');
subject.complete();
});
});
return subject.subscribe(res => {
if (res === 'success') {
item.onSuccess({}, item.file, event);
} else {
item.onError('err', item.file);
}

});
};

获得接口的返回值,并显示到前端页面

从上面接口中获得返回值即可,然后显示到页面上


刚开始做的时候以为一定要通过canvas才可以转换,原来想多了,直接通过FileRender进行加载,然后通过FileRender.readAsDataURL(file)就可以读取到图片的base64编码的字符串。这里倒是研究了如何在异步的情况通过Observable进行消息通知。通过Canvas可以实现图片的大小剪贴等操作,后续有机会可以了解了解。

码字辛苦,打赏个咖啡☕️可好?💘