前言
最近在做一个的一个项目(Yii2.0 + vue 2.5)有一个Excel导出的需求,分别用前后端的方法来生成,这里对比一下两者的差异
后端生成
一开始我是不知道前端也可以把数据直接生成Excel下载的,所以第一个想法就是直接用PHP的插件来完成这个事情,以前用过phpExcel,上GitHub搜索的时候发现,作者15年就开始不再维护这个项目了,而是转而去做另外一个叫PhpSpreadsheet的项目,其实也是可以做Excel的各种操作,composer下来
这里需要注意fileinfo的扩展才能正确安装上
第一种,直接保存文件在服务器
然后写了这么一个类,大概使用方法就是在head里面指定了字段,会从data里面找到合适的字段分别写到Excel里面去,然后保存在服务器里面,再返回给前端一个连接,前端就只需要window.open(line)就OK了,很简单
<?php
namespace common\libs;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
/**
* excel类
*/
class Excel
{
public function save($data, $head, $name = '')
{
if (empty($data)) {
return false;
}
$spreadsheet = new Spreadsheet();
try {
$sheet = $spreadsheet->getActiveSheet();
$j = 65;
foreach ($head as $item) {
$str = chr($j) . '1';
$sheet->setCellValue($str, $item);
$j++;
}
$i = 2;
foreach ($data as $v) {
$j = 65;
// 这里主要是拿头的的key,用于匹配上合适的字段
foreach ($head as $k => $item) {
// 从A开始
$str = chr($j) . $i;
$sheet->setCellValue($str, $v[$k]);
$j++;
}
$i++;
}
$writer = new Xlsx($spreadsheet);
$dir = 'assets/excel';
is_dir($dir) OR mkdir($dir, 0777, true);
$fileName = $dir . '/' . time() . rand(000001, 999999) . '.xlsx';
$writer->save($fileName);
return $fileName;
} catch (\Exception $e) {
\Yii::error($e);
return false;
}
}
}
第二种,生成文件流(也需要前端配合)
这种方式,首先后端的生成Excel基本上是没有改变的, 然后最后保存的那也改一下
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
exit;
这里返回到前端的会是这样一个形式
所以我们在前端请求的方法里面就需要注意告诉这是一个bolb对象
axios({
// 用axios发送post请求
method: 'get',
url: 'access/load-search-list', // 请求地址
params: data, // 参数
responseType: 'blob', // 表明返回服务器返回的数据类型
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
this.loading = false
const content = res.data
const blob = new Blob([content])
const fileName = '导出信息.xlsx'
if ('download' in document.createElement('a')) {
// 非IE下载
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // 释放URL 对象
document.body.removeChild(elink)
} else {
// IE10+下载
navigator.msSaveBlob(blob, fileName)
}
})
前端直接生成
因为我项目用的是d2admin,发现是可以直接在前端生成Excel直接下载的,看了一下代码,十分简单
引入插件
yarn add @d2-projects/vue-table-export
main.js 使用
import pluginExport from '@d2-projects/vue-table-export'
Vue.use(pluginExport)
代码使用
首先定义好表头,label是你需要在表头里面显示的字段,然后data里面必须含有prop的字段,然后就可以了,很简单
const columns = [
{
prop: 'id',
label: 'id'
},
{
prop: 'url',
label: '落地页'
},
{
prop: 'word',
label: '搜索词'
},
{
prop: 'ip',
label: 'ip'
},
{
prop: 'area',
label: '地区'
},
{
prop: 'addTime',
label: '时间'
}
]
this.$export
.excel({
columns,
data: data
})
.then(() => {
this.$message('导出表格成功')
})
差异
后端生成更稳定
一般我们做Excel导出的时候,会数据量有可能比较大,数据量如果太大,传输到前端的时候,会对浏览器的性能有一定要求,但是如果是后端生成,只需要给前端一个链接用于下载就可以了
前端生成不占用空间
后端生成需要在服务器生成一个文件,而前端则不用,直接就可以在浏览器生成Excel了
后端可以做文件缓存
一般我们导出一个Excel,这个Excel可能是有固定性的,譬如上个月的某个数据,这个数据是固定的,也就是说,我只要生成一遍以后,以后无论是谁,需要是要这个Excel,我可以直接给链接,而不用到数据库里面去查询,而前端则不行,你每次都需要查询数据库(当然你也可以把数据缓存下来,但是这样就失去了前端生成的意义了,缓存的文件也会很大)
总结
最后我还是选用了前端直接生成的方法,其实这个是和我项目有关系的,我的项目里面每次需要的数据不算很大,而且我还有查询的语句,我后端不需要做很大的修改就可以了,如果在后端生成(无论是文件还是文件流),我后端代码和前端代码都需要做很大的修改