JS上传文件(base64字符串和二进制文件流)

简介: 这篇文章介绍了两种JavaScript文件上传的方法:使用FileReader对象将文件读取为base64字符串上传,以及使用FormData对象以二进制文件流的形式上传文件,包括如何处理文件选择、读取和上传的详细代码示例。

①以base64字符串上传(使用FileReader对象获取文件的base64字符串)

FileReader参考文档: FileReader - Web API 接口参考 | MDN

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

FileReader

  • readAsArrayBuffer():开始读取指定的 Blob中的内容,一旦完成,result 属性中保存的将是被读取文件的ArrayBuffer 数据对象。
  • readAsBinaryString():开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。
  • readAsDataURL():开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL 格式的 Base64 字符串以表示所读取文件的内容。
  • readAsText():开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个字符串以表示所读取的文件内容。
<input
    ref="upload"
    type="file"
    accept="image/*,application/pdf"
    @change="uploadFile($event.target.files)"
    style="display: none;" />
<!-- 普通点击上传 -->
<div @click="$ref.upload.click()" class="m-upload">选择文件</div>
<!-- 拖动文件上传 -->
<div @click="$refs.upload.click()" ref="dragUpload" class="m-upload">
    <img src="@/assets/images/add-upload.svg" class="u-upload" />
    <div class="assist"></div>
</div>

mounted () {
    // 将ref为dragUpload的元素变成drop区域
    this.$refs.dragUpload.addEventListener('dragenter', this.dragenter, false)
    this.$refs.dragUpload.addEventListener('dragover', this.dragover, false)
    this.$refs.dragUpload.addEventListener('drop', this.drop, false)
},
methods: {
    dragenter (e) {
      e.stopPropagation()
      e.preventDefault()
      this.$once('hook:beforeDestroy', function () {
        removeEventListener('dragenter', this.dragenter)
      })
    },
    dragover (e) {
      e.stopPropagation()
      e.preventDefault()
      this.$once('hook:beforeDestroy', function () {
        removeEventListener('dragover', this.dragover)
      })
    },
    drop (e) { // 拖拽上传方法
      e.stopPropagation()
      e.preventDefault()
      const files = e.dataTransfer.files
      this.uploadFile(files)
      this.$once('hook:beforeDestroy', function () {
        removeEventListener('drop', this.drop)
      })
    },
    uploadFile (files) { // 统一上传文件方法
      console.log('开始上传 upload-event files:', files)
      if (files.length) {
        var reader = new FileReader()
        // reader.readAsBinaryString(files[0])
        reader.readAsDataURL(files[0]) // 以base64方式读取文件内容
        reader.onloadstart = function (e) { // 当读取操作开始时触发
            const fileSize = e.total
            if (fileSize > 1024 * 500) { // 大于500KB时取消上传
                reader.abort()
            } else {
                console.log('开始读取 onloadstart:', e)
            }
        }
        reader.onabort = function (e) { // 当读取操作被中断时触发
            console.log('读取中止 onabort:', e)
        }
        reader.onerror = function (e) { // 当读取操作发生错误时触发
            console.log('读取错误 onerror:', e)
        }
        reader.onprogress = function (e) { // 在读取Blob时触发,读取上传进度,50ms左右调用一次
            console.log('读取中 onprogress:', e)
            console.log('已读取:', Math.ceil(e.loaded / e.total * 100) + '%')
        }
        const that = this
        reader.onload = function (e) { // 当读取操作成功完成时调用
            console.log('读取成功 onload:', e)
            // 该文件的base64数据,前端可直接用来展示图片
            // that.preImg = e.target.result
            // 若使用<img id="img">标签展示图片,可直接赋值src属性
            // document.getElementById('img').src = e.target.result
            // 调用上传接口,上传base64格式的文件数据
            const fileType = files[0].type.slice(files[0].type.indexOf('/') + 1)
            var formData = {
                uploadFile: e.target.result,
                fileFormat: fileType
            }
            console.log('提交数据:', formData)
            upload(formData).then(res => {
                console.log('upload-res:', res)
                if (res.message.code === 0) {
                    that.fileUrl = res.data.url
                }
            }).finally(() => {
                // input的change事件默认保存上一次input的value值,同一value值(根据文件路径判断)在上传时不重新加载
                that.$refs.upload.value = ''
            })
        }
        reader.onloadend = function (e) { // 当读取操作结束时触发(要么成功,要么失败)触发
            console.log('读取结束 onloadend:', e)
        }
      }
    }
}
.m-upload { // 拖动区域元素
    position: relative;
    display: inline-block;
    width: 98px;
    height: 98px;
    background: #FFFFFF;
    border: 1px dashed #D1D1D1;
    text-align: center;
    cursor: pointer;
    .u-upload { // 垂直居中
        width: 20px;
        height: 20px;
        display: inline-block;
        vertical-align: middle;
    }
    .assist { // 垂直居中辅助元素
        height: 100%;
        width: 0;
        display: inline-block;
        vertical-align: middle;
    }
}

②以二进制文件流上传(使用FormData模拟form表单提交)

FormData参考文档: FormData - Web API 接口参考 | MDN

FormData 接口提供了一种表示表单数据的键值对 key/value 的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send() 方法发送出去,本接口和此方法都相当简单直接。如果送出时的编码类型被设为 "multipart/form-data",它会使用和表单一样的格式。

实现了 FormData 接口的对象可以直接在for...of结构中使用,而不需要调用entries() : for (var p of myFormData) 的作用和 for (var p of myFormData.entries()) 是相同的。

FormData方法

  • FormData.append():向 FormData 中添加新的属性值,FormData 对应的属性值存在也不会覆盖原值,而是新增一个值,如果属性不存在则新增一项属性值。
  • FormData.delete():从 FormData 对象里面删除一个键值对。
  • FormData.entries():返回一个包含所有键值对的iterator对象。
  • FormData.get():返回在 FormData 对象中与给定键关联的第一个值。
  • FormData.getAll():返回一个包含 FormData 对象中与给定键关联的所有值的数组。
  • FormData.has():返回一个布尔值表明 FormData 对象是否包含某些键。
  • FormData.keys():返回一个包含所有键的iterator对象。
  • FormData.set():给 FormData 设置属性值,如果FormData 对应的属性值存在则覆盖原值,否则新增一项属性值。
  • FormData.values():返回一个包含所有值的iterator对象。
uploadFile (files) {
    console.log('开始上传 upload-event files:', files)
    if (files.length) {
        if (files[0].size > 500 * 1024) { // 校验文件大小
            this.content = '文件大小不能超过500KB'
            this.showTip = true
        } else {
            const fileType = files[0].type.slice(files[0].type.indexOf('/') + 1)
            var formData = new FormData()
            formData.set('uploadFile', files[0])
            formData.set('fileFormat', fileType)
            // 调用接口上传文件
            upload(formData).then(res => {
                console.log('upload-res:', res)
                if (res.message.code === 0) {
                    this.fileUrl = res.data.url
                }
            }).finally(() => {
                this.$refs.upload.value = ''
            })
        }
    }
}
相关文章
|
2月前
|
JavaScript 前端开发
JS几种拼接字符串的方法
JS几种拼接字符串的方法
53 1
|
1月前
|
JavaScript 前端开发 数据处理
模板字符串和普通字符串在浏览器和 Node.js 中的性能表现是否一致?
综上所述,模板字符串和普通字符串在浏览器和 Node.js 中的性能表现既有相似之处,也有不同之处。在实际应用中,需要根据具体的场景和性能需求来选择使用哪种字符串处理方式,以达到最佳的性能和开发效率。
|
28天前
|
JavaScript 前端开发 索引
JavaScript学习第二章--字符串
本文介绍了JavaScript中的字符串处理,包括普通字符串和模板字符串的使用方法及常见字符串操作方法如`charAt`、`concat`、`endsWith`等,适合前端学习者参考。作者是一位热爱前端技术的大一学生,专注于分享实用的编程技巧。
23 2
|
2月前
|
存储 JavaScript 前端开发
JavaScript 字符串(String) 对象
JavaScript 字符串(String) 对象
47 3
|
3月前
|
JavaScript 前端开发
javascript创建字符串
javascript创建字符串
|
3月前
|
JavaScript 前端开发
如何在JavaScript中替换字符串:一篇详细指南
如何在JavaScript中替换字符串:一篇详细指南
|
3月前
|
JavaScript 前端开发 C++
JavaScript用indexOf()在字符串数组中查找子串时需要注意的一个地方
JavaScript用indexOf()在字符串数组中查找子串时需要注意的一个地方
|
3月前
|
C++
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
|
3月前
|
存储 移动开发 JavaScript
用 JavaScript 操作字符串
用 JavaScript 操作字符串
|
3月前
|
JavaScript 前端开发 安全
JavaScript编程实现字符和字符串翻转
JavaScript编程实现字符和字符串翻转