使用axios和ajax实现文件上传

332 阅读2分钟

前言

最近碰到要给需求,需要做一个上传进度的进度,附加一个进度动画,摸索了好久,终于用原生的XMLHTTPREQUEST和axios以及jQuery实现了,下面就是代码

HTML

<div>
    <div class="downloadContainer">
        <div class="animateImgWrapper">
            <img class="animateImg" src="./1.jpg" alt=""/>
        </div>
        <div class="animateBarWrapper">
            <div class="animateBar"></div>
        </div>
        <div>
            <p class="upload">文件上传</p>
            <input class="file" type="file" name="file"/>
        </div>
        <div>
            <input class="submit" type="submit" value="提交"/>
        </div>
    </div>
</div>

CSS

html,
body {
    margin: 0;
    padding: 0;
}

.animateImgWrapper {
    height: 30px;
}

img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: none;
}

.animateBarWrapper {
    height: 5px;
    width: 100%;
    background-color: #d8e5f4;
}

.animateBar {
    height: 5px;
    width: 0;
    line-height: 30px;
    text-align: center;
    background-color: #5287ee;
}

.file {
    display: none;
}

.fileShow {
    display: block;
    background: #5287ee;
}

.imgShow {
    display: block;
}

js

xhr

const animateImgWrapper = document.querySelector(".animateImgWrapper");
const upload = document.querySelector(".upload");
const file = document.querySelector(".file");
const submit = document.querySelector(".submit");
const animateImg = document.querySelector(".animateImg");
const animateBar = document.querySelector(".animateBar");
upload.addEventListener("click", function () {
    file.click();
});
file.addEventListener("change", function (e) {
    file.classList.add("fileShow");
});
submit.addEventListener("click", function () {
    if (file.files[0] == null) {
        alert("请先上传文件");
    } else {
        const f = file.files[0];
        const name = file.files[0].name;
        const options = {
            f,
            name,
        };
        xhr(options)
    }
});

// 文件上传
function xhr(options) {
    const formData = new FormData();
    const Rect = animateImgWrapper.getBoundingClientRect();
    let defaults = {
        method: "post",
        url: "http://localhost:8088/upload/file?userid=gsgsgsgsg",
    };
    defaults = Object.assign(defaults, options);
    formData.append("file", defaults.f, defaults.name);
    const xhr = new XMLHttpRequest();
    xhr.open(defaults.method, defaults.url);
    // 上传的返回结果
    xhr.onloadend = function (e) {
        if (xhr.status == 200) {
            animateImg.style.display = "none";
        }
    };
    // 文件上传进度
    xhr.upload.addEventListener("progress", (e) => {
        animateImg.style.display = "block";
        let result = e.loaded / e.total;
        let move = result * Rect.width - 30 + "px";
        animateImg.style.transform = `translateX(${move})`
        /*            animateImg.animate(
                        [
                            {
                                transform: `translateX(${move})`,
                            },
                        ],
                        {
                            easing: "ease",
                            fill: "forwards",
                            duration: 250
                        }
                    );*/
        // 下面的进度条
        animateBar.style.width = `${result * 100}%`;
        animateBar.innerHTML = parseInt(String(result * 100)) + "%";
    });
    xhr.send(formData);
}

/*
    // 最快250ms触发一次
    function throttle (func, limit = 250) {
        let inThrottle = false;
        return function() {
            const args = arguments;
            const context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        }
    }*/

jquery

const animateImgWrapper = document.querySelector(".animateImgWrapper");
const upload = document.querySelector(".upload");
const file = document.querySelector(".file");
const submit = document.querySelector(".submit");
const animateImg = document.querySelector(".animateImg");
const animateBar = document.querySelector(".animateBar");
upload.addEventListener("click", function () {
    file.click();
});
file.addEventListener("change", function (e) {
    file.classList.add("fileShow");
});
submit.addEventListener("click", function () {
    if (file.files[0] == null) {
        alert("请先上传文件");
    } else {
        const f = file.files[0];
        const name = file.files[0].name;
        const options = {
            f,
            name,
        };
        xhr(options)
    }
});

// 文件上传
function xhr(options) {
    const formData = new FormData();
    const Rect = animateImgWrapper.getBoundingClientRect();
    let defaults = {
        method: "post",
        url: "http://localhost:8088/upload/file?userid=gsgsgsgsg",
    };
    defaults = Object.assign(defaults, options);
    formData.append("file", defaults.f, defaults.name);
    $.ajax({
        url: defaults.url,
        type: defaults.method,
        data: formData,
        contentType: false,//必须false才会自动加上正确的Content-Type
        processData: false,//必须false才会避开jQuery对 formdata 的默认处理
        xhr: function () { //获取ajaxSettings中的xhr对象,为它的upload属性绑定progress事件的处理函数
            myXhr = $.ajaxSettings.xhr();

            if (myXhr.upload) { //检查upload属性是否存在
                //绑定progress事件的回调函数
                myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
            }

            return myXhr; //xhr对象返回给jQuery使用
        },
        success: function (data) {
               console.log("做一些事情吧")
        },
        error: function () {
            mui.alert("上传失败!", "提示", "确定");
        }
    });
}

axios

使用axios不需要用formdata对文件进行处理,axios自己内部会处理

const formdata = new FormData()
formdata.append("file",this.files[0],this.files[0].name)
this.axios.post(uploadUrl, formdata , {
  headers: {
    'Content-Type': 'multipart/form-data'
  },
  transformRequest: [function (data) {
    return data
  }],
  onUploadProgress: progressEvent => {
    let complete = (progressEvent.loaded / progressEvent.total * 100 | 0) + '%'
    self.uploadMessage = '上传 ' + complete
  }
})
.then((response) => {
  if (response.status === 200) {
    self.uploadMessage = '上传成功!'
  }
})

注意事项

使用ajax和或者原生的xhr上传时,千万不用设置请求头'Content-Type': 'multipart/form-data',不然后台使用 org.springframework.web.multipart.MultipartFile类时无法拿到传过去的file的值,值总是为null,这也是我自己搞了好久才找到的知识点,但是使用axios时,就必须指定了,xhr和ajax不行,好像是chrome自己会做一层转换,具体原因忘了记下了,总之就是不能设置请求头,另外这个图片跟着进度条走的时候,还有优化空间,可以让他看起来跟丝滑参考,但是我自己试了下,效果不是太好,但是这完全是我自己没有处理好,该demo后续会继续完善