ionic2中选取相册图片并支持多附件上传

最近在研究的ionic2,准备公司项目用该框架来写。近期在做多附件上传时遇到问题了,先简单的说下自己所遇到的具体问题和解决方案。另外强调下,由于web这块之前是一窍不通,经过一段时间的学习从最简单的html、css、javascript接着angularjs2再到ionic2,也算是入门了,web需要探究和摸索的地方实在是太多了,但好在ionic2封装了项目开发过程中绝大多数常见的控件和功能,所以对于我这种菜鸟来说开发起来不至于摸不着头脑。

言归正传,项目中有个功能是通过相册或者拍照可以选取并上传多张图片到服务端,如图

UI部分并不难,但是在附件上传这块卡手至少一个星期,其实一直到今天完成该功能回头想想还是当初想的太复杂了些。找了很多资料,由于ionic2出来也没多久,百度资料很少,只能去谷歌,其中一个解决方案就是使用native中提供的Transfer插件。本来还挺高兴的,心想终于找到答案了,但是看过文档后才发现该插件只支持单个文件的上传,想要实现多附件?不好意思,我是没想到办法,后来找到一哥们写的放在for循环里面,显然不行,这会导致上传完后在服务端出现多条记录(相当于post了很多次)。没辙,又在stackoverflow上用我那蹩脚的英语提问了,万能的S.O也没能帮到我。

经过了长达数天的煎熬,到处找资料,也稍微有点头绪了,但是web这块实在是菜,看了很多资料也就激发出一点点灵感,大概意思是使用window.resolveLocalFileSystemURL方法将本地选取的图片转为Blob然后追加到FormData中去,但是怎么upload也没说啊。最重要的是ts文件中window.resolveLocalFileSystemURL这个方法根本就不存在,后来找到了替代的方法File.resolveLocalFilesystemUrl,但是不管怎么转都是报错。再后来就是发现了这篇让我脱离苦海的文章,经过一番调试后发现,ImagePicker中返回的URI和这篇文章中使用的Camera返回的URI不一样,少了个file://,后来把这串加上后终于可以了。然后就是见证奇迹的时刻。

下面附上代码节选,几天的精华都在这里面了:

private upload(filePaths:Array<string>):Observable<any> {
        //每个文件上传任务创建一个信号
        var observables: Array<any> = [];
        filePaths.forEach((value:string, i, array) => {
            if (!value.startsWith('file://')) {
                value = 'file://' + value;
            }
            
            console.log('这里应该执行了吧.........');

            var observable = new Observable((sub:any) => {
                File.resolveLocalFilesystemUrl(value).then(entry => {
                    (<FileEntry>entry).file(file => {
                        // this.readFile(<Blob>file);
                        let blob: Blob = <Blob>file;
                        const reader = new FileReader();
                        reader.onloadend = () => {
                            
                            const imgBlob = new Blob([reader.result], {type: blob.type});
                            this.formData.append('file', imgBlob, (<any>blob).name);
                            console.log('已经成功一半了.................'+ + imgBlob);
                            

                            sub.next(null);
                            sub.complete();
                        };
                        reader.readAsArrayBuffer(blob);
                    });
                })
                .catch(error => console.log('报错了,日了狗----->' + JSON.stringify(error)));
            });

            observables.push(observable);
        });

        return ForkJoinObservable.create(observables);
    }


    uploadFile(host: string, params: Map<string, string>, filePaths:Array<string>, context: any, success: Function, fail: Function) {
        this.formData = new FormData();

        this.upload(filePaths).subscribe(data => {

            console.log('开始上传........');

            params.forEach((value, key) => {
                this.formData.append(key, value);
            });
            this.http.post(host, this.formData).toPromise().then(res => {
                success.call(context, res);
            }).catch(error => {
                fail.call(context, error);
            });
            // .catch(e => this.handleError(e))
            // .map(response => response.text())
            // // .finally(() => console.log('完成了'))
            // .subscribe(ok => console.log('上传成功了'));

        }, error => {
            console.log('文件处理失败');
        });
    }

可以这么去调用:

this.fileUpload.uploadFile(this.host, this.params, images, self, res => {
            console.log('真的可以了');
        }, error => {
            console.log('好像失败了');
        });

当然别忘了引入相关的包

import { Http, Response, Headers, RequestOptions } from '@angular/http';

import { Observable } from 'rxjs/Observable';
import { ForkJoinObservable } from "rxjs/observable/ForkJoinObservable";
import { File, Entry, FileEntry } from 'ionic-native';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

各位看过还请多指教。

2017.4.9  00:14

转载请注明出处http://www.longdw.com/ionic2-imagepicker-multiple-file-upload/

《ionic2中选取相册图片并支持多附件上传》上有26条评论

  1. 您好楼主,有完整的代码吗,我参考您的这个写了发现有几个参数可能是格式不对,老是报错

  2. 楼主您好,请问有完整的代码吗,或者github源码?参照您的代码,但是会报错,不知道为什么我的this.formdata无法append进数据,不知道您是怎么赋类型的?

  3. 你好,最近太忙了一直没看评论。我这边是可以的,this.formData = new FormData();然后this.formData.append(key, value);

  4. *this.params 这个参数是怎么传的,我传入

    {
    “flowNo”:”111111″,
    “object”: {
    “userName”:”admin”,
     “posType”:”trip_out”,
     “posDate”:”2017-08-01″
    }
    }

    怎么不行,
    求解,谢谢你

  5. 像这种参数怎么传

    let params={
    “flowNo”:”111111″,
    “object”: {
    “userName”:”admin”,
    “posType”:”trip_out”,
    “posDate”:”2017-08-01″
    }
    }

     

    怎么用下面的这种

    this.params = new Map();
    this.params.set(……)

    this.http.uploadFile(“http://124.202.135.197:18580/camp_s/pos-file/mapupload”, this.params, imageFileUri, self, res=> {}

    可以给我写个例子吗,我也是刚做ionic
    谢谢,明天老大还要看急死了
    ?

  6. Hi Longdw,

    When i copy paste your code into my project, lot of errors occur my project is ionic3, it seems that your code is not ionic3?

    Hope you can help me to convert your code into ionic3?

    Advance Many Thanks to you!

    Kind Regards

    1. The most obvious difference between ionic2 and ionic3 is that lazy loading,this code can use in ionic2 and ionic3. I think it’s better to base on specific errors and check what is cause.

  7. The most obvious difference between ionic2 and ionic3 is that lazy loading,this code can use in ionic2 and ionic3. I think it’s better to base on specific errors and check what is cause.

  8. Hi Longdw,

    我把你的代码全复制 ok 了 。。没有报错

    但是上传一直失败,debug  不方便,请问下你是如何debug 的

  9. 你好,我页面同时存在3个上传控件,依次调用,发现this.formData = new FormData();没有起到重置效果;

    反而,3个控件依次会把前一个控件选取的图片也会上传

评论已关闭。