- A+
首先我们使用composer安装:
composer require phpoffice/phpspreadsheet
然后建立一个抽象的工具类Export并为其创建单例类:
namespace app\common\tool; abstract class Export { private static $instance = []; /** * @return static */ public static function getInstance() { $class = get_called_class(); if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){ self::$instance[$class] = new static(); } return self::$instance[$class]; } }
然后我们定义3个方法,分别定义文件的标题(sheet)名,文件的后缀格式以及表头是否加粗显示:
定义标题:
public function setFileTitle() : string { return 'sheet'; }
定义文件后缀格式:
public function setFileFormat() : string { return 'Xlsx'; }
定义表头是否加粗:
public function setFileHeaderBold(): bool { return true; }
定义两个抽象方法要求子类必须实现:
定义表头的内容:
abstract public function setFileHeader(): array ;
定义文件的名称:
abstract public function setFileName(): string ;
我们来实现导出的功能:
public function export($datas) { $spreadsheet = new Spreadsheet(); //设置当前的sheet对象 并获取 sheet $worksheet = $spreadsheet->setActiveSheetIndex(0); $startRow = 1; $fields = []; foreach ($this->setFileHeader() as $key => $headers){ $startCell = 1; foreach ($headers as $column => $header){ //表头中设置text的属性 if(isset($header['text'])){ //获取当前要做成的单元格对象 $nowColumn = $this->getNowColumn($worksheet, $startCell, $startRow); $worksheet->setCellValue($nowColumn, $header['text']); //设置单元格的宽度 if(isset($header['width'])){ $worksheet->getColumnDimension(Coordinate::stringFromColumnIndex($startCell))->setWidth($header['width']); } //设置表头加粗 $worksheet->getStyle($nowColumn)->getFont()->setBold($this->setFileHeaderBold()); //设置水平居中 if(isset($header['align'])){ $worksheet->getStyle($nowColumn)->getAlignment()->setHorizontal($header['align']); }else{ $worksheet->getStyle($nowColumn)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); } //设置垂直居中 $worksheet->getStyle($nowColumn)->getAlignment()->setVertical(Alignment::VERTICAL_CENTER); //设置背景颜色 if(isset($header['bgColor'])){ $worksheet->getStyle($nowColumn)->getFill()->setFillType(Fill::FILL_SOLID) ->getStartColor()->setARGB($header['bgColor']); } //设置文字颜色 if(isset($header['fontColor'])){ $worksheet->getStyle($nowColumn)->getFont()->getColor()->setARGB($header['fontColor']); } //合并列 if(isset($header['colspan']) && $header['colspan'] >= 2){ $mergeCells = $nowColumn.':'.Coordinate::stringFromColumnIndex($startCell + $header['colspan'] - 1).$startRow; $worksheet->mergeCells($mergeCells); $startCell = $startCell + $header['colspan'] -1; } //合并行 if(isset($header['rowspan']) && $header['rowspan'] >= 2){ $mergeCells = $nowColumn.':'.Coordinate::stringFromColumnIndex($startCell).($startRow + $header['rowspan'] - 1); $worksheet->mergeCells($mergeCells); } } //field在datas中存在,用于取数据 if(isset($header['field'])){ $fields[] = $header['field']; } $startCell++; } $startRow++; } //设置sheet标题 $worksheet->setTitle($this->setFileTitle()); //输出内容到sheet foreach ($datas as $key => $data){ $row = $startRow + $key; foreach ($fields as $index => $field){ //如果存在getFieldNameAttr()则调用,实现字段的判断 $method = 'get'.ucfirst(Loader::parseName($field, 1)).'Attr'; if(method_exists($this, $method)){ $value = $this->$method(...[$field, $data]); }else if(isset($data[$field])){ //存在取值 $value = $data[$field]; }else{ //不存在留空 $value = ''; } //设置单元格值 $worksheet->setCellValue(Coordinate::stringFromColumnIndex($index + 1).$row, $value); } } $this->downloadExcel($spreadsheet, $this->setFileName(), $this->setFileFormat()); }
获取当前单元格的位置:
private function getNowColumn($worksheet, &$startCell, $startRow) { $nowColumn = Coordinate::stringFromColumnIndex($startCell).$startRow; if(!$this->isMergeCell($worksheet, $nowColumn)){ return $nowColumn; } $startCell++; return $this->getNowColumn($worksheet, $startCell, $startRow); }
判断当前单元格是否合并的状态:
private function isMergeCell($worksheet, $nowColumn) { foreach ($worksheet->getMergeCells() as $cells) { if ($worksheet->getCell($nowColumn)->isInRange($cells)) { return true; } } return false; }
下载文件的方法:
private function downloadExcel($spreadsheet, $fileName, $format) { header("Content-Type:application/octet-stream"); if ($format == 'Xlsx') { header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); } elseif ($format == 'Xls') { header('Content-Type: application/vnd.ms-excel'); } header("Content-Disposition: attachment;filename=" . $fileName. '.' . strtolower($format)); header('Cache-Control: max-age=0'); $writer = IOFactory::createWriter($spreadsheet, $format); $writer->save('php://output'); exit; }
我们来实现一个具体的导出,如用户导出:
首先建立UserExport:
namespace app\common\tool\export; use app\common\tool\Export; class UserExport extends Export { public function setFileHeader(): array { return [ [ ['field' => 'user_name', 'text' => '用户名', 'width' => 60, 'bgColor' => '67834B', 'fontColor' => 'FFFFFF'] ] ]; } public function setFileName(): string { return 'userData'.date("Ymd"); } }
高级用法:
public function setFileHeader(): array { return [ [ ['text' => '用户信息', 'width' => 20, 'rowspan' => 2], ['text' => '其他信息', 'colspan' => 5, 'bgColor' => '0589FA'], ], [ ['field' => 'mem_name','text' => '姓名'], ['field' => 'telephone', 'text' => '电话', 'width' => 25], ['field' => 'city', 'text' => '城市'], ] ]; }
设置字段的值:
public function getTelephoneAttr($key, $data) { return $data['telephone']; //手机号隐藏中间的四位处理 }