Skip to content

在使用 mk-j/php_xlsxwriter 库时,markMergedCell 方法用于标记需要合并的单元格。以下是一个详细的示例,展示如何正确使用 markMergedCell 方法来合并单元格:

示例代码 ​

php
<?php

require 'vendor/autoload.php';

use XLSXWriter;

// 创建一个新的 XLSXWriter 实例
$writer = new XLSXWriter();

// 设置表头
$header = ['姓名', '年龄', '城市'];
$writer->writeSheetHeader('Sheet1', $header);

// 数据
$data = [
    ['张三', 25, '北京'],
    ['张三', 25, '北京'],
    ['李四', 30, '上海'],
    ['李四', 30, '上海'],
    ['王五', 22, '广州'],
    ['王五', 22, '广州'],
];

// 记录需要合并的单元格范围
$mergeRanges = [];

// 遍历数据并写入单元格
$prevRow = null;
$startRow = 1; // 从第二行开始(第一行是表头)
foreach ($data as $index => $row) {
    $currentRow = $index + 1; // 当前行号(从1开始)

    // 如果当前行与前一行相同,则记录合并范围
    if ($prevRow && $row === $prevRow) {
        $mergeRanges[] = ['A' . $startRow . ':A' . $currentRow, 'B' . $startRow . ':B' . $currentRow, 'C' . $startRow . ':C' . $currentRow];
    } else {
        // 如果当前行与前一行不同,则更新起始行
        $startRow = $currentRow;
    }

    // 写入当前行数据
    $writer->writeSheetRow('Sheet1', $row);

    // 更新前一行
    $prevRow = $row;
}

// 合并单元格
foreach ($mergeRanges as $range) {
    foreach ($range as $cellRange) {
        list($startCell, $endCell) = explode(':', $cellRange);
        list($startCol, $startRow) = parseCell($startCell);
        list($endCol, $endRow) = parseCell($endCell);
        $writer->markMergedCell('Sheet1', $startRow, $startCol, $endRow, $endCol);
    }
}




// 设置 HTTP 头,告诉浏览器这是一个文件下载
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="example.xlsx"');
header('Cache-Control: max-age=0');

// 输出文件内容
$writer->writeToStdOut();
exit();

/**
 * 解析单元格引用(如 A1)为列和行的索引
 *
 * @param string $cell 单元格引用(如 A1)
 * @return array 列和行的索引(如 [0, 1])
 */
function parseCell($cell) {
    preg_match('/([A-Z]+)(\d+)/', $cell, $matches);
    $col = $matches[1];
    $row = (int)$matches[2] - 1; // 行索引从0开始

    // 将列字母转换为列索引
    $colIndex = 0;
    $len = strlen($col);
    for ($i = 0; $i < $len; $i++) {
        $colIndex = $colIndex * 26 + ord($col[$i]) - ord('A') + 1;
    }
    $colIndex -= 1; // 列索引从0开始

    return [$colIndex, $row];
}



/**
 * 计算单元格合并
   * @param $data 数据
   * @param $rules 合并规则  一行数据 下标设置  ['0','0,1','0,1,2']; 第一列 一样合并 第二列 0,1 下标数据一样合并
   * @return array
   * @author Lenovo
   * @date 2024/10/30 下午3:43
   */
function getMergeList($data,$rules)
{
   $rowIndex = count($data[0]);
   $mergeRanges = [];
   for ($index = 0;$index < $rowIndex;$index++)
   {
      $startIndex = 0;
      foreach ($data as $key => $row)
      {
            $rule = isset($rules[$index]) ? $rules[$index] : false;
            if($rule !== false){
               $rule_key = explode(',', $rule);
               $childRow = '';
               foreach ($rule_key as $k) {
                  $childRow .= $row[$k];
               }
               if ($prevRow && $childRow === $prevRow) {
                  $mergeRanges[] = [$startIndex,$index,$key,$index];
               }else{
                  $startIndex = $key;
               }
               $prevRow = '';
               foreach ($rule_key as $k) {
                  $prevRow .= $row[$k];
               }
            }
      }
   }
   return $mergeRanges;
}

解释 ​

  1. 创建 XLSXWriter 实例:

    • 使用 new XLSXWriter() 创建一个新的 XLSXWriter 实例。
  2. 设置表头:

    • 使用 writeSheetHeader 方法设置表头。
  3. 数据:

    • 定义一个包含数据的数组 $data。
  4. 记录需要合并的单元格范围:

    • 创建一个数组 $mergeRanges 用于记录需要合并的单元格范围。
  5. 遍历数据并写入单元格:

    • 遍历数据数组 $data,并使用 writeSheetRow 方法写入每一行数据。
    • 如果当前行与前一行相同,则记录合并范围。
    • 如果当前行与前一行不同,则更新起始行。
  6. 合并单元格:

    • 使用 markMergedCell 方法合并单元格。
    • 使用 parseCell 函数将单元格引用(如 A1)解析为列和行的索引。
  7. 设置 HTTP 头:

    • 使用 header 函数设置 HTTP 头,告诉浏览器这是一个文件下载。
  8. 输出文件内容:

    • 使用 writeToStdOut 方法将文件内容输出到标准输出(浏览器)。

总结 ​

通过手动解析单元格引用并使用 markMergedCell 方法,你可以在 php_xlsxwriter 中实现合并单元格的功能。这种方法适用于需要合并单元格的场景,如导出 Excel 报表时合并相同内容的单元格。确保合并单元格的逻辑和顺序正确,以避免单元格没有合并的问题。

woodlc