文件上传

82 阅读1分钟

base64格式

    <input type="file" multiple> 
    <img>
    <script>
        const file = document.getElementsByTagName('input')[0];
        const image = document.getElementsByTagName('img')[0];
        file.onchange = () => {
            const read = new FileReader();
            // 将文件转为base64格式
            read.readAsDataURL(file.files[0]);
            read.onload = (event) =>{
              image.src = event.target.result
            }
        }
    </script>

单个文件上传

    <input type="file"> 
    <script>
        const file = document.getElementsByTagName('input')[0];
        const formData = new FormData();
        file.onchange = () => {
            const fileList = file.files[0];
            // 可以对文件类型进行判断
            if(fileList.type!=="image/png"){
                // 清除上传的文件
                file.value = '';
                console.log("上传文件类型只能为.png");
            }else{
                formData.append("file",fileList);
                formData.append('fileName',fileList.name);
                // 调用上传接口,对上传接口返回状态码进行判断,看文件是否上传成功
            }
        }
    </script>

多文件上传

 <input type="file" multiple> 
    <script>
        const file = document.getElementsByTagName('input')[0];
        const formData = new FormData();
        file.onchange = () => {
            const fileList = Array.from(file.files);
            fileList.map(item => {
                let formData = new FormData();
                formData.append('file',item);
                formData.append('fileName',item.name);
                return axios.post('api路径',formData,{
                    onUploadProgress(ev) {
                        // 检测每一个的上传进度
                        // ev.loaded获取已上传的部分,ev.total获取文件总大小
                        // 判断是否有显示每个文件的进度条
                        // if (curSpan) {
                        //     curSpan.innerHTML = `${(ev.loaded/ev.total*100).toFixed(2)}%`;
                        // }
                    }
                }).then((data) => {
                    // 如果每个文件有进度条,这时应该将它设置为100%
                })
            })
            //对文件上传结果进行判断
            Promise.all(fileList).then(() => {
                alert('恭喜您,所有文件都上传成功~~');
            }).catch(() => {
                alert('很遗憾,上传过程中出现问题,请您稍后再试~~');
            }).finally(() => {
                fileList = [];
                file.value = '';
            });
        }
      </script>

大文件分片上传

<input type="file">
    <script type="module">
        // import SparkMD5 from "spark-md5"
        const file = document.getElementsByTagName('input')[0];
        file.addEventListener('change', async function () {
            let file = upload_inp.files[0];
            if (!file) return;

            // 获取文件的HASH
            let already = [],
                data = null,
                {
                    HASH,
                    suffix
                } = await changeBuffer(file);

            // 获取已经上传的切片信息
            try {
                data = await instance.get('/upload_already', {
                    params: {
                        HASH
                    }
                });
                if (+data.code === 0) {
                    already = data.fileList;
                }
            } catch (err) {}

            // 实现文件切片处理 「固定数量 & 固定大小」
            let max = 1024 * 100,
                count = Math.ceil(file.size / max),
                index = 0,// 用来编码切片
                chunks = [];
            // 尽量让文件分为100份,这样文件进度便于计算
            if (count > 100) {
                max = file.size / 100;
                count = 100;
            }
            while (index < count) {
                chunks.push({
                    file: file.slice(index * max, (index + 1) * max),
                    filename: `${HASH}_${index+1}.${suffix}`
                });
                index++;
            }
                    // 把每一个切片都上传到服务器上
            chunks.forEach(chunk => {
                // 已经上传的无需在上传
                if (already.length > 0 && already.includes(chunk.filename)) {
                    complate();
                    return;
                }
                let fm = new FormData;
                fm.append('file', chunk.file);
                fm.append('filename', chunk.filename);
                instance.post('/upload_chunk', fm).then(data => {
                    if (+data.code === 0) {
                        complate();
                        return;
                    }
                    return Promise.reject(data.codeText);
                    }).catch(() => {
                        alert('当前切片上传失败,请您稍后再试~~');
                    });
                });
        });
    const changeBuffer = file => {
        return new Promise(resolve => {
            let fileReader = new FileReader();
            fileReader.readAsArrayBuffer(file);
            fileReader.onload = ev => {
                let buffer = ev.target.result,
                    spark = new SparkMD5.ArrayBuffer(),
                    HASH,
                    suffix;
                // append的参数必须为ArrayBuffer类型
                spark.append(buffer);
                // 获取唯一hash值
                HASH = spark.end();
                // 获取文件类型
                suffix = /\.([a-zA-Z0-9]+)$/.exec(file.name)[1];
                resolve({
                    buffer,
                    HASH,
                    suffix,
                    filename: `${HASH}.${suffix}`
                });
            };
        });
    };
    const complate = async () => {
            // 管控进度条
            index++;
            // 当所有切片都上传成功,我们合并切片
            if (index < count) return;
            try {
                data = await instance.post('/upload_merge', {
                    HASH,
                    count
                }, {
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    }
                });
                if (+data.code === 0) {
                    alert(`恭喜您,文件上传成功,您可以基于 ${data.servicePath} 访问该文件~~`);
                    return;
                }
                throw data.codeText;
            } catch (err) {
                alert('切片合并失败,请您稍后再试~~');
            }
        };
    </script>