• 技术文章 >web前端 >前端问答

    一个小时带你总结前端上传文件的方法(整理分享)

    长期闲置长期闲置2022-02-08 17:33:31转载909
    本篇文章给大家带来了关于前端上传文件的相关知识,其中包括传统开发模式上传、前后端分离上传以及ajax上传等等相关问题,希望对大家有帮助。

    上传文件

    项目中会有很多文件上传的需求,例如:头像上传、表格文件、word文档等…

    上传必备表单元素:

    <input type="file">

    进行文件上传的时候,
    1.表单必须是post请求
    2.表单必须声明不要对数据进行编码 - enctype=multipart/form-data

    传送数据的格式就是键值对的形式,且数据都是js的数据类型,但文件进行传输的时候,只有两种形式去传输:

    1. 以字符串的形式去描述一个文件
    2. 以文件流的形式去描述一个文件

    传统开发模式上传

    前后端混在一起开发

    传统开发模式的上传需要将表单中选择的文件传送给后端,让后端做上传:

    <form action="./upload.php" method="post" enctype="multipart/form-data">
        <input type="file" name="avatar">
        <input type="submit" value="上传"></form>

    此时的表单中必须有enctype这个属性,这个属性的说明如下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJ4TCM6S-1623079075591)(media/1621737905322.png)]

    点击上传按钮后,后端对文件进行上传处理,以php为例:

    echo "上传文件名: " . $_FILES["avatar"]["name"] . "<br>";  上传文件的名称
    echo "文件类型: " . $_FILES["avatar"]["type"] . "<br>";  上传文件的类型
    echo "文件大小: " . ($_FILES["avatar"]["size"] / 1024) . " kB<br>";  上传文件的大小,以字节计
    echo "文件临时存储的位置: " . $_FILES["avatar"]["tmp_name"];  存储在服务器的文件的临时副本的名称
    echo $_FILES["file"]["error"]  由文件上传导致的错误代码

    将文件保存到服务器中:

    move_uploaded_file($_FILES["avatar"]["tmp_name"], "upload/" . $_FILES["avatar"]["name"]);
    echo "文件存储在: " . "upload/" . $_FILES["avatar"]["name"];

    在实际开发中,为了提高效率,通常都会使用前后端分离开发。

    前后端分离上传

    前端做前端,后端做后端,最终使用接口文档对接 - 核心技术是 ajax

    前后端分离开发,应用的主要技术就是ajax。上传同样可以使用ajax来上传。

    FormData是js内置的一个构造函数,构造出来的对象可以识别文件信息。

    使用方式:

    构造FormData对象,将文件信息添加到FormData对象中,然后上传。

    文件信息在文件选择控件中:表单.files

    例:

    <body>
        <input type="file" name="avatar">
        <input type="button" value="上传"></body><script>document.querySelector('[type="button"]').onclick = function(){
    	 console.log(document.querySelector('[type="file"]').files)}</script>

    在这里插入图片描述

    FormData对象有一个特点,将文件信息添加进去后,直接打印不能看到文件信息,需要使用for of遍历才能看到:

    var formdata = new FormData();var fileinfo = document.querySelector('[type="file"]').files[0];formdata.append('avatar',fileinfo) / 将文件信息添加到FormData对象中
    console.log(formdata)for(var v of formdata){
        console.log(v)}

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w0A4kjb7-1623079075609)(media/1621739596218.png)]

    FormData对象中也可以添加别的数据,进行一起提交:

    formdata.append('avatar',fileinfo)formdata.append('age',12)for(var v of formdata){
        console.log(v)}

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4L8JjjG-1623079075612)(media/1621739699971.png)]

    从FormData对象中删除一个数据,使用:

    formdata.delete(键)

    有时候,我们在一个表单中需要上传多个文件,此时,FormData中可以不用追加一个文件信息,可以在构造FormData对象的时候,将整个表单对象传入,他会自动识别所有数据:

    <body><form action="">
        <input type="text" name="age" value="20">
        <input type="file" name="avatar">
        <input type="button" value="上传"></form></body><script>document.querySelector('[type="button"]').onclick = function(){
        var formdata = new FormData(document.querySelector('form'));
        for(var v of formdata){
            console.log(v)
        }}</script>

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UfREm9lD-1623079075616)(media/1621739964694.png)]

    当使用FormData上传的时候,将FormData对象当做数据传入,不需要修改请求头,浏览器会自动修改。

    此时已经实现了前后端分离上传了,但是正常项目中都会有一个预览图片的功能。

    我们可以让后端在实现上传后,将上传以后的文件名称传送给前端,让前端渲染返回的图片路径。

    但这样是在上传以后预览的,假设我们选择了文件以后,就想看看这个文件是否要上传,也就是在上传之前要预览的话,还是没有办法实现。

    我们可以利用H5提供的FileReader来读取文件并预览,然后决定是否要上传。

    ajax上传

    ajax进行上传后

     var xhr = new XMLHttpRequest;
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status>=200 && xhr.status<300){
                    var res = xhr.responseText;
                    // console.log(res);
                    if(res==1){
                         alert('上传成功')
                         location.reload()
                    }
                }
            }
        }
        xhr.open('post','2-upload.php')

    将文件数据放在send中进行传送
    需要借助H5提供的构造函数FormData - 用来识别文件信息

    var fd = new FormData()

    将文件信息放在fd这个对象中 - 用fd的append方法

    文件信息在哪里?

    var file = document.querySelector('[type="file"]')
        // console.dir(file);
        var fileinfo = file.files[0] / 文件信息

    append方法,是将文件放入这个对象中,对象就需要键值对,参数1是键,参数2是文件信息

    fd.append('avatar',fileinfo)

    fd有一个特性,就是直接打印他, 看不到其中的内容 需要遍历才能看到其中的数据 - 必须使用 for of

    for(var value of fd){
             console.log(value);
        }

    fd除了能添加文件信息,还可以添加数据

    fd.append('username',document.querySelector('[name="username"]').value)

    上传文件的时候,利用FormData,里面就有了数据和文件信息,其实最终文件和数据以二进制数据流进行传送的,不需要设置请求头,因为ajax会自动调整

    文件数据其实就是fd

    php:

    现在能打印出数据,文件存到了临时目录中
    上传就是将临时文件移动到服务器中

    header("content-type:text/html;charset=utf8");echo "<pre>";print_r($_FILES);move_uploaded_file($_FILES['avatar']['tmp_name'],'./upload/'.$_FILES['avatar']['name']);// echo '上传成功';echo './upload/'.$_FILES['avatar']['name'];
     echo "<script>
         alert('上传成功')
         location.assign('./1-上传表单.html')

    ajax 上传前:

    当文件选择器中的数据发生了变化就要读取并预览
    读取并预览 - 借助H5提供的FileReader - 读取文件是异步读取
    构造函数需要new

    document.querySelector('[type="file"]').onchange = function(){var fr = new FileReader();

    readAsArrayBuffer - 将数据读取成一个Buffer数组

    var fileinfo = this.files[0]

    参数要一个文件对象 - 结果是一个buffer

    fr.readAsArrayBuffer(fileinfo)

    参数要一个文件对象 - 结果是一个二进制数据 - 适用于多媒体文件

    fr.readAsBinaryString(fileinfo)

    结果是一个可以当做路径使用的数据 - base64字符串 - 适用于图片

    fr.readAsDataURL(fileinfo)

    在load事件中,读取完成后获取读取出来的数据
    load事件在读取完成的时候触发

    fr.onload = function(){
            / result属性是读取出来的内容        / console.log(fr.result);
            / 创建img标签        var img = document.createElement('img')
            img.src = fr.result;
            document.body.appendChild(img)

    FileReader读取文件

    FileReader也是js内置的一个构造函数,主要功能是用来读取文件,读取文件为异步读取。

    var fr = new FileReader()  创建读取对象// 该对象的读取方法:fr.readAsDataUrl(文件信息)  将文件读取为base64字符串 - 通常用于图片文件,读取结果可以作为图片的src使用
    fr.readAsArrayBuffer(文件信息)  将文件读取为二进制数据流 - 通常用于多媒体文件
    fr.readAsText(文件信息)  将文件读取为字符串 - 通常用于文档文件

    对象监听的事件:

    abort事件:在读取被中断的时候触发
    error事件:读取发生错误的时候触发
    load事件:在读取完成的时候触发 - 常用语读取完成后获取数据
    loadstart事件:在读取开始的时候触发
    loadend事件:在读取结束的时候触发
    progress事件:在读取过程中触发

    例:

    fr.onload = function(){
      读取结果为:对象.result 或 事件对象.target.result
        console.log(fr.result)  此时这个数据就可以作为img的src进行图片预览}

    base64是指:小写字母+大写字母+数字+加号+等于号 共64个字符

    jquery上传

    data位置就直接写formData就好了

    设置一个content-type为false表示jquery不要设置请求头

    设置一个processData为false,表示query不要修改数据格式

    <form action="javascript:;">
        <input type="file" name="avatar">
        <input type="text" name="username">
        <br>
        <input type="button" value="上传"></form>

    我们可以在new的时候,将表单元素放在构造函数中 - 默认能将表单中的数据,添加到这个对象中

    $('[type="button"]').click(function()
        var fd = new FormData($('form')[0])
    
        $.ajax({
            url:"2-upload.php",
            method:"post",
             jquery上传用 FormData
            data:fd,
            contentType:false,  不让jQuery的ajax修改请求头
            processData:false,  不让jquery的ajax编码数据        success:res=>{
                console.log(res);
            }
            
        })})

    webWorker

    大量运算的代码,可以作为一个异步线程执行
    需要将这段代码单独放在一个文件中
    需要new一个worker对象 - 这个构造函数需要在服务器环境中运行

    woker需要一个事件,当文件完成以后获取里面的数据
    可以在事件中,接收到文件中导出的数据

    woker.onmessage = function(e){
        数据就在事件对象的data属性中
        console.log(e.data);}

    当业务逻辑需要的计算量比较大的时候,同步代码会阻塞下面的代码继续执行,此时需要将这个大计算量的代码另外开辟一个新的线程进行执行,这个线程也是异步执行的,但需要将在新线程中执行的代码单独放在一个js文件中,使用方式:

    var w = new Worker(需要异步执行的js文件)

    如果在主线程中需要这个线程中返回的数据,在这个线程中使用postMessage来返回:

    postMessage(数据)

    主线程中接收返回出来的数据:

    w.onmessage = function(e){
        e.data // 是异步线程中返回出来的数据}

    离线缓存

    离线缓存的作用:在马上断网之后,依旧可以访问到缓存下来的文件。比较鸡肋。该技术在2020年8月已经被弃用了。

    使用方式:

    使用规则        1. 需要你自定义一个 .manifest 文件        2. 再你书写 html 文件的时候
              => 如果这个 html 文件需要缓存规则
              => 再 html 标签上添加一个 manifest 属性
              => 值就写你的缓存规则文件        3. 第一次打开页面的时候
              => 就会按照你书写的缓存规则去缓存文件

    例:

    第一行必须要写上
    CACHE MANIFEST
    以注释的形式书写一个版本号
    app version 1.0

    表示你要缓存的文件
    CACHE:
    ./index.html
    ./css/index.css

    表示必须需要网络环境才可以请求的文件
    一般我们会书写 星号(*), 表示除了 CACHE 里面书写的文件, 其他的去过没有网络环境就报错
    NETWORK:
    *

    当你再一个离线环境下访问一些没有的页面的时候
    使用一个什么内容替代
    FALLBACK:


    事件循环面试题:

    <script>console.log(1)setTimeout(()=>{ console.log(2) },0) new Promise(resolve=>{
        console.log(3)
        resolve()}).then(()=>{ 
        console.log(4)})setTimeout(()=>{ 
        console.log(5)
        new Promise(resolve=>{
            console.log(6)
            setTimeout(()=>{ 
                console.log(7)
            })
            resolve()
        }).then(()=>{ 
            console.log(8)
        })},500)new Promise(resolve=>{
        console.log(9)
        resolve()}).then(()=>{ 
        console.log(10)
        setTimeout(()=>{ 
            console.log(11)
        },0)})console.log(12)</script>

    答案:1 3 9 12 4 10 2 11 5 6 8 7

    更多编程相关知识,请访问:编程视频!!

    以上就是一个小时带你总结前端上传文件的方法(整理分享)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:CSDN,如有侵犯,请联系admin@php.cn删除
    专题推荐:前端
    上一篇:javascript中function的用法是什么 下一篇:JavaScript经典讲解之设计模式(实例详解)
    Web大前端开发直播班

    相关文章推荐

    • 总结分享一些基于Node.js的前端面试题(附解析)• 编程中的前端和后端是什么• 前端怎么调用后台tp6验证码• php 怎么实现前端统计流量• vue怎样解决axios请求出现前端跨域问题(实例详解)

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网