【问题标题】:How to upload files one by one using javascript如何使用javascript逐个上传文件
【发布时间】:2021-08-21 11:54:45
【问题描述】:

我正在开发一个文件上传器,我希望我的用户能够同时上传多个文件,并且一个接一个地上传多个文件。我看到很多其他页面都有类似的问题,但没有一个能解决我的问题。

这是我的 html 上传表单:

<form id="myform" action="upload.php" method="post" enctype="multipart/form-data" >
  <h3>Upload File</h3>
  <input type="file" name="myfile[]" id="uploadFile" multiple> 
  <button type="submit" id="mySubmitButton" onclick="saveData()" name="save">UPLOAD</button>
</form>

我认为 FormData 是适合我的情况的正确方法,但我不确定。我想制作一个文件数组并通过 PHP 文件将它们发送到服务器。我真的不想用ajax。

这是我的 Javascript 代码:

<script>

function saveData(){
  formData.getAll("myfile[]");
}

$('#uploadFile').on('change', function() {
  var formData = new FormData();
  var files = $('#uploadFile')[0].files;
  for (var i = 0; i < files.length; i++) {
    formData.append('myfile[]', document.getElementById('uploadFile').files[i]);
  }    
});

</script>

这行不通。现在我只上传最后选择的文件。希望您能帮助我,在此先感谢!

【问题讨论】:

  • 当您说 "multiple files one by one" 时,这意味着顺序(选择所有并上传 1,2,3...)还是单独(选择文件 -> 上传,选择另一个 -> 上传等)?
  • 我想按顺序上传文件,所以,选择文件->选择另一个->选择另一个->上传。现在,如果我按顺序选择文件,只会上传最后一个文件,因为它会覆盖当前选择。
  • 好的 - 有道理,但 FormData 使用没有 - 如果你不使用 Ajax,你将如何使用它?
  • Ajax 的解决方案是什么样的?

标签: javascript php form-data


【解决方案1】:

试着改成这样:

$('#uploadFile').on('change', function() {
  var formData = new FormData();
  var files = $('#uploadFile').files;
  for (var i = 0; i < files.length; i++) {
    formData.append('myfile[]', files[i]);
  }    
});

【讨论】:

  • 这仍然只上传最后选择的文件 :(,谢谢。
【解决方案2】:

一般的想法是创建一个全局变量(或者可能在匿名函数的范围内)并将每个新选择的文件添加到该数组中。单击按钮时,通过发送 ajax 请求上传文件来处理此数组。通过使用Promises,您可以让用户知道所有文件何时已上传。

sn-p 在这里不起作用,因为没有 PHP 来处理请求,但完整的示例可以正常工作。

// keep track of selected files in this array
let files=[];
let promises=[];

// various form elements
const form=document.forms.uploader;
const bttn=form.save;
const input=form.querySelector('input[name="myfile[]"]');

// event handler to add selcted files to array - one or more at a time
input.addEventListener('change',function(e){
  for( let i=0; i < this.files.length; i++ ) files.push( this.files[i] );
});


// event handler to process button click. Ajax request sent using Fetch
// result echoed to console only
bttn.addEventListener('click',function(e){
  e.preventDefault();

  let fd=new FormData();

  // create a new Promise for each file and upload. Resolve on success
  files.forEach( file =>{
    console.info( 'Promise to upload:%s', file.name )
    /*
    fd.set('file',file);

    promises.push( new Promise((resolve,reject)=>{
      fetch( form.action, { method:'post', body:fd } )
      .then( r=>r.json() )
      .then( json=>resolve( json ) )
      .catch( err=>reject( err ) )                    
    }))
    */
  })

  // process all files and display results
  /*
  Promise.all( promises )  
  .then( results=>console.log(results) )
  .catch( err=>alert(err) )
  */
});
<!-- form action removed for testing only -->
<form name='uploader' action='' method='post'><!-- upload.php -->
  <h3>Upload File</h3>
  <input type='file' name='myfile[]' multiple /> 
  <button type='submit' name='save'>UPLOAD</button>
</form>

单页完整示例:

<?php
    if( $_SERVER['REQUEST_METHOD']=='POST' ){
        ob_clean();
        
        $savepath=sprintf('%s/uploads',__DIR__);

        if( !empty( $_FILES['file'] ) ){
            $obj=(object)$_FILES['file'];
            $tmp=$obj->tmp_name;
            $name=$obj->name;
            $size=$obj->size;
            $type=$obj->type;
            $error=$obj->error;
            
            if( $error==UPLOAD_ERR_OK ){
                $targetfile=sprintf('%s/%s',$savepath,$name);
                $bytes=move_uploaded_file($tmp,$targetfile);
                
                $data=array(
                    'name'  =>  $name,
                    'size'  =>  $size,
                    'type'  =>  $type,
                    'bytes' =>  $bytes,
                    'file'  =>  $targetfile
                );
                exit( json_encode( $data ) );               
            }
            

        }
        exit();
    }
?>

<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title></title>
    </head>
    <body>
    
        <!-- form action removed for testing only -->
        <form name='uploader' action='' method='post'><!-- upload.php -->
            <h3>Upload File</h3>
            <input type='file' name='myfile[]' multiple /> 
            <button type='submit' name='save'>UPLOAD</button>
        </form>
    
        <script>
            
            // keep track of selected files in this array
            let files=[];
            let promises=[];
            
            // various form elements
            const form=document.forms.uploader;
            const bttn=form.save;
            const input=form.querySelector('input[name="myfile[]"]');
            
            // event handler to add selcted files to array - one or more at a time
            input.addEventListener('change',function(e){
                for( let i=0; i < this.files.length; i++ ) files.push( this.files[i] );
            });
            
            
            // event handler to process button click. Ajax request sent using Fetch
            // result echoed to console only
            bttn.addEventListener('click',function(e){
              e.preventDefault();
              
              let fd=new FormData();
              
              // create a new Promise for each file and upload. Resolve on success
              files.forEach( file =>{
                  console.info( 'Promise to upload:%s', file.name )
                  fd.set('file',file);
                  
                  promises.push( new Promise((resolve,reject)=>{
                      fetch( form.action, { method:'post', body:fd } )
                        .then( r=>r.json() )
                        .then( json=>resolve( json ) )
                        .catch( err=>reject( err ) )                      
                  }))
                  
              })
              
              // process all files and display results
              Promise.all( promises )  
                .then( results=>{ console.log(results);files=[];} )
                .catch( err=>alert(err) )
            });
        </script>
    </body>
</html>

【讨论】:

  • 感谢您的回答!我可以在控制台中看到承诺,但上传按钮仍然被禁用。你知道为什么会这样吗?
  • 该按钮不能被禁用,否则您最初将无法发送请求。
  • 你是对的,对不起。上传文件不起作用。我在控制台中收到此错误: Uncaught (in promise) SyntaxError: Unexpected token
  • 您在使用发布的代码时遇到特定错误 - 包括 PHP?如果是 - 您是否修改了 savepath 以适应您的环境?
  • 有没有办法将“文件”数组值放入文件输入(表单)而不是控制台?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 2015-07-06
  • 2016-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-11
相关资源
最近更新 更多