Laravel-excel: 如何:仅使用 ajax 保存 csv/xls 文件

创建于 2016-07-14  ·  12评论  ·  资料来源: Maatwebsite/Laravel-Excel

嗨,大家好,

我已经看到我们中的一些人试图从 ajax 请求中提供文件。 经过一番研究,我没有找到任何明确的解决方案。 调整其中的一些,我成功地从 Ajax 请求中导出了 csv 和 xls 数据。 问题是,如果文件类型是 xls,操作是不同的,因为编码的原因,所以有一些调整。

数据来自典型的 Eloquent 查询,转换为数组:

PHP

if(!empty(Input::get('exportType'))) { //i use a custom get parameter here
            $dd = Excel::create('testFileName', function($excel) use ($data) {
                $excel->sheet('testSheetName', function($sheet) use ($data) {
                    $sheet->fromArray($data->get()->toArray());
                });
                $excel->setTitle($filename);
                $excel->setLastModifiedBy(Carbon::now()->toDayDateTimeString()); //updated has Carbon::now() only now throw exception on vendor/phpoffice/phpexcel/Classes/PHPExcel/Writer/Excel5.php l847 strlen()
            });

            //tweak for serving XLS file from ajax (or go trough download() Excel method for csv files)
            if(Input::get('exportType') == 'xls') {
                $dd = $dd->string();
                $response =  array(
                    'filename' => 'testFileName', //as we serve a custom response, HTTP header for filename is not setted by Excel. From the JS, you need to retrieve this value if type is XLS to set filename
                    'file' => "data:application/vnd.ms-excel;base64,".base64_encode($dd)
                );
                return response()->success($response); //do a json encode
            } else {
                //direct use of Excel download method for non-xls files - xls files need special JS treatment
                $dd->download(Input::get('exportType')); //not XLS, so CSV (didnt tried xlsx, pdf is blank but not sure it's related to this)
            }
            die; //prevent malformed binary data stream, not sure if needed
        }

JS

$.ajax({
      cache: false,
      url: url, //GET route 
      responseType: 'ArrayBuffer', //not sure if needed
      data:  exportParam, //exportType parameter here
      success: function (data, textStatus, request) {

//you could need to decode json here, my app do it automaticly, use a try catch cause csv are not jsoned

        //already json decoded? custom return from controller so format is xls
        if(jQuery.isPlainObject(data)) {
          data = data.data; //because my return data have a 'data' parameter with the content
        }

        //V1 - http://stackoverflow.com/questions/35378081/laravel-excel-using-with-ajax-is-not-working-properly
        //+V3 - http://stackoverflow.com/questions/27701981/phpexcel-download-using-ajax-call
        var filename = "";
        var disposition = request.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
          var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
          var matches = filenameRegex.exec(disposition);
          if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
        }
        if(!jQuery.isPlainObject(data)) { //is CSV - we use blob
           var type = request.getResponseHeader('Content-Type');
           var blob = new Blob([data], { type: type ,endings:'native'});
           var URL = window.URL || window.webkitURL;
           var downloadUrl = URL.createObjectURL(blob);
        }
        var a = document.createElement("a");
        a.href = jQuery.isPlainObject(data) ? data.file : downloadUrl; 
        a.download = jQuery.isPlainObject(data) ? data.filename : filename;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

ps:这不是问题

最有用的评论

我需要从 ajax 返回一个 xlsx,所以我再次调整了一下,这就是我最终得到的结果:

PHP
$data 是一个转换为数组的 Eloquent 查询。

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

所有12条评论

非常感谢它适用于 CSV 但不适用于 xls ,

我需要从 ajax 返回一个 xlsx,所以我再次调整了一下,这就是我最终得到的结果:

PHP
$data 是一个转换为数组的 Eloquent 查询。

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

谢谢!!

我收到“找不到‘Excel’类”错误。你能帮帮我吗?

@randomhoodie任何来源您是如何提出该解决方案的?

@eldyvoon就像我说的那样,“我调整了”原始答案,去掉了我不需要的东西,使其紧凑,并为 ms office xlsx 扩展的 mime 类型使用了duckduckgo(搜索引擎),我不确定它是在我尝试之前会工作,但我在发布之前确实尝试过,并且因为它有效我发布了它,以防任何人会发现它有用。

我发现根本不需要 javascript 和 ajax。 我有一个带有链接的网页,可以下载一堆不同的 csv/xls/xlsx 文件,我根本不希望页面刷新。 我所做的只是将链接连接到返回以下内容的操作...

公共函数 getSpreadsheet() {
$items = Item::all();
Excel::create('items', function($excel) use($items) {
$excel->sheet('ExportFile', function($sheet) use($items) {
$sheet->fromArray($items);
});
})->导出('xls');
}

精彩!!!!

谢谢@randomhoodie!

对于 3.x 包,我会根据升级指南用这样的东西更新你的 PHP:

        $myFile = Excel::raw(new YOUR_Export_Class, \Maatwebsite\Excel\Excel::XLSX);

        $response =  array(
           'name' => "filename", //no extention needed
           'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
        );

        return response()->json($response);

谢谢@kynetiv ,我使用 3.x 版,但我需要将扩展​​名添加为:filename.xlsx

如果您在 2020 年仍然遇到此问题。请注意 Laravel excel 的 3.x 版已更改,因此这里是解决方案

  1. 通过 Ajax 将数据发送到与 Laravel Excel 对象交互的控制器
  2. 让 Laravel excel 对象将您的数据发送到刀片视图
  3. 将刀片视图存储在服务器上
  4. 使用js将文件下载到服务器上。
    所以这个想法是将刀片视图导出为 excel 并将其存储在磁盘位置,您可以在其中下载它
    javascript。

例子:

 $exports = new ReportsExporter($data, $columns);
  Excel::store($exports , 'filename.xlsx', 'custom_disk_location');

像这样在配置文件系统中定义您的自定义磁盘位置

'custom_disk_location' => [
            'driver' => 'local',
            'root' => public_path('files'),
        ],
...

这将确保 excel 文件不会保存在存储/应用程序中
但会将其保存在您服务器上的公共/文件路径中

回到你的javascript,像这样下载文件

function download(filename, path) {
        let element = document.createElement('a');
        element.setAttribute('href', path);
        element.setAttribute('download', filename);

        element.style.display = 'none';
        document.body.appendChild(element);

        element.click();

        document.body.removeChild(element);
    }

通过传递文件名和路径调用下载函数
下载(“文件名.xlsx”,location.origin+“文件/文件名.xlsx”);

下载后记得回到服务器并像这样删除存储在服务器上的那个
unlink("文件/文件名.xlsx");

我希望这可以帮助任何发现很难通过 ajax 或 javascript 下载 laravel-excel 的人。
这是一个更好的选择,因为它使您可以更灵活地自定义用户体验和
向他们提供有关下载状态以及以您喜欢的方式命名文件的反馈。

我需要从 ajax 返回一个 xlsx,所以我再次调整了一下,这就是我最终得到的结果:

PHP
$data 是一个转换为数组的 Eloquent 查询。

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

我需要从 ajax 返回一个 xlsx,所以我再次调整了一下,这就是我最终得到的结果:

PHP
$data 是一个转换为数组的 Eloquent 查询。

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

超好的

此页面是否有帮助?
0 / 5 - 0 等级