美文网首页I hava a coding dream
js 实现多图片上传,并且展示上传进度

js 实现多图片上传,并且展示上传进度

作者: super静_jingjing | 来源:发表于2018-03-06 18:23 被阅读1872次

    最近项目需要做一个如下图所示的图片上传功能;


    image.png

    找了很多插件发现都不是我自己想要的,索性自己实现一个,也可以学习一下;
    主要的思想就是:
    1.所有的图片包括相机图标的蓝色窗口(以下皆描述为相机)都看成一个li,点击相机选择文件上传;
    2.读取到文件之后,循环在相机之前插入图片的li,具体的图片处理,见2-1至2-5
    3.如果图片个数达到要求,隐藏相机;
    4.删除图片,将对应的li remove掉即可,注意相机的隐藏和展示;

    图片的读取以及上传原理:
    2-1.使用输入框的file类型,进行图片的获取
    2-2.使用FileReader进行文件的读取,并且转换成dataURL格式
    2-3.采用canvas对图片进行剪裁,并且转成dataURL格式;
    2-4.将dataURL数据转成bolb格式
    2-5.将bolb添加到FormData中
    2-6.使用XMLHttpRequest进行图片上传,可以查看进度;

    以上就是一个完整的实现流程,如果不需要进行剪裁图片,直接原图上传,直接省略第2-3点;

    1.使用input的多文件上传,设置好accept

    <input type="file" multiple onchange="selectImage(this)" accept="image/gif, image/jpeg, image/png" id="upload" > 
    

    2.使用FileReader读取文件
    在这里遇到了一个问题,开始我在load中获取值是使用的reader.result,导致一直只能拿到最后一条数据;然后断点发现reader.load是异步执行的,在for循环结束之后才能顺序执行load方法,所以在load中获取url不可使用 reader.result,必须通过load函数的参数进行获取值

    function selectImage(imgFile) {
        var allFile = imgFile.files;
        var imageArr = [];
        for(var i=0;i<allFile.length;i++){
            var file = allFile[i];
            //添加一层过滤
            var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
            if(!rFilter.test(file.type)) {
                alert("文件格式必须为图片");
                return;
            }
            var reader = new FileReader();
            reader.readAsDataURL(file); //用文件加载器加载文件
            //文件加载完成
            reader.onload = function(e) {
                //计算最后一个窗口right边距,当时处于第4个的时候,right=0
                if((allFile.length + 1)%4 == 0){
                    document.getElementById("uploadBtn").style.marginRight = "0px";
                }
                //以下就是将所有上传的图片回显到页面上,如果需要用canvas进行剪裁再回显以下代码就放入到canvas中
                var li = document.createElement('li');
                li.className = "upload-li";
                li.innerHTML = '<div class="item image">'+
                                    '<img class="upload-image" src="'+e.target.result+'"/>'+
                                    '<img class="delete-image" src="assets/image/image-delete.png"/>'+
                                '</div>';
                document.getElementById("uploadUL").insertBefore(li, document.getElementById("uploadBtn"));
            };
        }
    }
    

    3.如果需要对图像进行剪裁再回显,加载页面的代码应该放入到这一步,按照你的需求去完成;
    ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
    img 规定要使用的图像、画布或视频。
    sx 可选。开始剪切的 x 坐标位置。
    sy 可选。开始剪切的 y 坐标位置。
    swidth 可选。被剪切图像的宽度。
    sheight 可选。被剪切图像的高度。
    x 在画布上放置图像的 x 坐标位置。
    y 在画布上放置图像的 y 坐标位置。
    width 可选。要使用的图像的宽度。(伸展或缩小图像)
    height 可选。要使用的图像的高度。(伸展或缩小图像)
    按照你自己的需求去剪裁,也可以不进行剪裁,按照实际大小去展示;不剪裁的完整写法如下

    function canvasImg(dataURL) {
        const img = new window.Image();
        img.src = dataURL;
        var canvas = document.createElement("canvas"),
            ctx = canvas.getContext("2d");
        img.onload = function() { //图片加载完成
            //canvas 值按照你自己的实际需求去写
            canvas.width = 131;
            canvas.height = 131;
            ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
            document.getElementById("uploadUL").insertBefore(canvas, document.getElementById("uploadBtn"));
        };
    }
    

    将剪裁的图片转成dataURL格式

    //图片的质量,这里设置的是1,也可以是小数
    var quality = 1; 
    //获取画布图片,并且要jpg格式
    var data = canvas.toDataURL("image/jpeg", quality); 
    data = data.split(',')[1];
    

    4.将dataURL转成Blob

    data = window.atob(data);
    var ia = new Uint8Array(data.length);
    for(var i = 0; i < data.length; i++) {
        ia[i] = data.charCodeAt(i);
    }
    //以上均为二进制参数处理,从而获取一个blob对象
    var resultBolb = new Blob([ia], { 
        type: "image/jpeg"
    });
    

    5.上传图片

    function fileUpload(resultBolb) { 
        var fd = new FormData(); 
        //向form中加入图片数据,name属性是file
        fd.append("file", resultBolb); 
        //上传图片
        var xhr = new XMLHttpRequest();
        //请求成功
        xhr.addEventListener('load', function(resUpload) {
        }, false);
        //请求失败
        xhr.addEventListener('error', function() {
        }, false);
        //上传终止
        xhr.addEventListener('abort', function() {
        }, false);
        //上传进度
        xhr.upload.addEventListener('progress', function() {
        }, false);
        xhr.open('POST', "http://XXXXXXXXXXXXX"); //请求地址
        xhr.send(fd); //发送
    }
    

    以上就是完成的js实现代码,以下简单展示一下实现的html+css:

    <div class="upload-div">
                <ul class="upload-ul" id="uploadUL">
                    <!--默认的点击窗口
                        在添加了图片之后,循环在这个前面insert图片的li
                    -->
                    <li class="upload-li" id="uploadBtn">
                        <form class="img-input-form" style="opacity: 0;">
                            <input type="file" multiple onchange="selectImage(this)" accept="image/gif, image/jpeg, image/png" id="upload" > 
                        </form>
                        <div class="item">
                            <span class="photo-span"></span>
                            <span class="circle-span"></span>
                            <span class="circle-solid-span"></span>
                        </div>
                    </li>
                </ul>
            </div>
    

    以上并不是完成代码,后面整理一下把完整代码放出来;欢迎提意见哦:)

    很多朋友私信我到底怎么实现我下面把完整版代码贴出来;
    以上代码经过了简化,和上面教程不太一样,主要是为了配合后台传数据,如果想按照上面教程进行做肯定也是没有问题的
    需要导入jquery包+我自己写的一个公共方法包(需要的私信我,我不贴出来了,太长了)
    我们后台提供的接口是多图片上传的,所以就在选择了图片之后点击按钮调用fileUpload,按钮被我整理这个demo出来的时候删掉了,你们自己加一个按钮吧,这个也不难的;

    <!DOCTYPE html>
    <html >
    <head>
        <meta charset="UTF-8">
        <title></title>
        <link rel="shortcut icon" href="#" />
        <meta id="viewport" name="viewport" content="width=750">
        <meta http-equiv="Content-Type" content="multipart/form-data; charset=utf-8" />
        <style>
            html,body{
                margin: 0;
                padding: 0;
            }
            ul,li{
                margin: 0;
                padding:0;
            }
            .image-div{
                padding: 30px 50px;
                border-radius: 10px;
                background-color: #fff;
                margin: 40px 30px 0;
            }
            .image-div .title{
                height: 70px;
                line-height: 70px;
                font-size: 32px;
                color: #5f5f5f;
                font-weight: 500;
            }
            .upload-div,
            .show-div{
                /*margin-top: 20px;*/
            }
            .upload-div .upload-ul,
            .show-div .show-image-ul{
                letter-spacing: -0.5em;
            }
            .upload-div .upload-ul .upload-li,
            .show-div .show-image-ul .show-image-li{
                height: 131px;
                width: 131px;
                margin-right: 22px;
                letter-spacing: normal;
                display: inline-block;
                margin-top: 20px;
            }
            .show-div .show-image-ul .show-image-li img{
                height: 100%;
                width: 100%;
            }
            .upload-div .upload-ul .upload-li:nth-child(4n),
            .show-div .show-image-ul .show-image-li:nth-child(4n){
                margin-right: 0;
            }
            .upload-div .upload-ul .upload-li .item{
                height: 100%;
                width: 100%;
                border-radius: 10px;
                border: 3px dashed #97def1;
                position: relative;
            }
            .upload-div .upload-ul .upload-li .item.image{
                border: none;
                font-size: 0;
            }
            .upload-div .upload-ul .upload-li .item .delete-image{
                position: absolute;
                height: 25px;
                top: -12.5px;
                left: -12.5px;
            }
            .upload-div .upload-ul .upload-li .item .upload-image{
                height: 100%;
                width: 100%;
                border-radius: 10px;
                vertical-align:initial;
            }
            .img-input-form{
                position: absolute;
                height: 131px;
                width: 131px;
                z-index: 999;
            }
            .img-input-form input{
                position: absolute;
                top: 0;
                left: 0;
                height: 131px;
                width: 131px;
            }
            .photo-span{
                display: inline-block;
                position: absolute;
                height: 32px;
                width: 39px;
                border-radius: 5px;
                border: 3px solid #97def1;
                left: 50%;
                top: 50%;
                margin-top: -16px;
                margin-left: -19.5px;
            }
            .circle-span{
                display: inline-block;
                position: absolute;
                height: 14px;
                width: 14px;
                border-radius: 7px;
                border: 3px solid #97def1;
                left: 50%;
                top: 50%;
                margin-top: -7px;
                margin-left: -7px;
            }
            .circle-solid-span{
                display: inline-block;
                position: absolute;
                height: 4px;
                width: 4px;
                border-radius: 2px;
                background-color: #97def1;
                left: 50%;
                top: 50%;
                margin-top: -10px;
                margin-left: 9px;
            }
            .btm-btn{
                height: 100px;
                width: 500px;
                border-radius: 50px;
                text-align: center;
                font-size: 26px;
                color: #fff;
                background-color: #ff7e00;
                margin-left: 125px;
                margin-top: 40px;
                margin-bottom: 40px;
            }
            
        </style>
    </head>
    
    <body>
    <div class="content" id="content">
        <div class="image-div" id="uploadDiv">
            <div class="title" id="imageTitle">
                上传图片(最多4张)
            </div>
            <div class="upload-div" id="uploadImageDiv">
                <ul class="upload-ul" id="uploadUL">
                    <!--默认的点击窗口
                        在添加了图片之后,循环在这个前面insert图片的li
                    -->
                    <li class="upload-li" id="uploadBtn">
                        <form class="img-input-form" enctype="multipart/form-data"  style="opacity: 0;">
                            <input type="file" multiple onchange="selectImage(this)" accept="image/gif, image/jpeg, image/png" id="upload" >
                        </form>
                        <div class="item">
                            <span class="photo-span"></span>
                            <span class="circle-span"></span>
                            <span class="circle-solid-span"></span>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <script src="assets/js/libs/jquery-2.1.1.min.js"></script>
    <script src="assets/js/libs/yutil-1.0.1.js"></script>
    <script type="text/javascript" charset="utf-8">
        var uploadImgIndex = 0;
        var imgArr = [];
        
        function selectImage(imgFile){
            var allFile = imgFile.files;
            var totalLen = allFile.length;
            if(yValidate.checkNotEmpty(imgArr) && imgArr.length>0){
                totalLen = totalLen + imgArr.length;
            }
            if(totalLen>4){
                alert("只能上传4张图片");
                return;
            }
            for(var i=0;i<allFile.length;i++){
                var file = allFile[i];
                if(yValidate.checkNotEmpty(imgArr) && imgArr.length>0){
                    if(imgArr.length <4){
                        imgArr.push(file);
                    }
                }else{
                    imgArr.push(file);
                }
                //添加一层过滤
                var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
                if(!rFilter.test(file.type)) {
                    alert("文件格式必须为图片");
                    return;
                }
                var reader = new FileReader();
                reader.readAsDataURL(file); //用文件加载器加载文件
                //文件加载完成
                reader.onload = function(e) {
                    //计算最后一个窗口right边距,当时处于第4个的时候,right=0
                    if((allFile.length + 1)%4 == 0){
                        document.getElementById("uploadBtn").style.marginRight = "0px";
                    }
                    //以下就是将所有上传的图片回显到页面上,如果需要用canvas进行剪裁再回显以下代码就放入到canvas中
                    var li = document.createElement('li');
                    li.id = "upload_"+uploadImgIndex;
                    document.getElementById("uploadBtn").style.display = "";
                    uploadImgIndex++;
                    li.className = "upload-li";
                    li.innerHTML = '<div class="item image">'+
                        '<img class="upload-image" src="'+e.target.result+'"/>'+
                        '<img class="delete-image" src="assets/image/image-delete.png"/>'+
                        '</div>';
                    document.getElementById("uploadUL").insertBefore(li, document.getElementById("uploadBtn"));
                    var uploadArr = document.getElementById("uploadUL").querySelectorAll("li");
                    var len = uploadArr.length ;
                    if(len > 4){
                        document.getElementById("uploadBtn").style.display = "none";
                    }
                };
                reader.onloadend = function(e) {
                    $(".delete-image").off('click');
                    $(".delete-image").on('click',function(){
                        // alert("dasd");
                        var li = $(this).parent().parent()[0];
                        var index = $(".upload-ul .upload-li").index(li);
                        var liId = li.id;
                        $("#"+liId).remove();
                        imgArr.splice(index,1);
                        document.getElementById("uploadBtn").style.display = "";
                    });
                }
            }
        }
        
        function fileUpload(){
            var param = new FormData();
            for(var i=0; i<imgArr.length;i++){
                param.append('file[]', imgArr[i], i);
            }
            param.append("orderId", req.id);
            param.append("userId", bxUserData.id);
            $("body").mLoading("show");
            $.ajax({
                url:url,
                type:'POST',
                data:param,
                async: false,
                cache: false,
                contentType: false,
                processData: false,
                success:function(data){
                    $("body").mLoading("hide");
                    
                },
                error:function(){
                    $("body").mLoading("hide");
                    alert(res.description || res.message || "上传失败");
                }
            });
        }
    </script>
    </body>
    </html>
    

    相关文章

      网友评论

      本文标题:js 实现多图片上传,并且展示上传进度

      本文链接:https://www.haomeiwen.com/subject/grerfftx.html