- 后端
【免费下载链接】PHPWord
A pure PHP library for reading and writing word processing documents
本文基于 PHPWord 官方文档 docs/usage/elements/table.md 展开,系统讲解在 Section 中创建表格、行、单元格的核心 API,以及通过addTableStyle定义可复用表格样式、通过gridSpan与vMerge实现跨列与跨行合并的完整用法。读完本文,你将能够在 PHPWord 中从零构建基础表格、精致样式表格、合并单元格表格、嵌套表格与浮动定位表格,并理解其底层实现原理。
一、表格的创建:addTable / addRow / addCell
在 PHPWord 中,表格是挂在 Section 之下的容器元素,由「表格 → 行 → 单元格」三层结构组成。创建一张表格只需三个方法调用:
<?php $table = $section->addTable([$tableStyle]); $table->addRow([$height], [$rowStyle]); $cell = $table->addCell($width, [$cellStyle]);$section->addTable($style):向当前 Section 添加一个表格。$style既可以传入内联样式数组,也可以传入已注册的样式名称(字符串),不传则使用默认样式。$table->addRow($height, $style):添加一行,$height指定行高(单位 twip),$style为行样式数组。$table->addCell($width, $style):添加单元格,$width为单元格宽度(单位 twip),$style为单元格样式数组。
从源码看,Table::addRow() 会创建Row对象并设置其父容器为表格;Table::addCell() 则将单元格挂到当前(最后添加的)行上。单元格继承自AbstractContainer(见 Element/Cell.php),因此addCell()的返回值可以直接调用addText()、addImage()等容器方法写入内容,形成$table->addCell($width)->addText('...')的链式写法。
基础表格示例
<?php $phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $rows = 10; $cols = 5; $table = $section->addTable(); for ($r = 1; $r <= $rows; ++$r) { $table->addRow(); for ($c = 1; $c <= $cols; ++$c) { $table->addCell(1750)->addText("Row {$r}, Cell {$c}"); } }以上代码生成一张 10 行 5 列、每列宽 1750 twip 的基础表格,完整可运行版本见 samples/Sample_09_Tables.php 的第 1 节。
二、用 addTableStyle 定义可复用表格样式
当同一张表格样式需要被多次使用(例如整套文档统一边框与表头底色)时,推荐先用PhpWord::addTableStyle()注册命名样式,再通过样式名引用:
<?php $tableStyle = array( 'borderColor' => '006699', 'borderSize' => 6, 'cellMargin' => 50 ); $firstRowStyle = array('bgColor' => '66BBFF'); $phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); $table = $section->addTable('myTable');addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null)的三个参数分别是:样式名称、表格样式数组、首行样式数组(可选)。从 PhpWord::addTableStyle() 的方法签名可以看到,首行样式是独立于表格样式传入的。
其底层实现位于 Style/Table.php 的构造函数:当传入$firstRowStyle时,会先克隆当前表格样式,禁用边框内部线(borderInside*)、单元格边距(cellMargin*)与cellSpacing等「仅表格层生效」的属性(对应 getTableOnlyProperty / setTableOnlyProperty 的保护逻辑),再套用首行样式。这意味着首行样式天然继承表格样式的外边框与底色基调,只需覆盖需要差异化的属性即可。
进阶:首行 + 单元格样式组合
samples/Sample_09_Tables.php第 2 节给出了更完整的组合用法,将表格样式、首行样式、单元格样式、字体样式四层叠加:
<?php $fancyTableStyleName = 'Fancy Table'; $fancyTableStyle = [ 'borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50, ]; $fancyTableFirstRowStyle = [ 'borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF', ]; $fancyTableCellStyle = ['valign' => 'center']; $fancyTableCellBtlrStyle = [ 'valign' => 'center', 'textDirection' => PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR, ]; $fancyTableFontStyle = ['bold' => true]; $phpWord->addTableStyle($fancyTableStyleName, $fancyTableStyle, $fancyTableFirstRowStyle); $table = $section->addTable($fancyTableStyleName); $table->addRow(900); $table->addCell(2000, $fancyTableCellStyle)->addText('Row 1', $fancyTableFontStyle); // ... 其余单元格同理这里alignment使用的是表格专用的对齐枚举JcTable(start/center/end,见 SimpleType/JcTable.php),textDirection则来自Style\Cell的常量TEXT_DIR_BTLR(自底向上、从左到右的文字方向,见 Style/Cell.php)。
三、表格、行、单元格的完整样式参数
表格级样式(Table)
完整的表格样式选项在 docs/usage/styles/table.md 中定义,对应源码类为 Style/Table.php,其继承自Border,因此边框类参数全部可用:
| 参数 | 说明 | 取值/示例 |
|---|---|---|
alignment | 表格对齐方式 | 见SimpleType\JcTable与SimpleType\Jc类常量(start/center/end等) |
bgColor | 表格背景色 | 如'9966CC' |
border(Top\|Right\|Bottom\|Left)Color | 各边边框颜色 | 如'9966CC' |
border(Top\|Right\|Bottom\|Left)Size | 各边边框粗细,单位 twip | 整数 |
cellMargin(Top\|Right\|Bottom\|Left) | 单元格边距,单位 twip | 整数 |
indent | 表格相对左页边距的缩进 | 必须是ComplexType\TblWidth实例 |
width | 表格宽度 | 以五十分之一百分比(pct)或二十分之一磅(dxa/twip)为单位 |
unit | 宽度单位 | SimpleType\TblWidth常量之一,默认auto |
layout | 表格布局 | fixed或autofit(Style\Table::LAYOUT_AUTO/LAYOUT_FIXED,见 Style/Table.php) |
cellSpacing | 单元格间距,单位 twip | 整数 |
position | 浮动表格定位 | 见下文「浮动表格定位选项」 |
bidiVisual | 以从右到左方式呈现表格 | 布尔值 |
宽度单位枚举见 SimpleType/TblWidth.php:nil(无宽度)、auto(自动计算,默认)、pct(五十分之一百分比)、dxa(二十分之一磅,即 twip)。设置百分比宽度时需自行换算:50% 写成50 * 50(=2500),示例见Sample_09_Tables.php第 5 节:['width' => 50 * 50, 'unit' => 'pct', 'alignment' => JcTable::CENTER]。
表格布局枚举LAYOUT_AUTO(autofit,默认)与LAYOUT_FIXED(fixed)定义于 Style/Table.php,对应 OOXML 标准w:tblLayout的两种取值。
浮动表格定位选项(position)
当表格需要脱离文档流、环绕于文字周围时,使用position数组开启浮动定位:
| 参数 | 说明 | 取值 |
|---|---|---|
leftFromText | 表格左侧距文字的距离,twip | 整数 |
rightFromText | 表格右侧距文字的距离,twip | 整数 |
topFromText | 表格顶部距文字的距离,twip | 整数 |
bottomFromText | 表格底部距文字的距离,twip | 整数 |
vertAnchor | 表格垂直锚点 | Style\TablePosition::VANCHOR_*常量 |
horzAnchor | 表格水平锚点 | Style\TablePosition::HANCHOR_*常量 |
tblpXSpec | 相对锚点的水平对齐 | Style\TablePosition::XALIGN_*常量 |
tblpX | 距锚点的绝对水平距离,twip | 整数 |
tblpYSpec | 相对锚点的垂直对齐 | Style\TablePosition::YALIGN_*常量 |
tblpY | 距锚点的绝对垂直距离,twip | 整数 |
Sample_09_Tables.php第 6 节演示了结合Converter::cmToTwip()做单位换算的浮动表格:
<?php use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style\TablePosition; $table = $section->addTable([ 'borderSize' => 6, 'borderColor' => '999999', 'position' => [ 'vertAnchor' => TablePosition::VANCHOR_TEXT, 'bottomFromText' => Converter::cmToTwip(1), ], ]);行级样式(Row)
行样式定义于 Style/Row.php,共三个布尔开关:
| 参数 | 说明 | 默认 |
|---|---|---|
cantSplit | 行不允许跨页断开 | false |
exactHeight | 行高为精确值(否则为「至少」高度) | false |
tblHeader | 跨页时重复表头行 | false |
其中tblHeader用于长表格分页时每页顶部重复显示标题行,cantSplit保证一行内容不被拆到两页。需要说明的是,ODText 写入器将行高序列化为原生 ODF 表格行样式:精确高度使用style:row-height,「至少」高度使用style:min-row-height,见 docs/usage/styles/table.md。
单元格级样式(Cell)
单元格样式对应 Style/Cell.php,同样继承Border:
| 参数 | 说明 | 取值/示例 |
|---|---|---|
bgColor | 单元格背景色 | 如'9966CC' |
border(Top\|Right\|Bottom\|Left)Color | 各边边框颜色 | 如'9966CC' |
border(Top\|Right\|Bottom\|Left)Size | 各边边框粗细,twip | 整数 |
border(Top\|Right\|Bottom\|Left)Style | 边框线型 | SimpleType\Border常量 |
gridSpan | 跨列数(colspan) | 整数,如 5 |
textDirection(btLr\|tbRl) | 文字方向 | Style\Cell::TEXT_DIR_BTLR/TEXT_DIR_TBRL(源码中还支持lrTb、lrTbV、tbRlV、tbLrV等常量,见 Style/Cell.php) |
valign | 垂直对齐 | top、center、both、bottom |
vMerge | 纵向合并 | restart或continue |
width | 单元格宽度,twip | 整数 |
关于 ODText 写入器:单元格边框会被序列化为原生 ODF 表格单元格样式,各边独立写入,因此同一行内非对称边框、不同单元格的不同边框定义都能保留;表格与单元格的bgColor会映射为原生 ODF 背景色,单元格内边距、垂直对齐、文字方向、换行、列跨度、表格对齐与宽度在设置了对应样式时也会一并映射(见 docs/usage/styles/table.md)。
四、单元格合并:gridSpan 跨列、vMerge 跨行
表格合并单元格有两种方式:
gridSpan:让一个单元格横跨多列,即 HTML 中的colspan;vMerge:让单元格纵跨多行,即 HTML 中的rowspan,通过restart开启合并、continue延续合并实现。
gridSpan 跨列
文档给出的最简用法:
<?php $cell = $table->addCell(200); $cell->getStyle()->setGridSpan(5);也可以直接在单元格样式数组中声明(效果等价):
<?php $cell = $table->addCell(200, ['gridSpan' => 5]);在 Word2007 写入器中,gridSpan与vMerge会被序列化为 OOXML 的w:gridSpan与w:vMerge元素(见 Writer/Word2007/Style/Cell.php),保证生成的 docx 与 Word 原生合并行为一致。
vMerge 跨行
<?php $row1 = $table->addRow(); $row1->addCell(500)->addText('A'); $row1->addCell(1000, ['gridSpan' => 2])->addText('B'); $row1->addCell(500, ['vMerge' => 'restart'])->addText('C'); $row2 = $table->addRow(); $row2->addCell(1500, ['gridSpan' => 3])->addText('D'); $row2->addCell(null, ['vMerge' => 'continue']); // 延续 C 的合并 $row3 = $table->addRow(); $row3->addCell(500)->addText('E'); $row3->addCell(500)->addText('F'); $row3->addCell(500)->addText('G'); $row3->addCell(null, ['vMerge' => 'continue']); // 再次延续关键规则:
- 合并起始单元格写
'vMerge' => 'restart',后续行对应位置写'vMerge' => 'continue'; - 延续单元格通常不需要宽度,传
null即可; vMerge取值restart/continue对应 Style/Cell.php 中的VMERGE_RESTART与VMERGE_CONTINUE常量。
上述代码对应Sample_09_Tables.php第 3 节的布局示意:
------------------------- | A | B | C | |-----|-----------| | | D | | ------|-----------| | | E | F | G | | -------------------------Sample_09_Tables.php第 4 节还演示了 gridSpan 与 vMerge 同时作用于同一单元格(如['gridSpan' => 2, 'vMerge' => 'restart'])的复合合并,这是实现「先跨列再跨行」复杂表头布局的常用手法。
五、进阶场景:嵌套表格与 50% 宽度表格
表格单元格本身是容器(AbstractContainer),因此可以在单元格内再嵌表格。Sample_09_Tables.php第 5 节演示了嵌套表格与百分比宽度:
<?php use PhpOffice\PhpWord\SimpleType\JcTable; $table = $section->addTable([ 'width' => 50 * 50, // 50% 宽度(pct 单位下 ×50 换算) 'unit' => 'pct', 'alignment' => JcTable::CENTER, ]); $cell = $table->addRow()->addCell(); $cell->addText('This cell contains nested table.'); $innerCell = $cell->addTable([ 'alignment' => JcTable::CENTER, ])->addRow()->addCell(); $innerCell->addText('Inside nested table');嵌套时只需在单元格对象上再次调用addTable(),PHPWord 会自动维护父子容器关系;外层表格通过unit => 'pct'+width => 2500实现 50% 相对宽度并居中,内层表格同样居中展示。
六、从源码理解表格的数据结构与列宽计算
从源码结构看,PHPWord 的表格对象模型是纯内存树:
Element\Table持有rows数组,提供addRow()、addCell()、getRows()、countColumns()与findFirstDefinedCellWidths()等方法(见 Element/Table.php);Element\Row持有height与cells数组,addCell()创建Element\Cell(见 Element/Row.php);Element\Cell继承自AbstractContainer,宽度与样式在构造时注入(见 Element/Cell.php)。
值得留意的是countColumns()的实现:它遍历所有行并取「最大单元格数」作为列数,而findFirstDefinedCellWidths()则按行序收集第一处定义了宽度的列宽序列(见 Element/Table.php)。这说明 PHPWord 允许不同行的单元格数量不一致,最终列宽由各列单元格宽度协调决定——这也正是合并单元格场景下null宽度(延续格)能被正确推算的原因。
七、运行示例与深入阅读
Sample_09_Tables.php可在仓库根目录直接通过命令行或浏览器运行:
php samples/Sample_09_Tables.php它依次输出基础表格、Fancy Table、colspan/rowspan 合并表格、嵌套表格与浮动定位表格,是本文全部要点的可运行合集。
- 核心文档:docs/usage/elements/table.md、docs/usage/styles/table.md
- 完整示例:samples/Sample_09_Tables.php
- 元素实现:src/PhpWord/Element/Table.php、src/PhpWord/Element/Row.php、src/PhpWord/Element/Cell.php
- 样式实现:src/PhpWord/Style/Table.php、src/PhpWord/Style/Row.php、src/PhpWord/Style/Cell.php
- 枚举定义:src/PhpWord/SimpleType/JcTable.php、src/PhpWord/SimpleType/TblWidth.php
- OOXML 序列化:src/PhpWord/Writer/Word2007/Style/Cell.php
- 后端
【免费下载链接】PHPWord
A pure PHP library for reading and writing word processing documents
相关推荐
Bodyguard安全考量:防止权限提升攻击的10个关键防御策略
Bodyguard安全考量:防止权限提升攻击的10个关键防御策略 Bodyguard是Phoenix应用中用于权限控制的强大工具,但如果不正确使用,可能导致严重
PHPWord表格操作终极指南:10个高级技巧实现复杂单元格布局
PHPWord表格操作终极指南:10个高级技巧实现复杂单元格布局 PHPWord作为一款强大的PHP文档处理库,能够轻松实现Word文档的创建和编辑功能。在前1
后端ReactQuill 实现表格编辑:合并单元格与样式定制完全指南
ReactQuill 实现表格编辑:合并单元格与样式定制完全指南 痛点直击:富文本编辑器表格功能的三大困境 你是否在使用ReactQuill开发时遇到这些表格操
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考