FormData打印为空、input的file只触发一次change、Blob加File生成文件、FileReader.readAsText读取之

本文通过标题中的几个问题功能,提供一些代码(包括接口,用于复习一下文件操作相关的知识)

问题一 FormData无法直接console.log出来

问题复现

如下代码:

js 复制代码
 <script>
    const formData = new FormData()
    formData.append('name', '孙悟空')
    formData.append('age', 50)
    formData.append('home', '花果山水帘洞')

    console.log('formData-->', formData);
</script>

如下看不到键值对的贴图:

  • 一般来说,我们是使用new FormData()去通过接口,给后端传递一些文件信息
  • FormData是无法直接console.log出来的,不过我们可以在请求的载荷中看到
  • 比如以下代码,笔者提供的一个带接口的代码示例(复制粘贴直接看)
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- axios的cdn -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        // 生成年月日时分秒
        function time() {
            var today = new Date();
            var y = today.getFullYear();
            var m = today.getMonth();
            var d = today.getDate();
            var h = today.getHours();
            var i = today.getMinutes();
            var s = today.getSeconds();
            m = m + 1;
            d = d < 10 ? "0" + d : d
            m = m < 10 ? "0" + m : m
            i = i < 10 ? "0" + i : i
            s = s < 10 ? "0" + s : s
            return (y + "-" + m + "-" + d + " " + h + ":" + i + ":" + s)
        }
    </script>
</head>

<body>
    <input type="file" />
    <script>
        // 选择input标签,并监听上传文件change事件
        let ipt = document.querySelector('input') 
        ipt.addEventListener('change', async (e) => {
            // 拿到第一个文件叭
            let file = e.target.files[0]
            const formData = new FormData()
            // 把相关信息丢到formData中
            formData.append('this_is_a_file_for_backend', file)
            formData.append('upload_time', time())
            // 直接打印不出来
            console.log('formData', formData);
            // 执行上传请求操作
            await uploadFn(formData)
            // e.target.value = null 
        })

        const uploadFn = (params) => {
            return new Promise((resolve, reject) => {
                axios.post('http://ashuai.work/api/simulateUpload', params)
                    .then((res) => {
                        resolve(res.data)
                    })
                    .catch((err) => {
                        reject(err)
                        console.log(err);
                    });
            })
        }
    </script>
</body>
</html>
  • 我们现在在载荷中看一下上传的参数,如下图:

FormData类数组循环打印看内容

  • 但是这样看的话,的确是有些不方便了,不过虽然不能直接打印出来,可以间接去看
  • FormData是一个类数组的东西,所以我们可以循环之,打印看看其每一项的东西内容
  • 如下代码:
js 复制代码
const formData = new FormData()
formData.append('this_is_a_file_for_backend', 'file')
formData.append('upload_time', '2024年1月1日')

// for of 方式
for (const iterator of formData) {
    console.log('for of--->', iterator);
}

// forEach 方式
formData.forEach((value, key) => {
    console.log(key, ' <-----forEach-----> ', value);
})
  • 如下打印图:

推荐使用Array.from(formData)打印看

  • 不过笔者推荐直接使用Array.from(formData)转一下,这样就能够直接打印了,如下:
js 复制代码
const formData = new FormData()
formData.append('this_is_a_file_for_backend', 'file')
formData.append('upload_time', '2024年1月1日')

// 类数组转一下直接打印的是二维数组
console.log(Array.from(formData));

input的file若还是上一次的文件,则只触发一次change

  • 当我们选择文件上传以后,需要把上一次进行清空
  • 这样就不会影响继续上传操作
  • 如下代码:
js 复制代码
let ipt = document.querySelector('input')
ipt.addEventListener('change', async (e) => {

    // 清空,要不然再上传同样的文件就不触发change事件了
    e.target.value = null 
    // 清空,要不然再上传同样的文件就不触发change事件了
   
    let file = e.target.files[0]
    const formData = new FormData()
    formData.append('this_is_a_file_for_backend', file)
    formData.append('upload_time', time())
    await uploadFn(formData)
})

浏览器会把文件进行缓存到变量e.target.value中,若再次触发上传操作,会自动比对前一次和这一次文件是否发生变化,若还是上一次的一致,不一致才会触发change事件

Blob加File生成文本文件

代码:

js 复制代码
/**
 * 使用Blob和File构造函数去创建一个简单的txt文件
 * */
function createTxtFile(fileName, fileContent) {
    let blob = new Blob([fileContent], { type: 'text/plain' });
    let txtFile = new File([blob], fileName);
    return txtFile
}

let file = createTxtFile('js创建的', 'Hello, World...')
console.log(file)

打印贴图:

FileReader.readAsText读取文本文件

  • 模拟需求
  • 假设有一个上传txt文件的功能,在发送上传请求前,需要解析一下txt中的内容文字
  • 这个时候,我们就需要去读取文本文件中的内容,并做一些相关的操作了
  • 即:使用FileReader的readAsText文本读取方法去操作

代码

js 复制代码
/**
 * 使用FileReader去异步读取一个简单的txt文件
 * */
function readTxtFile(file) {
    return new Promise((resolve, reject) => {
        // 实例化文件阅读器
        var reader = new FileReader();
        // 读取完成
        reader.onload = function (event) {
            var contents = event.target.result;
            resolve(contents)
        };
        // 读取错误
        reader.onerror = function (err) {
            reject(err)
        };
        // 开始读取(字符串形式)
        reader.readAsText(file);
        // reader.readAsText(xxx); // 报错
    })
}

readTxtFile(file).then((res) => {
    console.log('成功', res);
}).catch((err) => {
    console.log('失败', err);
})

可以结合上述代码,先生产创建txt文件,再去读取文件

A good memory is better than a bad pen...

参考资料:

相关推荐
PYB33 小时前
【Web·JS·基础】函数的使用和展运算符...objs
前端·javascript
默_笙4 小时前
🚥 给 RAG 装一台心电监护仪:LangSmith 全链路观测(上)
前端·javascript
变与不变8065 小时前
js同步和异步难点重点详解
开发语言·javascript·ecmascript
Dovis(誓平步青云)6 小时前
多个链接不等于多份证据,新闻核验看板怎样合并来源
java·服务器·前端·javascript·人工智能·pdf·电脑
Dovis(誓平步青云)6 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
可乐鸡翅yeah_8 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
ss2739 小时前
AI全栈实战 | 2.3-01 组件库实战:Element Plus 怎么搭出专业界面,过度封装为什么成维护负担
前端·javascript·elementui·vue
福兮说9 小时前
URL 编码的七个坑:c++ 传到后端变空格、%25 套娃、截断 emoji 直接报错
开发语言·前端·javascript·node.js·url
小的时候可菜了9 小时前
JS 异步的本质:从单线程到 thenable(一条进化链)
开发语言·前端·javascript
可乐鸡翅yeah_10 小时前
hls.js 配置 loadStartPosition,点播起始播放位置踩坑
开发语言·javascript·网络协议·ecmascript·m3u8在线