IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    打印FormData、file input只触发一次change、Blob加File生成文件、FileReader读取

    水冗水孚发表于 2023-12-20 11:04:37
    love 0
    本文通过标题中的几个问题功能,提供一些代码(包括接口,用于复习一下文件操作相关的知识)

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

    问题复现

    如下代码:

     <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出来的,不过我们可以在请求的载荷中看到
    • 比如以下代码,笔者提供的一个带接口的代码示例(复制粘贴直接看)
    <!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是一个类数组的东西,所以我们可以循环之,打印看看其每一项的东西内容
    • 如下代码:
    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)转一下,这样就能够直接打印了,如下:
    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

    • 当我们选择文件上传以后,需要把上一次进行清空
    • 这样就不会影响继续上传操作
    • 如下代码:
    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生成文本文件

    代码:

    /**
     * 使用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文本读取方法去操作

    代码

    /**
     * 使用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...

    参考资料:

    • FormData: https://developer.mozilla.org/zh-CN/docs/Web/API/FormData
    • Blob:https://developer.mozilla.org/zh-CN/docs/Web/API/blob
    • FileReader:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader


沪ICP备19023445号-2号
友情链接