[{"data":1,"prerenderedAt":3449},["ShallowReactive",2],{"blog-zh-tables-in-go-pdfs":3},{"id":4,"title":5,"author":6,"body":10,"date":3411,"description":3412,"draft":3413,"extension":3414,"howTo":3415,"image":3439,"meta":3440,"navigation":488,"path":3441,"seo":3442,"stem":3443,"tags":3444,"updated":3439,"__hash__":3448},"blogZh/zh/blog/022.tables-in-go-pdfs.md","Go PDF 表格：列宽、斑马纹、分页头",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":3394},"minimark",[13,17,25,183,202,205,208,222,225,263,266,270,273,335,342,446,452,456,471,1588,1591,1606,1610,1620,1634,1640,1646,1685,1692,1723,1731,1735,1762,1772,1790,1793,1814,1826,1830,1833,1843,1869,1872,1893,1896,1902,1906,1911,2350,2387,2396,2405,2411,2414,2417,2478,2495,2501,2504,2698,2701,2704,2707,2845,2854,2866,2870,2873,3168,3171,3179,3182,3187,3211,3216,3239,3244,3247,3252,3265,3270,3280,3288,3294,3297,3304,3311,3314,3318,3321,3338,3350,3353,3390],[14,15,16],"h2",{"id":16},"一句话总结",[18,19,20,24],"p",{},[21,22,23],"strong",{},"表格是 PDF 生成里最容易翻车的部分。"," 加起来不对的列宽、第二页消失的表头、被行循环 off-by-one 画错的斑马纹。gpdf 把这一切折叠成一次调用：",[26,27,32],"pre",{"className":28,"code":29,"language":30,"meta":31,"style":31},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","c.Table(header, rows,\n    template.ColumnWidths(40, 15, 20, 25),\n    template.TableHeaderStyle(template.TextColor(pdf.White), template.BgColor(brand)),\n    template.TableStripe(pdf.RGBHex(0xF5F5F5)),\n)\n","go","",[33,34,35,67,102,151,177],"code",{"__ignoreMap":31},[36,37,40,44,48,52,55,58,61,64],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sTEyZ","c",[36,45,47],{"class":46},"sMK4o",".",[36,49,51],{"class":50},"s2Zo4","Table",[36,53,54],{"class":46},"(",[36,56,57],{"class":42},"header",[36,59,60],{"class":46},",",[36,62,63],{"class":42}," rows",[36,65,66],{"class":46},",\n",[36,68,70,73,75,78,80,84,86,89,91,94,96,99],{"class":38,"line":69},2,[36,71,72],{"class":42},"    template",[36,74,47],{"class":46},[36,76,77],{"class":50},"ColumnWidths",[36,79,54],{"class":46},[36,81,83],{"class":82},"sbssI","40",[36,85,60],{"class":46},[36,87,88],{"class":82}," 15",[36,90,60],{"class":46},[36,92,93],{"class":82}," 20",[36,95,60],{"class":46},[36,97,98],{"class":82}," 25",[36,100,101],{"class":46},"),\n",[36,103,105,107,109,112,114,117,119,122,124,127,129,132,135,138,140,143,145,148],{"class":38,"line":104},3,[36,106,72],{"class":42},[36,108,47],{"class":46},[36,110,111],{"class":50},"TableHeaderStyle",[36,113,54],{"class":46},[36,115,116],{"class":42},"template",[36,118,47],{"class":46},[36,120,121],{"class":50},"TextColor",[36,123,54],{"class":46},[36,125,126],{"class":42},"pdf",[36,128,47],{"class":46},[36,130,131],{"class":42},"White",[36,133,134],{"class":46},"),",[36,136,137],{"class":42}," template",[36,139,47],{"class":46},[36,141,142],{"class":50},"BgColor",[36,144,54],{"class":46},[36,146,147],{"class":42},"brand",[36,149,150],{"class":46},")),\n",[36,152,154,156,158,161,163,165,167,170,172,175],{"class":38,"line":153},4,[36,155,72],{"class":42},[36,157,47],{"class":46},[36,159,160],{"class":50},"TableStripe",[36,162,54],{"class":46},[36,164,126],{"class":42},[36,166,47],{"class":46},[36,168,169],{"class":50},"RGBHex",[36,171,54],{"class":46},[36,173,174],{"class":82},"0xF5F5F5",[36,176,150],{"class":46},[36,178,180],{"class":38,"line":179},5,[36,181,182],{"class":46},")\n",[18,184,185,186,189,190,193,194,197,198,201],{},"列宽、斑马纹、",[21,187,188],{},"分页时表头自动重复"," 一次到位。不写行循环。没有 ",[33,191,192],{},"PageBreak"," 选项。当表格放不下时布局引擎会发现，并在下一页顶部重新发出 ",[33,195,196],{},"Header"," 切片。需要列合并、行合并、跨页重复的表尾时，下沉到 ",[33,199,200],{},"document.Table"," 一层 —— 同样的积木，更细粒度的控制。",[18,203,204],{},"本文讲表格设计真正重要的三个轴 (列宽、斑马纹、分页)，gpdf 各自做了什么，以及抽象在哪里有意停下。",[14,206,207],{"id":207},"为什么写这篇文章",[18,209,210,217,218,221],{},[211,212,216],"a",{"href":213,"rel":214},"https://github.com/gpdf-dev/gpdf",[215],"nofollow","gpdf"," 是一个 Go 的 PDF 生成库。MIT、零依赖、单页渲染约 13 µs。表格部分的 API 很小 —— 只有 8 个 ",[33,219,220],{},"TableOption"," —— 但承受的设计压力很大。Go 的 PDF 项目几乎都是卡在表格上。",[18,223,224],{},"Go 里写表格容易翻车的三件事：",[226,227,228,243,253],"ol",{},[229,230,231,234,235,238,239,242],"li",{},[21,232,233],{},"列宽。"," Web 有 CSS ",[33,236,237],{},"\u003Ccol>"," 和 ",[33,240,241],{},"colgroup","。PDF 什么都没有。要么自己用点（pt）算每一列，要么接受库给的等分。",[229,244,245,248,249,252],{},[21,246,247],{},"斑马纹。"," 想让正文每隔一行变浅灰好读。低层库要自己写循环、跟踪 ",[33,250,251],{},"i % 2","，这是表格 bug 的一半源头。",[229,254,255,258,259,262],{},[21,256,257],{},"分页。"," 200 行的报表 A4 单页放不下。库需要 (a) 在合理位置切分，(b) 关闭当前页，(c) 打开新页，(d) ",[21,260,261],{},"在新页顶部重画表头","，让读者知道列名。少一项这个表格就废了。",[18,264,265],{},"这篇按顺序解释 gpdf 怎么解决每一个，以及做了什么取舍。只想要复制粘贴的食谱请看末尾的相关链接。这是给\"我能不能把每月一万行的对账单交给这个 API\"做判断用的长版。",[14,267,269],{"id":268},"api-形状","API 形状",[18,271,272],{},"构建器层只有一个入口：",[26,274,276],{"className":28,"code":275,"language":30,"meta":31,"style":31},"func (c *ColBuilder) Table(header []string, rows [][]string, opts ...TableOption)\n",[33,277,278],{"__ignoreMap":31},[36,279,280,283,286,290,293,297,300,303,305,307,310,314,316,318,321,323,325,328,331,333],{"class":38,"line":39},[36,281,282],{"class":46},"func",[36,284,285],{"class":46}," (",[36,287,289],{"class":288},"sHdIc","c ",[36,291,292],{"class":46},"*",[36,294,296],{"class":295},"sBMFI","ColBuilder",[36,298,299],{"class":46},")",[36,301,302],{"class":50}," Table",[36,304,54],{"class":46},[36,306,57],{"class":288},[36,308,309],{"class":46}," []",[36,311,313],{"class":312},"spNyl","string",[36,315,60],{"class":46},[36,317,63],{"class":288},[36,319,320],{"class":46}," [][]",[36,322,313],{"class":312},[36,324,60],{"class":46},[36,326,327],{"class":288}," opts",[36,329,330],{"class":46}," ...",[36,332,220],{"class":295},[36,334,182],{"class":46},[18,336,337,338,341],{},"表头是字符串切片，正文是字符串切片的切片，可变长 ",[33,339,340],{},"opts"," 配置其余一切。一共 8 个选项构造器：",[343,344,345,358],"table",{},[346,347,348],"thead",{},[349,350,351,355],"tr",{},[352,353,354],"th",{},"选项",[352,356,357],{},"控制内容",[359,360,361,372,382,392,402,412,422,436],"tbody",{},[349,362,363,369],{},[364,365,366],"td",{},[33,367,368],{},"ColumnWidths(...float64)",[364,370,371],{},"父 Col 宽度的百分比，每列一个",[349,373,374,379],{},[364,375,376],{},[33,377,378],{},"TableHeaderStyle(...TextOption)",[364,380,381],{},"表头背景色与文字颜色",[349,383,384,389],{},[364,385,386],{},[33,387,388],{},"TableStripe(pdf.Color)",[364,390,391],{},"正文交替行的背景色",[349,393,394,399],{},[364,395,396],{},[33,397,398],{},"TableCellVAlign(document.VerticalAlign)",[364,400,401],{},"正文单元格的垂直对齐",[349,403,404,409],{},[364,405,406],{},[33,407,408],{},"WithTableBorder(BorderSpec)",[364,410,411],{},"整张表的外框",[349,413,414,419],{},[364,415,416],{},[33,417,418],{},"WithTableCellBorder(BorderSpec)",[364,420,421],{},"每个单元格的相同边框 —— 网格效果",[349,423,424,429],{},[364,425,426],{},[33,427,428],{},"WithTableBorderCollapse(bool)",[364,430,431,432,435],{},"CSS ",[33,433,434],{},"border-collapse: collapse"," 语义",[349,437,438,443],{},[364,439,440],{},[33,441,442],{},"WithTableBackground(pdf.Color)",[364,444,445],{},"整张表的背景填充",[18,447,448,449,451],{},"构建器层全部表面就是这些。能用构建器搭的都用这 8 个搭。这之外 —— 列合并、行合并、表尾、固定 pt 宽 —— 走 ",[33,450,200],{},"。后面会讲。",[14,453,455],{"id":454},"可运行代码六个月发票台账","可运行代码：六个月发票台账",[18,457,458,459,462,463,466,467,470],{},"完整可运行示例。保存为 ",[33,460,461],{},"main.go","，执行 ",[33,464,465],{},"go run .","，得到 ",[33,468,469],{},"ledger.pdf","。",[26,472,474],{"className":28,"code":473,"language":30,"meta":31,"style":31},"package main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/pdf\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(gpdf.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    )\n\n    brand := pdf.RGBHex(0x1A237E)\n    stripe := pdf.RGBHex(0xF5F5F5)\n    hairline := template.Border(\n        template.BorderWidth(document.Pt(0.5)),\n        template.BorderColor(pdf.Gray(0.85)),\n    )\n\n    header := []string{\"日期\", \"发票号\", \"客户\", \"金额\"}\n    rows := make([][]string, 0, 120)\n    for i := 1; i \u003C= 120; i++ {\n        rows = append(rows, []string{\n            fmt.Sprintf(\"2026-%02d-%02d\", (i%6)+1, (i%28)+1),\n            fmt.Sprintf(\"INV-%05d\", 10000+i),\n            fmt.Sprintf(\"客户 #%d\", i),\n            fmt.Sprintf(\"¥%d\", (100+i*7)*10),\n        })\n    }\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"2026 上半年台账\", template.FontSize(18), template.Bold())\n            c.Spacer(document.Mm(4))\n\n            c.Table(header, rows,\n                template.ColumnWidths(20, 20, 40, 20),\n                template.TableHeaderStyle(\n                    template.TextColor(pdf.White),\n                    template.BgColor(brand),\n                ),\n                template.TableStripe(stripe),\n                template.WithTableCellBorder(hairline),\n            )\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"ledger.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[33,475,476,484,490,499,510,519,529,534,544,554,564,574,579,584,598,618,640,677,683,688,710,730,747,774,800,805,810,865,893,927,953,1018,1051,1078,1122,1128,1134,1139,1158,1189,1224,1270,1296,1301,1320,1349,1360,1380,1395,1401,1417,1434,1440,1445,1451,1456,1478,1494,1512,1517,1563,1578,1583],{"__ignoreMap":31},[36,477,478,481],{"class":38,"line":39},[36,479,480],{"class":46},"package",[36,482,483],{"class":295}," main\n",[36,485,486],{"class":38,"line":69},[36,487,489],{"emptyLinePlaceholder":488},true,"\n",[36,491,492,496],{"class":38,"line":104},[36,493,495],{"class":494},"s7zQu","import",[36,497,498],{"class":46}," (\n",[36,500,501,504,507],{"class":38,"line":153},[36,502,503],{"class":46},"    \"",[36,505,506],{"class":295},"fmt",[36,508,509],{"class":46},"\"\n",[36,511,512,514,517],{"class":38,"line":179},[36,513,503],{"class":46},[36,515,516],{"class":295},"log",[36,518,509],{"class":46},[36,520,522,524,527],{"class":38,"line":521},6,[36,523,503],{"class":46},[36,525,526],{"class":295},"os",[36,528,509],{"class":46},[36,530,532],{"class":38,"line":531},7,[36,533,489],{"emptyLinePlaceholder":488},[36,535,537,539,542],{"class":38,"line":536},8,[36,538,503],{"class":46},[36,540,541],{"class":295},"github.com/gpdf-dev/gpdf",[36,543,509],{"class":46},[36,545,547,549,552],{"class":38,"line":546},9,[36,548,503],{"class":46},[36,550,551],{"class":295},"github.com/gpdf-dev/gpdf/document",[36,553,509],{"class":46},[36,555,557,559,562],{"class":38,"line":556},10,[36,558,503],{"class":46},[36,560,561],{"class":295},"github.com/gpdf-dev/gpdf/pdf",[36,563,509],{"class":46},[36,565,567,569,572],{"class":38,"line":566},11,[36,568,503],{"class":46},[36,570,571],{"class":295},"github.com/gpdf-dev/gpdf/template",[36,573,509],{"class":46},[36,575,577],{"class":38,"line":576},12,[36,578,182],{"class":46},[36,580,582],{"class":38,"line":581},13,[36,583,489],{"emptyLinePlaceholder":488},[36,585,587,589,592,595],{"class":38,"line":586},14,[36,588,282],{"class":46},[36,590,591],{"class":50}," main",[36,593,594],{"class":46},"()",[36,596,597],{"class":46}," {\n",[36,599,601,604,607,610,612,615],{"class":38,"line":600},15,[36,602,603],{"class":42},"    doc ",[36,605,606],{"class":46},":=",[36,608,609],{"class":42}," gpdf",[36,611,47],{"class":46},[36,613,614],{"class":50},"NewDocument",[36,616,617],{"class":46},"(\n",[36,619,621,624,626,629,631,633,635,638],{"class":38,"line":620},16,[36,622,623],{"class":42},"        gpdf",[36,625,47],{"class":46},[36,627,628],{"class":50},"WithPageSize",[36,630,54],{"class":46},[36,632,216],{"class":42},[36,634,47],{"class":46},[36,636,637],{"class":42},"A4",[36,639,101],{"class":46},[36,641,643,645,647,650,652,655,657,660,662,664,666,669,671,674],{"class":38,"line":642},17,[36,644,623],{"class":42},[36,646,47],{"class":46},[36,648,649],{"class":50},"WithMargins",[36,651,54],{"class":46},[36,653,654],{"class":42},"document",[36,656,47],{"class":46},[36,658,659],{"class":50},"UniformEdges",[36,661,54],{"class":46},[36,663,654],{"class":42},[36,665,47],{"class":46},[36,667,668],{"class":50},"Mm",[36,670,54],{"class":46},[36,672,673],{"class":82},"20",[36,675,676],{"class":46},"))),\n",[36,678,680],{"class":38,"line":679},18,[36,681,682],{"class":46},"    )\n",[36,684,686],{"class":38,"line":685},19,[36,687,489],{"emptyLinePlaceholder":488},[36,689,691,694,696,699,701,703,705,708],{"class":38,"line":690},20,[36,692,693],{"class":42},"    brand ",[36,695,606],{"class":46},[36,697,698],{"class":42}," pdf",[36,700,47],{"class":46},[36,702,169],{"class":50},[36,704,54],{"class":46},[36,706,707],{"class":82},"0x1A237E",[36,709,182],{"class":46},[36,711,713,716,718,720,722,724,726,728],{"class":38,"line":712},21,[36,714,715],{"class":42},"    stripe ",[36,717,606],{"class":46},[36,719,698],{"class":42},[36,721,47],{"class":46},[36,723,169],{"class":50},[36,725,54],{"class":46},[36,727,174],{"class":82},[36,729,182],{"class":46},[36,731,733,736,738,740,742,745],{"class":38,"line":732},22,[36,734,735],{"class":42},"    hairline ",[36,737,606],{"class":46},[36,739,137],{"class":42},[36,741,47],{"class":46},[36,743,744],{"class":50},"Border",[36,746,617],{"class":46},[36,748,750,753,755,758,760,762,764,767,769,772],{"class":38,"line":749},23,[36,751,752],{"class":42},"        template",[36,754,47],{"class":46},[36,756,757],{"class":50},"BorderWidth",[36,759,54],{"class":46},[36,761,654],{"class":42},[36,763,47],{"class":46},[36,765,766],{"class":50},"Pt",[36,768,54],{"class":46},[36,770,771],{"class":82},"0.5",[36,773,150],{"class":46},[36,775,777,779,781,784,786,788,790,793,795,798],{"class":38,"line":776},24,[36,778,752],{"class":42},[36,780,47],{"class":46},[36,782,783],{"class":50},"BorderColor",[36,785,54],{"class":46},[36,787,126],{"class":42},[36,789,47],{"class":46},[36,791,792],{"class":50},"Gray",[36,794,54],{"class":46},[36,796,797],{"class":82},"0.85",[36,799,150],{"class":46},[36,801,803],{"class":38,"line":802},25,[36,804,682],{"class":46},[36,806,808],{"class":38,"line":807},26,[36,809,489],{"emptyLinePlaceholder":488},[36,811,813,816,818,820,822,825,828,832,834,836,839,842,844,846,848,851,853,855,857,860,862],{"class":38,"line":812},27,[36,814,815],{"class":42},"    header ",[36,817,606],{"class":46},[36,819,309],{"class":46},[36,821,313],{"class":312},[36,823,824],{"class":46},"{",[36,826,827],{"class":46},"\"",[36,829,831],{"class":830},"sfazB","日期",[36,833,827],{"class":46},[36,835,60],{"class":46},[36,837,838],{"class":46}," \"",[36,840,841],{"class":830},"发票号",[36,843,827],{"class":46},[36,845,60],{"class":46},[36,847,838],{"class":46},[36,849,850],{"class":830},"客户",[36,852,827],{"class":46},[36,854,60],{"class":46},[36,856,838],{"class":46},[36,858,859],{"class":830},"金额",[36,861,827],{"class":46},[36,863,864],{"class":46},"}\n",[36,866,868,871,873,876,879,881,883,886,888,891],{"class":38,"line":867},28,[36,869,870],{"class":42},"    rows ",[36,872,606],{"class":46},[36,874,875],{"class":50}," make",[36,877,878],{"class":46},"([][]",[36,880,313],{"class":312},[36,882,60],{"class":46},[36,884,885],{"class":82}," 0",[36,887,60],{"class":46},[36,889,890],{"class":82}," 120",[36,892,182],{"class":46},[36,894,896,899,902,904,907,910,912,915,917,919,922,925],{"class":38,"line":895},29,[36,897,898],{"class":494},"    for",[36,900,901],{"class":42}," i ",[36,903,606],{"class":46},[36,905,906],{"class":82}," 1",[36,908,909],{"class":46},";",[36,911,901],{"class":42},[36,913,914],{"class":46},"\u003C=",[36,916,890],{"class":82},[36,918,909],{"class":46},[36,920,921],{"class":42}," i",[36,923,924],{"class":46},"++",[36,926,597],{"class":46},[36,928,930,933,936,939,941,944,946,948,950],{"class":38,"line":929},30,[36,931,932],{"class":42},"        rows ",[36,934,935],{"class":46},"=",[36,937,938],{"class":50}," append",[36,940,54],{"class":46},[36,942,943],{"class":42},"rows",[36,945,60],{"class":46},[36,947,309],{"class":46},[36,949,313],{"class":312},[36,951,952],{"class":46},"{\n",[36,954,956,959,961,964,966,968,971,975,978,980,982,984,986,989,992,995,998,1001,1003,1005,1007,1009,1012,1014,1016],{"class":38,"line":955},31,[36,957,958],{"class":42},"            fmt",[36,960,47],{"class":46},[36,962,963],{"class":50},"Sprintf",[36,965,54],{"class":46},[36,967,827],{"class":46},[36,969,970],{"class":830},"2026-",[36,972,974],{"class":973},"swJcz","%02d",[36,976,977],{"class":830},"-",[36,979,974],{"class":973},[36,981,827],{"class":46},[36,983,60],{"class":46},[36,985,285],{"class":46},[36,987,988],{"class":42},"i",[36,990,991],{"class":46},"%",[36,993,994],{"class":82},"6",[36,996,997],{"class":46},")+",[36,999,1000],{"class":82},"1",[36,1002,60],{"class":46},[36,1004,285],{"class":46},[36,1006,988],{"class":42},[36,1008,991],{"class":46},[36,1010,1011],{"class":82},"28",[36,1013,997],{"class":46},[36,1015,1000],{"class":82},[36,1017,101],{"class":46},[36,1019,1021,1023,1025,1027,1029,1031,1034,1037,1039,1041,1044,1047,1049],{"class":38,"line":1020},32,[36,1022,958],{"class":42},[36,1024,47],{"class":46},[36,1026,963],{"class":50},[36,1028,54],{"class":46},[36,1030,827],{"class":46},[36,1032,1033],{"class":830},"INV-",[36,1035,1036],{"class":973},"%05d",[36,1038,827],{"class":46},[36,1040,60],{"class":46},[36,1042,1043],{"class":82}," 10000",[36,1045,1046],{"class":46},"+",[36,1048,988],{"class":42},[36,1050,101],{"class":46},[36,1052,1054,1056,1058,1060,1062,1064,1067,1070,1072,1074,1076],{"class":38,"line":1053},33,[36,1055,958],{"class":42},[36,1057,47],{"class":46},[36,1059,963],{"class":50},[36,1061,54],{"class":46},[36,1063,827],{"class":46},[36,1065,1066],{"class":830},"客户 #",[36,1068,1069],{"class":973},"%d",[36,1071,827],{"class":46},[36,1073,60],{"class":46},[36,1075,921],{"class":42},[36,1077,101],{"class":46},[36,1079,1081,1083,1085,1087,1089,1091,1094,1096,1098,1100,1102,1105,1107,1109,1111,1114,1117,1120],{"class":38,"line":1080},34,[36,1082,958],{"class":42},[36,1084,47],{"class":46},[36,1086,963],{"class":50},[36,1088,54],{"class":46},[36,1090,827],{"class":46},[36,1092,1093],{"class":830},"¥",[36,1095,1069],{"class":973},[36,1097,827],{"class":46},[36,1099,60],{"class":46},[36,1101,285],{"class":46},[36,1103,1104],{"class":82},"100",[36,1106,1046],{"class":46},[36,1108,988],{"class":42},[36,1110,292],{"class":46},[36,1112,1113],{"class":82},"7",[36,1115,1116],{"class":46},")*",[36,1118,1119],{"class":82},"10",[36,1121,101],{"class":46},[36,1123,1125],{"class":38,"line":1124},35,[36,1126,1127],{"class":46},"        })\n",[36,1129,1131],{"class":38,"line":1130},36,[36,1132,1133],{"class":46},"    }\n",[36,1135,1137],{"class":38,"line":1136},37,[36,1138,489],{"emptyLinePlaceholder":488},[36,1140,1142,1145,1147,1150,1152,1155],{"class":38,"line":1141},38,[36,1143,1144],{"class":42},"    page ",[36,1146,606],{"class":46},[36,1148,1149],{"class":42}," doc",[36,1151,47],{"class":46},[36,1153,1154],{"class":50},"AddPage",[36,1156,1157],{"class":46},"()\n",[36,1159,1161,1164,1166,1169,1172,1175,1178,1180,1182,1185,1187],{"class":38,"line":1160},39,[36,1162,1163],{"class":42},"    page",[36,1165,47],{"class":46},[36,1167,1168],{"class":50},"AutoRow",[36,1170,1171],{"class":46},"(func(",[36,1173,1174],{"class":288},"r",[36,1176,1177],{"class":46}," *",[36,1179,116],{"class":295},[36,1181,47],{"class":46},[36,1183,1184],{"class":295},"RowBuilder",[36,1186,299],{"class":46},[36,1188,597],{"class":46},[36,1190,1192,1195,1197,1200,1202,1205,1207,1210,1212,1214,1216,1218,1220,1222],{"class":38,"line":1191},40,[36,1193,1194],{"class":42},"        r",[36,1196,47],{"class":46},[36,1198,1199],{"class":50},"Col",[36,1201,54],{"class":46},[36,1203,1204],{"class":82},"12",[36,1206,60],{"class":46},[36,1208,1209],{"class":46}," func(",[36,1211,43],{"class":288},[36,1213,1177],{"class":46},[36,1215,116],{"class":295},[36,1217,47],{"class":46},[36,1219,296],{"class":295},[36,1221,299],{"class":46},[36,1223,597],{"class":46},[36,1225,1227,1230,1232,1235,1237,1239,1242,1244,1246,1248,1250,1253,1255,1258,1260,1262,1264,1267],{"class":38,"line":1226},41,[36,1228,1229],{"class":42},"            c",[36,1231,47],{"class":46},[36,1233,1234],{"class":50},"Text",[36,1236,54],{"class":46},[36,1238,827],{"class":46},[36,1240,1241],{"class":830},"2026 上半年台账",[36,1243,827],{"class":46},[36,1245,60],{"class":46},[36,1247,137],{"class":42},[36,1249,47],{"class":46},[36,1251,1252],{"class":50},"FontSize",[36,1254,54],{"class":46},[36,1256,1257],{"class":82},"18",[36,1259,134],{"class":46},[36,1261,137],{"class":42},[36,1263,47],{"class":46},[36,1265,1266],{"class":50},"Bold",[36,1268,1269],{"class":46},"())\n",[36,1271,1273,1275,1277,1280,1282,1284,1286,1288,1290,1293],{"class":38,"line":1272},42,[36,1274,1229],{"class":42},[36,1276,47],{"class":46},[36,1278,1279],{"class":50},"Spacer",[36,1281,54],{"class":46},[36,1283,654],{"class":42},[36,1285,47],{"class":46},[36,1287,668],{"class":50},[36,1289,54],{"class":46},[36,1291,1292],{"class":82},"4",[36,1294,1295],{"class":46},"))\n",[36,1297,1299],{"class":38,"line":1298},43,[36,1300,489],{"emptyLinePlaceholder":488},[36,1302,1304,1306,1308,1310,1312,1314,1316,1318],{"class":38,"line":1303},44,[36,1305,1229],{"class":42},[36,1307,47],{"class":46},[36,1309,51],{"class":50},[36,1311,54],{"class":46},[36,1313,57],{"class":42},[36,1315,60],{"class":46},[36,1317,63],{"class":42},[36,1319,66],{"class":46},[36,1321,1323,1326,1328,1330,1332,1334,1336,1338,1340,1343,1345,1347],{"class":38,"line":1322},45,[36,1324,1325],{"class":42},"                template",[36,1327,47],{"class":46},[36,1329,77],{"class":50},[36,1331,54],{"class":46},[36,1333,673],{"class":82},[36,1335,60],{"class":46},[36,1337,93],{"class":82},[36,1339,60],{"class":46},[36,1341,1342],{"class":82}," 40",[36,1344,60],{"class":46},[36,1346,93],{"class":82},[36,1348,101],{"class":46},[36,1350,1352,1354,1356,1358],{"class":38,"line":1351},46,[36,1353,1325],{"class":42},[36,1355,47],{"class":46},[36,1357,111],{"class":50},[36,1359,617],{"class":46},[36,1361,1363,1366,1368,1370,1372,1374,1376,1378],{"class":38,"line":1362},47,[36,1364,1365],{"class":42},"                    template",[36,1367,47],{"class":46},[36,1369,121],{"class":50},[36,1371,54],{"class":46},[36,1373,126],{"class":42},[36,1375,47],{"class":46},[36,1377,131],{"class":42},[36,1379,101],{"class":46},[36,1381,1383,1385,1387,1389,1391,1393],{"class":38,"line":1382},48,[36,1384,1365],{"class":42},[36,1386,47],{"class":46},[36,1388,142],{"class":50},[36,1390,54],{"class":46},[36,1392,147],{"class":42},[36,1394,101],{"class":46},[36,1396,1398],{"class":38,"line":1397},49,[36,1399,1400],{"class":46},"                ),\n",[36,1402,1404,1406,1408,1410,1412,1415],{"class":38,"line":1403},50,[36,1405,1325],{"class":42},[36,1407,47],{"class":46},[36,1409,160],{"class":50},[36,1411,54],{"class":46},[36,1413,1414],{"class":42},"stripe",[36,1416,101],{"class":46},[36,1418,1420,1422,1424,1427,1429,1432],{"class":38,"line":1419},51,[36,1421,1325],{"class":42},[36,1423,47],{"class":46},[36,1425,1426],{"class":50},"WithTableCellBorder",[36,1428,54],{"class":46},[36,1430,1431],{"class":42},"hairline",[36,1433,101],{"class":46},[36,1435,1437],{"class":38,"line":1436},52,[36,1438,1439],{"class":46},"            )\n",[36,1441,1443],{"class":38,"line":1442},53,[36,1444,1127],{"class":46},[36,1446,1448],{"class":38,"line":1447},54,[36,1449,1450],{"class":46},"    })\n",[36,1452,1454],{"class":38,"line":1453},55,[36,1455,489],{"emptyLinePlaceholder":488},[36,1457,1459,1462,1464,1467,1469,1471,1473,1476],{"class":38,"line":1458},56,[36,1460,1461],{"class":42},"    data",[36,1463,60],{"class":46},[36,1465,1466],{"class":42}," err ",[36,1468,606],{"class":46},[36,1470,1149],{"class":42},[36,1472,47],{"class":46},[36,1474,1475],{"class":50},"Generate",[36,1477,1157],{"class":46},[36,1479,1481,1484,1486,1489,1492],{"class":38,"line":1480},57,[36,1482,1483],{"class":494},"    if",[36,1485,1466],{"class":42},[36,1487,1488],{"class":46},"!=",[36,1490,1491],{"class":46}," nil",[36,1493,597],{"class":46},[36,1495,1497,1500,1502,1505,1507,1510],{"class":38,"line":1496},58,[36,1498,1499],{"class":42},"        log",[36,1501,47],{"class":46},[36,1503,1504],{"class":50},"Fatal",[36,1506,54],{"class":46},[36,1508,1509],{"class":42},"err",[36,1511,182],{"class":46},[36,1513,1515],{"class":38,"line":1514},59,[36,1516,1133],{"class":46},[36,1518,1520,1522,1524,1526,1529,1531,1534,1536,1538,1540,1542,1544,1547,1549,1552,1555,1557,1559,1561],{"class":38,"line":1519},60,[36,1521,1483],{"class":494},[36,1523,1466],{"class":42},[36,1525,606],{"class":46},[36,1527,1528],{"class":42}," os",[36,1530,47],{"class":46},[36,1532,1533],{"class":50},"WriteFile",[36,1535,54],{"class":46},[36,1537,827],{"class":46},[36,1539,469],{"class":830},[36,1541,827],{"class":46},[36,1543,60],{"class":46},[36,1545,1546],{"class":42}," data",[36,1548,60],{"class":46},[36,1550,1551],{"class":82}," 0o644",[36,1553,1554],{"class":46},");",[36,1556,1466],{"class":42},[36,1558,1488],{"class":46},[36,1560,1491],{"class":46},[36,1562,597],{"class":46},[36,1564,1566,1568,1570,1572,1574,1576],{"class":38,"line":1565},61,[36,1567,1499],{"class":42},[36,1569,47],{"class":46},[36,1571,1504],{"class":50},[36,1573,54],{"class":46},[36,1575,1509],{"class":42},[36,1577,182],{"class":46},[36,1579,1581],{"class":38,"line":1580},62,[36,1582,1133],{"class":46},[36,1584,1586],{"class":38,"line":1585},63,[36,1587,864],{"class":46},[18,1589,1590],{},"A4 上 120 行大约会跨 5 页。每页顶部会重画深蓝表头，正文从上一页结束处继续，斑马纹的交替模式跨页保持一致。这些都不需要额外写代码。",[18,1592,1593,1594,1597,1598,1601,1602,1605],{},"这段代码值得看的是 ",[21,1595,1596],{},"缺少的东西","：没有行循环、没有页计数器、没有 ",[33,1599,1600],{},"if i == lastRowOnPage","、没有 ",[33,1603,1604],{},"PageBreak()"," 调用、没有手动重画表头。四行选项声明表格长什么样，引擎负责\"在哪里分页\"。",[14,1607,1609],{"id":1608},"列宽百分比到底是什么的百分比","列宽：百分比到底是什么的百分比",[18,1611,1612,1615,1616,1619],{},[33,1613,1614],{},"ColumnWidths(40, 15, 20, 25)"," 看起来像 CSS 的 ",[33,1617,1618],{},"\u003Ccol width=\"40%\">","。差不多，但有三个尖锐的边角值得知道。",[18,1621,1622,1625,1626,1629,1630,1633],{},[21,1623,1624],{},"百分比是父 Col 的，不是页面的。"," ",[33,1627,1628],{},"r.Col(6, ...)"," 占一行内容宽度的一半。其中一张 ",[33,1631,1632],{},"ColumnWidths(50, 50)"," 的表，每列占行宽的 25%，不是页宽的 50%。百分比对表格所在位置是局部的。把表格从整宽行换到并排布局时，选项调用本身不需要改。",[18,1635,1636,1639],{},[21,1637,1638],{},"不归一化。"," 加起来等于 90，右边就空 10%。等于 110，最右列就溢出父级流到页外。gpdf 信任你的算术。不会警告 —— 也不应该 —— 自动改你写的值比那个 bug 危害更大。",[18,1641,1642,1645],{},[21,1643,1644],{},"尾部缺省自动分配。"," 给的宽度数量少于列数时，剩余列等分剩余空间：",[26,1647,1649],{"className":28,"code":1648,"language":30,"meta":31,"style":31},"// 五列表格，给三个宽度\ntemplate.ColumnWidths(40, 10, 20)\n// → 40% / 10% / 20% / 15% / 15%   (剩余 30% 二等分)\n",[33,1650,1651,1657,1680],{"__ignoreMap":31},[36,1652,1653],{"class":38,"line":39},[36,1654,1656],{"class":1655},"sHwdD","// 五列表格，给三个宽度\n",[36,1658,1659,1661,1663,1665,1667,1669,1671,1674,1676,1678],{"class":38,"line":69},[36,1660,116],{"class":42},[36,1662,47],{"class":46},[36,1664,77],{"class":50},[36,1666,54],{"class":46},[36,1668,83],{"class":82},[36,1670,60],{"class":46},[36,1672,1673],{"class":82}," 10",[36,1675,60],{"class":46},[36,1677,93],{"class":82},[36,1679,182],{"class":46},[36,1681,1682],{"class":38,"line":104},[36,1683,1684],{"class":1655},"// → 40% / 10% / 20% / 15% / 15%   (剩余 30% 二等分)\n",[18,1686,1687,1688,1691],{},"\"我只关心这几列宽度，剩下的随便\"是个有用的招法。显式传 ",[33,1689,1690],{},"0"," 也能让某列变成自动：",[26,1693,1695],{"className":28,"code":1694,"language":30,"meta":31,"style":31},"template.ColumnWidths(0, 30, 30) // 三列表格 → 40% / 30% / 30%\n",[33,1696,1697],{"__ignoreMap":31},[36,1698,1699,1701,1703,1705,1707,1709,1711,1714,1716,1718,1720],{"class":38,"line":39},[36,1700,116],{"class":42},[36,1702,47],{"class":46},[36,1704,77],{"class":50},[36,1706,54],{"class":46},[36,1708,1690],{"class":82},[36,1710,60],{"class":46},[36,1712,1713],{"class":82}," 30",[36,1715,60],{"class":46},[36,1717,1713],{"class":82},[36,1719,299],{"class":46},[36,1721,1722],{"class":1655}," // 三列表格 → 40% / 30% / 30%\n",[18,1724,1725,1726,1730],{},"列宽的边角细节请看 ",[211,1727,1729],{"href":1728},"/zh/blog/table-column-widths","列宽食谱","。一句话：百分比覆盖 95% 的布局，剩下 5% 下沉一层。后面讲。",[14,1732,1734],{"id":1733},"斑马纹你不用写的行循环","斑马纹：你不用写的行循环",[26,1736,1738],{"className":28,"code":1737,"language":30,"meta":31,"style":31},"template.TableStripe(pdf.RGBHex(0xF5F5F5))\n",[33,1739,1740],{"__ignoreMap":31},[36,1741,1742,1744,1746,1748,1750,1752,1754,1756,1758,1760],{"class":38,"line":39},[36,1743,116],{"class":42},[36,1745,47],{"class":46},[36,1747,160],{"class":50},[36,1749,54],{"class":46},[36,1751,126],{"class":42},[36,1753,47],{"class":46},[36,1755,169],{"class":50},[36,1757,54],{"class":46},[36,1759,174],{"class":82},[36,1761,1295],{"class":46},[18,1763,1764,1765,1767,1768,1771],{},"就这一行。gpdf 用从 0 开始的索引 ",[33,1766,988],{}," 遍历正文行，给 ",[33,1769,1770],{},"i % 2 == 1"," 的行上色。表头是单独切片不计数，所以第一行正文是干净的、第二行是阴影 —— Bootstrap 约定。",[18,1773,1774,1775,238,1778,1781,1782,1785,1786,1789],{},"为什么需要这个选项：在 ",[33,1776,1777],{},"gofpdf",[33,1779,1780],{},"gopdf"," 里你要自己写循环、每行 ",[33,1783,1784],{},"SetFillColor","、给 ",[33,1787,1788],{},"CellFormat"," 传填充标志。八到十行代码，off-by-one 的发生率高到 StackOverflow 上专门有一组答案。把它压缩到一个选项里，整个 bug 类别就消失了。",[18,1791,1792],{},"约束是有意的：",[1794,1795,1796,1802,1808],"ul",{},[229,1797,1798,1801],{},[21,1799,1800],{},"只支持一个斑马色，不是两色交替。"," 不能\"蓝灰交替\"。页面本身就是白的，所以没上色的行自动是白色。再加第三色循环只会增加阅读负担 —— 斑马纹是为减负而存在的。",[229,1803,1804,1807],{},[21,1805,1806],{},"不能反转奇偶。"," 第一正文行始终干净，第二行始终阴影。真要反转就在数据前面塞个空行。但其实没人想反转。",[229,1809,1810,1813],{},[21,1811,1812],{},"斑马纹跨页保持正确。"," 正文第 14 行流到第二页时还是 14，奇偶性不变。引擎跨分页携带索引。",[18,1815,1816,1817,1821,1822,1825],{},"颜色选择和暗色主题变体见 ",[211,1818,1820],{"href":1819},"/zh/blog/zebra-striped-table-rows","斑马纹食谱","。本篇要点：表格的 ",[21,1823,1824],{},"属性","（交替模式）在表格调用处声明，不是在行级别配置。",[14,1827,1829],{"id":1828},"分页真正难的部分","分页：真正难的部分",[18,1831,1832],{},"大多数 Go PDF 故事都在这里崩盘，也是 gpdf 设计回报最高的地方。",[18,1834,1835,1836,1842],{},"简单版：",[21,1837,1838,1839,1841],{},"给表格塞超过单页容量的行，gpdf 自动分页。",[33,1840,196],{}," 切片在每个续页顶部重新绘制。"," 没有要打开的选项，没有要调用的方法。是布局引擎的默认行为。",[18,1844,1845,1846,1849,1850,1853,1854,1856,1857,1860,1861,1864,1865,1868],{},"详细版更有意思。块布局引擎 (",[33,1847,1848],{},"document/layout/block.go",") 用可用高度布局表格。正文放不下时返回结果会带 ",[33,1851,1852],{},"Overflow"," 字段 —— 同样的 ",[33,1855,196],{},"、同样的 ",[33,1858,1859],{},"Footer","、",[21,1862,1863],{},"剩余的正文行"," 组成的新 ",[33,1866,1867],{},"*document.Table","。页面系统把已布局部分写出到当前页，开新页，再用新页的可用高度把溢出表格喂回布局引擎。直到溢出为空。",[18,1870,1871],{},"两个推论：",[226,1873,1874,1887],{},[229,1875,1876,1883,1884,1886],{},[21,1877,1878,1879,1882],{},"表头住在 ",[33,1880,1881],{},"tbl.Header"," 里，不在循环里。"," 因为溢出表格复用同一个 ",[33,1885,196],{}," 切片，续页顶部自动重复表头。样式、列宽、所有都一样。",[229,1888,1889,1892],{},[21,1890,1891],{},"不存在\"表头放不下\"的边界情况。"," 布局引擎在测量正文行之前先为表头预留空间。如果一页连表头加至少一行正文都装不下，整张表被推到下一页。",[18,1894,1895],{},"表尾 —— 在 document 层用时 —— 工作方式相同。每个续页底部自动重绘。",[18,1897,1898,1899,470],{},"没有的功能：「这组行别拆开」标注、特定行不分页、「这张表从新页开始」指令。前两个是 TODO。第三个在页层面做 —— 在包含表格的行之前调 ",[33,1900,1901],{},"doc.AddPage()",[14,1903,1905],{"id":1904},"走出构建器-api","走出构建器 API",[18,1907,1908,1909,470],{},"构建器对常见情况好用。需要单元格合并、固定 pt 宽、每页重复的表尾，或单元格混合多种内容类型时，下沉到 ",[33,1910,200],{},[26,1912,1914],{"className":28,"code":1913,"language":30,"meta":31,"style":31},"import (\n    \"github.com/gpdf-dev/gpdf/document\"\n)\n\nfooter := document.TableRow{\n    Cells: []document.TableCell{\n        {\n            Content: []document.DocumentNode{\n                &document.Text{Content: \"合计\", TextStyle: document.DefaultStyle()},\n            },\n            ColSpan: 3, // ← 跨前三列\n            RowSpan: 1,\n        },\n        {\n            Content: []document.DocumentNode{\n                &document.Text{Content: \"¥48,720\", TextStyle: document.DefaultStyle()},\n            },\n            ColSpan: 1,\n            RowSpan: 1,\n        },\n    },\n}\n\ntbl := &document.Table{\n    Columns: []document.TableColumn{\n        {Width: document.Pct(20)},\n        {Width: document.Pct(20)},\n        {Width: document.Auto},\n        {Width: document.Pt(80)}, // 不随页宽变化的固定 80pt\n    },\n    Header: /* ... */,\n    Body:   /* ... */,\n    Footer: []document.TableRow{footer},\n}\n",[33,1915,1916,1922,1930,1934,1938,1955,1974,1979,1997,2039,2044,2059,2070,2075,2079,2095,2132,2136,2146,2156,2160,2165,2169,2173,2191,2209,2233,2253,2271,2296,2300,2312,2324,2346],{"__ignoreMap":31},[36,1917,1918,1920],{"class":38,"line":39},[36,1919,495],{"class":494},[36,1921,498],{"class":46},[36,1923,1924,1926,1928],{"class":38,"line":69},[36,1925,503],{"class":46},[36,1927,551],{"class":295},[36,1929,509],{"class":46},[36,1931,1932],{"class":38,"line":104},[36,1933,182],{"class":46},[36,1935,1936],{"class":38,"line":153},[36,1937,489],{"emptyLinePlaceholder":488},[36,1939,1940,1943,1945,1948,1950,1953],{"class":38,"line":179},[36,1941,1942],{"class":42},"footer ",[36,1944,606],{"class":46},[36,1946,1947],{"class":295}," document",[36,1949,47],{"class":46},[36,1951,1952],{"class":295},"TableRow",[36,1954,952],{"class":46},[36,1956,1957,1960,1963,1965,1967,1969,1972],{"class":38,"line":521},[36,1958,1959],{"class":42},"    Cells",[36,1961,1962],{"class":46},":",[36,1964,309],{"class":46},[36,1966,654],{"class":295},[36,1968,47],{"class":46},[36,1970,1971],{"class":295},"TableCell",[36,1973,952],{"class":46},[36,1975,1976],{"class":38,"line":531},[36,1977,1978],{"class":46},"        {\n",[36,1980,1981,1984,1986,1988,1990,1992,1995],{"class":38,"line":536},[36,1982,1983],{"class":42},"            Content",[36,1985,1962],{"class":46},[36,1987,309],{"class":46},[36,1989,654],{"class":295},[36,1991,47],{"class":46},[36,1993,1994],{"class":295},"DocumentNode",[36,1996,952],{"class":46},[36,1998,1999,2002,2004,2006,2008,2010,2013,2015,2017,2020,2022,2024,2027,2029,2031,2033,2036],{"class":38,"line":546},[36,2000,2001],{"class":46},"                &",[36,2003,654],{"class":295},[36,2005,47],{"class":46},[36,2007,1234],{"class":295},[36,2009,824],{"class":46},[36,2011,2012],{"class":42},"Content",[36,2014,1962],{"class":46},[36,2016,838],{"class":46},[36,2018,2019],{"class":830},"合计",[36,2021,827],{"class":46},[36,2023,60],{"class":46},[36,2025,2026],{"class":42}," TextStyle",[36,2028,1962],{"class":46},[36,2030,1947],{"class":42},[36,2032,47],{"class":46},[36,2034,2035],{"class":50},"DefaultStyle",[36,2037,2038],{"class":46},"()},\n",[36,2040,2041],{"class":38,"line":556},[36,2042,2043],{"class":46},"            },\n",[36,2045,2046,2049,2051,2054,2056],{"class":38,"line":566},[36,2047,2048],{"class":42},"            ColSpan",[36,2050,1962],{"class":46},[36,2052,2053],{"class":82}," 3",[36,2055,60],{"class":46},[36,2057,2058],{"class":1655}," // ← 跨前三列\n",[36,2060,2061,2064,2066,2068],{"class":38,"line":576},[36,2062,2063],{"class":42},"            RowSpan",[36,2065,1962],{"class":46},[36,2067,906],{"class":82},[36,2069,66],{"class":46},[36,2071,2072],{"class":38,"line":581},[36,2073,2074],{"class":46},"        },\n",[36,2076,2077],{"class":38,"line":586},[36,2078,1978],{"class":46},[36,2080,2081,2083,2085,2087,2089,2091,2093],{"class":38,"line":600},[36,2082,1983],{"class":42},[36,2084,1962],{"class":46},[36,2086,309],{"class":46},[36,2088,654],{"class":295},[36,2090,47],{"class":46},[36,2092,1994],{"class":295},[36,2094,952],{"class":46},[36,2096,2097,2099,2101,2103,2105,2107,2109,2111,2113,2116,2118,2120,2122,2124,2126,2128,2130],{"class":38,"line":620},[36,2098,2001],{"class":46},[36,2100,654],{"class":295},[36,2102,47],{"class":46},[36,2104,1234],{"class":295},[36,2106,824],{"class":46},[36,2108,2012],{"class":42},[36,2110,1962],{"class":46},[36,2112,838],{"class":46},[36,2114,2115],{"class":830},"¥48,720",[36,2117,827],{"class":46},[36,2119,60],{"class":46},[36,2121,2026],{"class":42},[36,2123,1962],{"class":46},[36,2125,1947],{"class":42},[36,2127,47],{"class":46},[36,2129,2035],{"class":50},[36,2131,2038],{"class":46},[36,2133,2134],{"class":38,"line":642},[36,2135,2043],{"class":46},[36,2137,2138,2140,2142,2144],{"class":38,"line":679},[36,2139,2048],{"class":42},[36,2141,1962],{"class":46},[36,2143,906],{"class":82},[36,2145,66],{"class":46},[36,2147,2148,2150,2152,2154],{"class":38,"line":685},[36,2149,2063],{"class":42},[36,2151,1962],{"class":46},[36,2153,906],{"class":82},[36,2155,66],{"class":46},[36,2157,2158],{"class":38,"line":690},[36,2159,2074],{"class":46},[36,2161,2162],{"class":38,"line":712},[36,2163,2164],{"class":46},"    },\n",[36,2166,2167],{"class":38,"line":732},[36,2168,864],{"class":46},[36,2170,2171],{"class":38,"line":749},[36,2172,489],{"emptyLinePlaceholder":488},[36,2174,2175,2178,2180,2183,2185,2187,2189],{"class":38,"line":776},[36,2176,2177],{"class":42},"tbl ",[36,2179,606],{"class":46},[36,2181,2182],{"class":46}," &",[36,2184,654],{"class":295},[36,2186,47],{"class":46},[36,2188,51],{"class":295},[36,2190,952],{"class":46},[36,2192,2193,2196,2198,2200,2202,2204,2207],{"class":38,"line":802},[36,2194,2195],{"class":42},"    Columns",[36,2197,1962],{"class":46},[36,2199,309],{"class":46},[36,2201,654],{"class":295},[36,2203,47],{"class":46},[36,2205,2206],{"class":295},"TableColumn",[36,2208,952],{"class":46},[36,2210,2211,2214,2217,2219,2221,2223,2226,2228,2230],{"class":38,"line":807},[36,2212,2213],{"class":46},"        {",[36,2215,2216],{"class":42},"Width",[36,2218,1962],{"class":46},[36,2220,1947],{"class":42},[36,2222,47],{"class":46},[36,2224,2225],{"class":50},"Pct",[36,2227,54],{"class":46},[36,2229,673],{"class":82},[36,2231,2232],{"class":46},")},\n",[36,2234,2235,2237,2239,2241,2243,2245,2247,2249,2251],{"class":38,"line":812},[36,2236,2213],{"class":46},[36,2238,2216],{"class":42},[36,2240,1962],{"class":46},[36,2242,1947],{"class":42},[36,2244,47],{"class":46},[36,2246,2225],{"class":50},[36,2248,54],{"class":46},[36,2250,673],{"class":82},[36,2252,2232],{"class":46},[36,2254,2255,2257,2259,2261,2263,2265,2268],{"class":38,"line":867},[36,2256,2213],{"class":46},[36,2258,2216],{"class":42},[36,2260,1962],{"class":46},[36,2262,1947],{"class":42},[36,2264,47],{"class":46},[36,2266,2267],{"class":42},"Auto",[36,2269,2270],{"class":46},"},\n",[36,2272,2273,2275,2277,2279,2281,2283,2285,2287,2290,2293],{"class":38,"line":895},[36,2274,2213],{"class":46},[36,2276,2216],{"class":42},[36,2278,1962],{"class":46},[36,2280,1947],{"class":42},[36,2282,47],{"class":46},[36,2284,766],{"class":50},[36,2286,54],{"class":46},[36,2288,2289],{"class":82},"80",[36,2291,2292],{"class":46},")},",[36,2294,2295],{"class":1655}," // 不随页宽变化的固定 80pt\n",[36,2297,2298],{"class":38,"line":929},[36,2299,2164],{"class":46},[36,2301,2302,2305,2307,2310],{"class":38,"line":955},[36,2303,2304],{"class":42},"    Header",[36,2306,1962],{"class":46},[36,2308,2309],{"class":1655}," /* ... */",[36,2311,66],{"class":46},[36,2313,2314,2317,2319,2322],{"class":38,"line":1020},[36,2315,2316],{"class":42},"    Body",[36,2318,1962],{"class":46},[36,2320,2321],{"class":1655},"   /* ... */",[36,2323,66],{"class":46},[36,2325,2326,2329,2331,2333,2335,2337,2339,2341,2344],{"class":38,"line":1053},[36,2327,2328],{"class":42},"    Footer",[36,2330,1962],{"class":46},[36,2332,309],{"class":46},[36,2334,654],{"class":295},[36,2336,47],{"class":46},[36,2338,1952],{"class":295},[36,2340,824],{"class":46},[36,2342,2343],{"class":42},"footer",[36,2345,2270],{"class":46},[36,2347,2348],{"class":38,"line":1080},[36,2349,864],{"class":46},[18,2351,2352,2353,2356,2357,2360,2361,2363,2364,2363,2366,2363,2369,2363,2372,2363,2375,2377,2378,2380,2381,2383,2384,2386],{},"几点。",[33,2354,2355],{},"TableColumn.Width"," 是 ",[33,2358,2359],{},"document.Value"," 类型，可取 ",[33,2362,766],{}," / ",[33,2365,668],{},[33,2367,2368],{},"Cm",[33,2370,2371],{},"In",[33,2373,2374],{},"Em",[33,2376,2225],{},"，以及特殊的 ",[33,2379,2267],{},"。一张表里可以混用。",[33,2382,2267],{}," 列共享固定列与百分比列扣除后的剩余。比构建器的纯百分比模型更接近 CSS ",[33,2385,237],{}," 元素。",[18,2388,2389,238,2392,2395],{},[33,2390,2391],{},"TableCell.ColSpan",[33,2393,2394],{},"RowSpan"," 是整数，默认 1。例子里前三列合并写\"合计\"，第四列放金额 —— 经典发票表尾。",[18,2397,2398,2356,2401,2404],{},[33,2399,2400],{},"document.Table.Footer",[33,2402,2403],{},"[]TableRow","，和表头一样每页重复。构建器 API 不暴露是因为短表格大多用不到 —— 真要用时已经离开\"常见情况\"区域了。",[18,2406,2407,2408,2410],{},"这是 gpdf 的整体模式：高层构建器优雅覆盖 90%，document 层在旁边等着另外 10%。不是两个库。同一份文档里可以混用构建器行和手搭行。构建器只是同一个 ",[33,2409,200],{}," 节点的构造函数。",[14,2412,2413],{"id":2413},"边框与盒模型",[18,2415,2416],{},"三个边框选项，三个不同任务：",[26,2418,2420],{"className":28,"code":2419,"language":30,"meta":31,"style":31},"template.WithTableBorder(spec)         // 整张表外框\ntemplate.WithTableCellBorder(spec)     // 每个单元格相同边框\ntemplate.WithTableBorderCollapse(true) // 合并相邻单元格边框\n",[33,2421,2422,2441,2458],{"__ignoreMap":31},[36,2423,2424,2426,2428,2431,2433,2436,2438],{"class":38,"line":39},[36,2425,116],{"class":42},[36,2427,47],{"class":46},[36,2429,2430],{"class":50},"WithTableBorder",[36,2432,54],{"class":46},[36,2434,2435],{"class":42},"spec",[36,2437,299],{"class":46},[36,2439,2440],{"class":1655},"         // 整张表外框\n",[36,2442,2443,2445,2447,2449,2451,2453,2455],{"class":38,"line":69},[36,2444,116],{"class":42},[36,2446,47],{"class":46},[36,2448,1426],{"class":50},[36,2450,54],{"class":46},[36,2452,2435],{"class":42},[36,2454,299],{"class":46},[36,2456,2457],{"class":1655},"     // 每个单元格相同边框\n",[36,2459,2460,2462,2464,2467,2469,2473,2475],{"class":38,"line":104},[36,2461,116],{"class":42},[36,2463,47],{"class":46},[36,2465,2466],{"class":50},"WithTableBorderCollapse",[36,2468,54],{"class":46},[36,2470,2472],{"class":2471},"sfNiH","true",[36,2474,299],{"class":46},[36,2476,2477],{"class":1655}," // 合并相邻单元格边框\n",[18,2479,2480,2481,2483,2484,2486,2487,2490,2491,2494],{},"默认无边框。要外框加 ",[33,2482,2430],{},"。要网格加 ",[33,2485,1426],{},"。两者都加得到\"框 + 网格\"。",[33,2488,2489],{},"BorderSpec"," 用 ",[33,2492,2493],{},"template.Border(template.BorderWidth(...), template.BorderColor(...))"," 构造。",[18,2496,2497,2500],{},[33,2498,2499],{},"WithTableBorderCollapse(true)"," 是 CSS 同名属性的语义：相邻单元格边框合并为一条线（不重复绘制）。发丝级网格中这个更干净；故意要双线的粗边框就关掉。默认分离。",[18,2502,2503],{},"实用组合：发丝级单元格边框 + 浅斑马纹：",[26,2505,2507],{"className":28,"code":2506,"language":30,"meta":31,"style":31},"c.Table(header, rows,\n    template.ColumnWidths(40, 20, 15, 25),\n    template.TableHeaderStyle(template.TextColor(pdf.White), template.BgColor(brand)),\n    template.TableStripe(pdf.RGBHex(0xF5F5F5)),\n    template.WithTableCellBorder(template.Border(\n        template.BorderWidth(document.Pt(0.5)),\n        template.BorderColor(pdf.Gray(0.85)),\n    )),\n    template.WithTableBorderCollapse(true),\n)\n",[33,2508,2509,2527,2553,2591,2613,2631,2653,2675,2680,2694],{"__ignoreMap":31},[36,2510,2511,2513,2515,2517,2519,2521,2523,2525],{"class":38,"line":39},[36,2512,43],{"class":42},[36,2514,47],{"class":46},[36,2516,51],{"class":50},[36,2518,54],{"class":46},[36,2520,57],{"class":42},[36,2522,60],{"class":46},[36,2524,63],{"class":42},[36,2526,66],{"class":46},[36,2528,2529,2531,2533,2535,2537,2539,2541,2543,2545,2547,2549,2551],{"class":38,"line":69},[36,2530,72],{"class":42},[36,2532,47],{"class":46},[36,2534,77],{"class":50},[36,2536,54],{"class":46},[36,2538,83],{"class":82},[36,2540,60],{"class":46},[36,2542,93],{"class":82},[36,2544,60],{"class":46},[36,2546,88],{"class":82},[36,2548,60],{"class":46},[36,2550,98],{"class":82},[36,2552,101],{"class":46},[36,2554,2555,2557,2559,2561,2563,2565,2567,2569,2571,2573,2575,2577,2579,2581,2583,2585,2587,2589],{"class":38,"line":104},[36,2556,72],{"class":42},[36,2558,47],{"class":46},[36,2560,111],{"class":50},[36,2562,54],{"class":46},[36,2564,116],{"class":42},[36,2566,47],{"class":46},[36,2568,121],{"class":50},[36,2570,54],{"class":46},[36,2572,126],{"class":42},[36,2574,47],{"class":46},[36,2576,131],{"class":42},[36,2578,134],{"class":46},[36,2580,137],{"class":42},[36,2582,47],{"class":46},[36,2584,142],{"class":50},[36,2586,54],{"class":46},[36,2588,147],{"class":42},[36,2590,150],{"class":46},[36,2592,2593,2595,2597,2599,2601,2603,2605,2607,2609,2611],{"class":38,"line":153},[36,2594,72],{"class":42},[36,2596,47],{"class":46},[36,2598,160],{"class":50},[36,2600,54],{"class":46},[36,2602,126],{"class":42},[36,2604,47],{"class":46},[36,2606,169],{"class":50},[36,2608,54],{"class":46},[36,2610,174],{"class":82},[36,2612,150],{"class":46},[36,2614,2615,2617,2619,2621,2623,2625,2627,2629],{"class":38,"line":179},[36,2616,72],{"class":42},[36,2618,47],{"class":46},[36,2620,1426],{"class":50},[36,2622,54],{"class":46},[36,2624,116],{"class":42},[36,2626,47],{"class":46},[36,2628,744],{"class":50},[36,2630,617],{"class":46},[36,2632,2633,2635,2637,2639,2641,2643,2645,2647,2649,2651],{"class":38,"line":521},[36,2634,752],{"class":42},[36,2636,47],{"class":46},[36,2638,757],{"class":50},[36,2640,54],{"class":46},[36,2642,654],{"class":42},[36,2644,47],{"class":46},[36,2646,766],{"class":50},[36,2648,54],{"class":46},[36,2650,771],{"class":82},[36,2652,150],{"class":46},[36,2654,2655,2657,2659,2661,2663,2665,2667,2669,2671,2673],{"class":38,"line":531},[36,2656,752],{"class":42},[36,2658,47],{"class":46},[36,2660,783],{"class":50},[36,2662,54],{"class":46},[36,2664,126],{"class":42},[36,2666,47],{"class":46},[36,2668,792],{"class":50},[36,2670,54],{"class":46},[36,2672,797],{"class":82},[36,2674,150],{"class":46},[36,2676,2677],{"class":38,"line":536},[36,2678,2679],{"class":46},"    )),\n",[36,2681,2682,2684,2686,2688,2690,2692],{"class":38,"line":546},[36,2683,72],{"class":42},[36,2685,47],{"class":46},[36,2687,2466],{"class":50},[36,2689,54],{"class":46},[36,2691,2472],{"class":2471},[36,2693,101],{"class":46},[36,2695,2696],{"class":38,"line":556},[36,2697,182],{"class":46},[18,2699,2700],{},"会计师 Excel 打印预览的那种感觉。发票、对账单、台账、报销单 —— 财务相邻文档的合理默认。",[14,2702,2703],{"id":2703},"与替代方案对比",[18,2705,2706],{},"参考一下，同样的\"多页 + 斑马纹\"表格在常被 gpdf 替换的库里怎么写：",[343,2708,2709,2728],{},[346,2710,2711],{},[349,2712,2713,2716,2719,2722,2725],{},[352,2714,2715],{},"库",[352,2717,2718],{},"表格代码行数",[352,2720,2721],{},"分页表头重复",[352,2723,2724],{},"斑马纹",[352,2726,2727],{},"备注",[359,2729,2730,2756,2778,2793,2809,2829],{},[349,2731,2732,2736,2741,2746,2753],{},[364,2733,2734],{},[21,2735,216],{},[364,2737,2738],{},[21,2739,2740],{},"约 10 行",[364,2742,2743],{},[21,2744,2745],{},"自动",[364,2747,2748],{},[21,2749,2750],{},[33,2751,2752],{},"TableStripe(...)",[364,2754,2755],{},"构建器与底层都可用",[349,2757,2758,2761,2764,2770,2775],{},[364,2759,2760],{},"jung-kurt/gofpdf (2021 归档)",[364,2762,2763],{},"40〜60 行",[364,2765,2766,2767,2769],{},"手动：跟踪 Y、调 ",[33,2768,1154],{},"、重绘表头",[364,2771,2772,2773],{},"行循环里 ",[33,2774,1784],{},[364,2776,2777],{},"奠基者，已停止维护",[349,2779,2780,2783,2785,2788,2790],{},[364,2781,2782],{},"go-pdf/fpdf (2025 归档)",[364,2784,2763],{},[364,2786,2787],{},"同上",[364,2789,2787],{},[364,2791,2792],{},"gofpdf 分支，模型相同",[349,2794,2795,2798,2801,2804,2806],{},[364,2796,2797],{},"signintech/gopdf",[364,2799,2800],{},"50〜80 行",[364,2802,2803],{},"手动",[364,2805,2803],{},[364,2807,2808],{},"更底层",[349,2810,2811,2814,2817,2819,2826],{},[364,2812,2813],{},"johnfercher/maroto v2",[364,2815,2816],{},"约 15 行",[364,2818,2745],{},[364,2820,2821,2822,2825],{},"行级 ",[33,2823,2824],{},"WithBackgroundColor"," 手动",[364,2827,2828],{},"基于 gofpdf；API 漂亮但带依赖",[349,2830,2831,2834,2837,2839,2842],{},[364,2832,2833],{},"unidoc/unipdf",[364,2835,2836],{},"约 12 行",[364,2838,2745],{},[364,2840,2841],{},"行样式辅助函数",[364,2843,2844],{},"商业许可",[18,2846,2847,2848,2850,2851,2853],{},"构建器行数比起来差距没那么大。真正的差异在用了 6 个月之后才显现。需求漂移时 —— 多了一列要不同对齐、报表要日文版、客户要在表尾打印行数 —— 用 ",[33,2849,1777],{}," 或 ",[33,2852,1780],{}," 每次都要碰行循环。用 gpdf 选项列表变长，正文不动。",[18,2855,2856,2857,2861,2862,470],{},"µs 级基准见 ",[211,2858,2860],{"href":2859},"/zh/blog/why-gpdf-is-faster","gpdf 为何更快","。更广维度的对比见 ",[211,2863,2865],{"href":2864},"/zh/blog/go-pdf-library-showdown-2026","2026 库总览",[14,2867,2869],{"id":2868},"表格里的-cjk","表格里的 CJK",[18,2871,2872],{},"上面对比表里看不到的事实：gpdf 原生渲染 CJK 字形。没有\"表格的中文模式\" —— 注册一次字体后表格就用它。",[26,2874,2876],{"className":28,"code":2875,"language":30,"meta":31,"style":31},"ttf, _ := os.ReadFile(\"NotoSansSC-Regular.ttf\")\ndoc := gpdf.NewDocument(\n    gpdf.WithPageSize(gpdf.A4),\n    gpdf.WithFont(\"NotoSansSC\", ttf),\n    gpdf.WithDefaultFont(\"NotoSansSC\"),\n)\n\nc.Table(\n    []string{\"日期\", \"发票号\", \"客户\", \"金额\"},\n    [][]string{\n        {\"2026-04-01\", \"INV-10001\", \"示例科技有限公司\", \"￥120,000\"},\n        {\"2026-04-02\", \"INV-10002\", \"山田商店\", \"￥38,500\"},\n    },\n    template.ColumnWidths(20, 20, 40, 20),\n)\n",[33,2877,2878,2908,2923,2942,2967,2986,2990,2994,3004,3045,3054,3094,3134,3138,3164],{"__ignoreMap":31},[36,2879,2880,2883,2885,2888,2890,2892,2894,2897,2899,2901,2904,2906],{"class":38,"line":39},[36,2881,2882],{"class":42},"ttf",[36,2884,60],{"class":46},[36,2886,2887],{"class":42}," _ ",[36,2889,606],{"class":46},[36,2891,1528],{"class":42},[36,2893,47],{"class":46},[36,2895,2896],{"class":50},"ReadFile",[36,2898,54],{"class":46},[36,2900,827],{"class":46},[36,2902,2903],{"class":830},"NotoSansSC-Regular.ttf",[36,2905,827],{"class":46},[36,2907,182],{"class":46},[36,2909,2910,2913,2915,2917,2919,2921],{"class":38,"line":69},[36,2911,2912],{"class":42},"doc ",[36,2914,606],{"class":46},[36,2916,609],{"class":42},[36,2918,47],{"class":46},[36,2920,614],{"class":50},[36,2922,617],{"class":46},[36,2924,2925,2928,2930,2932,2934,2936,2938,2940],{"class":38,"line":104},[36,2926,2927],{"class":42},"    gpdf",[36,2929,47],{"class":46},[36,2931,628],{"class":50},[36,2933,54],{"class":46},[36,2935,216],{"class":42},[36,2937,47],{"class":46},[36,2939,637],{"class":42},[36,2941,101],{"class":46},[36,2943,2944,2946,2948,2951,2953,2955,2958,2960,2962,2965],{"class":38,"line":153},[36,2945,2927],{"class":42},[36,2947,47],{"class":46},[36,2949,2950],{"class":50},"WithFont",[36,2952,54],{"class":46},[36,2954,827],{"class":46},[36,2956,2957],{"class":830},"NotoSansSC",[36,2959,827],{"class":46},[36,2961,60],{"class":46},[36,2963,2964],{"class":42}," ttf",[36,2966,101],{"class":46},[36,2968,2969,2971,2973,2976,2978,2980,2982,2984],{"class":38,"line":179},[36,2970,2927],{"class":42},[36,2972,47],{"class":46},[36,2974,2975],{"class":50},"WithDefaultFont",[36,2977,54],{"class":46},[36,2979,827],{"class":46},[36,2981,2957],{"class":830},[36,2983,827],{"class":46},[36,2985,101],{"class":46},[36,2987,2988],{"class":38,"line":521},[36,2989,182],{"class":46},[36,2991,2992],{"class":38,"line":531},[36,2993,489],{"emptyLinePlaceholder":488},[36,2995,2996,2998,3000,3002],{"class":38,"line":536},[36,2997,43],{"class":42},[36,2999,47],{"class":46},[36,3001,51],{"class":50},[36,3003,617],{"class":46},[36,3005,3006,3009,3011,3013,3015,3017,3019,3021,3023,3025,3027,3029,3031,3033,3035,3037,3039,3041,3043],{"class":38,"line":546},[36,3007,3008],{"class":46},"    []",[36,3010,313],{"class":312},[36,3012,824],{"class":46},[36,3014,827],{"class":46},[36,3016,831],{"class":830},[36,3018,827],{"class":46},[36,3020,60],{"class":46},[36,3022,838],{"class":46},[36,3024,841],{"class":830},[36,3026,827],{"class":46},[36,3028,60],{"class":46},[36,3030,838],{"class":46},[36,3032,850],{"class":830},[36,3034,827],{"class":46},[36,3036,60],{"class":46},[36,3038,838],{"class":46},[36,3040,859],{"class":830},[36,3042,827],{"class":46},[36,3044,2270],{"class":46},[36,3046,3047,3050,3052],{"class":38,"line":556},[36,3048,3049],{"class":46},"    [][]",[36,3051,313],{"class":312},[36,3053,952],{"class":46},[36,3055,3056,3058,3060,3063,3065,3067,3069,3072,3074,3076,3078,3081,3083,3085,3087,3090,3092],{"class":38,"line":566},[36,3057,2213],{"class":46},[36,3059,827],{"class":46},[36,3061,3062],{"class":830},"2026-04-01",[36,3064,827],{"class":46},[36,3066,60],{"class":46},[36,3068,838],{"class":46},[36,3070,3071],{"class":830},"INV-10001",[36,3073,827],{"class":46},[36,3075,60],{"class":46},[36,3077,838],{"class":46},[36,3079,3080],{"class":830},"示例科技有限公司",[36,3082,827],{"class":46},[36,3084,60],{"class":46},[36,3086,838],{"class":46},[36,3088,3089],{"class":830},"￥120,000",[36,3091,827],{"class":46},[36,3093,2270],{"class":46},[36,3095,3096,3098,3100,3103,3105,3107,3109,3112,3114,3116,3118,3121,3123,3125,3127,3130,3132],{"class":38,"line":576},[36,3097,2213],{"class":46},[36,3099,827],{"class":46},[36,3101,3102],{"class":830},"2026-04-02",[36,3104,827],{"class":46},[36,3106,60],{"class":46},[36,3108,838],{"class":46},[36,3110,3111],{"class":830},"INV-10002",[36,3113,827],{"class":46},[36,3115,60],{"class":46},[36,3117,838],{"class":46},[36,3119,3120],{"class":830},"山田商店",[36,3122,827],{"class":46},[36,3124,60],{"class":46},[36,3126,838],{"class":46},[36,3128,3129],{"class":830},"￥38,500",[36,3131,827],{"class":46},[36,3133,2270],{"class":46},[36,3135,3136],{"class":38,"line":581},[36,3137,2164],{"class":46},[36,3139,3140,3142,3144,3146,3148,3150,3152,3154,3156,3158,3160,3162],{"class":38,"line":586},[36,3141,72],{"class":42},[36,3143,47],{"class":46},[36,3145,77],{"class":50},[36,3147,54],{"class":46},[36,3149,673],{"class":82},[36,3151,60],{"class":46},[36,3153,93],{"class":82},[36,3155,60],{"class":46},[36,3157,1342],{"class":82},[36,3159,60],{"class":46},[36,3161,93],{"class":82},[36,3163,101],{"class":46},[36,3165,3166],{"class":38,"line":600},[36,3167,182],{"class":46},[18,3169,3170],{},"表头中文、正文中文、列宽仍然是百分比、跨页表头重复仍然生效。字体只对文档使用的字形做子集化，单页输出只 50 KB 左右，而完整 Noto Sans SC 是 6 MB。",[18,3172,3173,3174,3178],{},"字体登记本身见 ",[211,3175,3177],{"href":3176},"/zh/blog/embed-japanese-font","嵌入中文 TrueType 字体"," 食谱（同模式适用简繁中文）。本篇要点：数据是 CJK 时表格 API 不变。",[14,3180,3181],{"id":3181},"常见问答",[18,3183,3184],{},[21,3185,3186],{},"Q: 支持每行单独样式吗？",[18,3188,3189,3190,3193,3194,3197,3198,3200,3201,3203,3204,3207,3208,3210],{},"构建器 API 不行。构建器对正文取 ",[33,3191,3192],{},"[][]string","，所有正文单元格共享列派生的同一个 ",[33,3195,3196],{},"Style","。要单独行风格请去 ",[33,3199,200],{}," 层组装 —— 每个 ",[33,3202,1971],{}," 携带自己的 ",[33,3205,3206],{},"CellStyle","。模式直接，只是失去 ",[33,3209,3192],{}," 的便利。",[18,3212,3213],{},[21,3214,3215],{},"Q: 单元格里能放图片或嵌套表格吗？",[18,3217,3218,3220,3221,2356,3224,3227,3228,1860,3231,3234,3235,3238],{},[33,3219,200],{}," 层可以。",[33,3222,3223],{},"TableCell.Content",[33,3225,3226],{},"[]DocumentNode","，能放 ",[33,3229,3230],{},"*Text",[33,3232,3233],{},"*Image","，甚至嵌套 ",[33,3236,3237],{},"*Table","。构建器的字符串 API 不暴露，因为这是大多数用户不想要的尖锐边缘，但底层模型支持。",[18,3240,3241],{},[21,3242,3243],{},"Q: gpdf 怎么决定分页位置？",[18,3245,3246],{},"逐行。布局引擎按顺序测每行，加到当前页直到下一行会超出可用高度。那一行成为溢出表格的首行。还没有\"这些行不要分开\"标注 —— 每行都可分。要让发票行项目的逻辑组保持单页，要么手动在组前换页，要么去 document 层插入分页提示。",[18,3248,3249],{},[21,3250,3251],{},"Q: gpdf 能渲染的最大表格？",[18,3253,3254,3255,3258,3259,3261,3262,3264],{},"A4 上 1 万正文行已验证。正确分页，每页表头重绘，输出 PDF 约 150 页几百 KB。瓶颈不是表格布局，是单元格内容的文字塑形，复杂度 ",[33,3256,3257],{},"O(行 × 列)","。要 10 万+ 行就分块写盘（每 1 万行一次 ",[33,3260,1475],{},"），或在 ",[33,3263,200],{}," 层喂预塑形 run。",[18,3266,3267],{},[21,3268,3269],{},"Q: 表尾能只在最后一页出现吗？",[18,3271,3272,3273,3275,3276,3279],{},"内置不支持。",[33,3274,2400],{}," 设计上每页重复 —— 常见用途是分页列合计。要文档末尾出一次的汇总，作为表格 ",[21,3277,3278],{},"之后"," 的独立行块追加，不要放表格里。",[18,3281,3282],{},[21,3283,3284,3285,3287],{},"Q: ",[33,3286,1426],{}," 影响表头吗？",[18,3289,3290,3291,470],{},"影响。单元格边框对表头和正文一致。要表头边框不同（比如表头底边更粗），在 document 层组表头并对单元格设 ",[33,3292,3293],{},"CellStyle.Border",[14,3295,3296],{"id":3296},"设计大局",[18,3298,3299,3300,3303],{},"只带走一件事：",[21,3301,3302],{},"gpdf 表格 API 小，是因为表格问题几乎全归结为同样的三个问题。"," 列宽、斑马纹、分页。其余是长尾。把常见情况放构建器、长尾放 document 层是这笔交易 —— 日常每天的用途五行写完，需要构建器表达不了的事时不用付抽象代价。",[18,3305,3306,3307,3310],{},"代价坦白：没有 ",[33,3308,3309],{},"setRowStyle(i, ...)"," 捷径，也不会有。要把第 4 行和第 5 行做成不同样式，你已经越过构建器不打算处理的复杂度线。下沉一层。边界清晰且稳定。",[18,3312,3313],{},"全文到此。一次读完，之后这块 API 不用再多想。",[14,3315,3317],{"id":3316},"试用-gpdf","试用 gpdf",[18,3319,3320],{},"gpdf 是 Go 的 PDF 生成库。MIT、零依赖、原生 CJK。",[26,3322,3326],{"className":3323,"code":3324,"language":3325,"meta":31,"style":31},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[33,3327,3328],{"__ignoreMap":31},[36,3329,3330,3332,3335],{"class":38,"line":39},[36,3331,30],{"class":295},[36,3333,3334],{"class":830}," get",[36,3336,3337],{"class":830}," github.com/gpdf-dev/gpdf\n",[18,3339,3340,3344,3345],{},[211,3341,3343],{"href":213,"rel":3342},[215],"⭐ 在 GitHub 加星"," · ",[211,3346,3349],{"href":3347,"rel":3348},"https://gpdf.dev/zh/docs/quickstart",[215],"阅读文档",[14,3351,3352],{"id":3352},"相关阅读",[1794,3354,3355,3364,3370,3377,3384],{},[229,3356,3357,3360,3361,3363],{},[211,3358,3359],{"href":1728},"如何在 gpdf 表格中设置列宽？"," — ",[33,3362,77],{}," 边角细节",[229,3365,3366,3369],{},[211,3367,3368],{"href":1819},"如何创建斑马纹（隔行变色）表格？"," — 颜色选择与暗色主题",[229,3371,3372,3376],{},[211,3373,3375],{"href":3374},"/zh/blog/bootstrap-grid-thinking-for-pdf","PDF 的 Bootstrap 思维：gpdf 的 12 列网格"," — 表格百分比对应的父 Col",[229,3378,3379,3383],{},[211,3380,3382],{"href":3381},"/zh/blog/invoice-pdf-go-under-50-lines","Go 用不到 50 行生成发票 PDF"," — 表格在完整文档里的真实用法",[229,3385,3386,3389],{},[211,3387,3388],{"href":2859},"gpdf 为何比 gofpdf / gopdf / Maroto 快"," — 对比表背后的 µs 数字",[3391,3392,3393],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":31,"searchDepth":69,"depth":69,"links":3395},[3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410],{"id":16,"depth":69,"text":16},{"id":207,"depth":69,"text":207},{"id":268,"depth":69,"text":269},{"id":454,"depth":69,"text":455},{"id":1608,"depth":69,"text":1609},{"id":1733,"depth":69,"text":1734},{"id":1828,"depth":69,"text":1829},{"id":1904,"depth":69,"text":1905},{"id":2413,"depth":69,"text":2413},{"id":2703,"depth":69,"text":2703},{"id":2868,"depth":69,"text":2869},{"id":3181,"depth":69,"text":3181},{"id":3296,"depth":69,"text":3296},{"id":3316,"depth":69,"text":3317},{"id":3352,"depth":69,"text":3352},"2026-05-07","Go 里画 PDF 表格容易翻车。gpdf 把列宽、斑马纹、跨页表头重复压缩到一次 Table 调用。完整 API 与权衡。",false,"md",{"name":3416,"totalTime":3417,"tools":3418,"steps":3420},"用 gpdf 在 Go 中渲染包含列宽、斑马纹与跨页重复表头的多页表格","PT20M",[3419,541],"Go 1.22+",[3421,3424,3427,3430,3433,3436],{"name":3422,"text":3423},"安装 gpdf","在 Go 1.22+ 模块里执行 go get github.com/gpdf-dev/gpdf。核心库无外部依赖，只需这一行。",{"name":3425,"text":3426},"在 Col 内写一次 Table 调用","在 page.AutoRow → r.Col(12, ...) 内调用 c.Table(header, rows)。header 是 []string，rows 是 [][]string。无选项时各列均分。",{"name":3428,"text":3429},"用百分比设置每列宽度","传入 template.ColumnWidths(40, 15, 20, 25)。每个值是父 Col 宽度的百分比。缺省的尾部列会自动平分剩余空间。",{"name":3431,"text":3432},"为表头加样式并启用斑马纹","添加 template.TableHeaderStyle(template.TextColor(pdf.White), template.BgColor(brand)) 和 template.TableStripe(pdf.RGBHex(0xF5F5F5))。斑马纹只作用于正文行，表头不受影响。",{"name":3434,"text":3435},"让 gpdf 自动分页，表头会重复","传入超过单页容量的行数。gpdf 会跨页拆分正文，并在每个续页顶部重新绘制 Header 切片。无需 PageBreak 选项，无需手动计数。",{"name":3437,"text":3438},"需要 ColSpan / RowSpan / 固定宽度 / 表尾时切换到 document.Table","直接构造 &document.Table{Columns, Header, Body, Footer}。跨列单元格、固定 pt 列、每页重复的表尾都在这一层处理。Builder API 故意不暴露。",null,{},"/zh/blog/tables-in-go-pdfs",{"title":5,"description":3412},"zh/blog/022.tables-in-go-pdfs",[3445,3446,3447],"tutorial","templates","comparison","szMCBl0TehYkGNzfEG0Hdka18XeuupQwJTfbH2fIHeE",1779199016713]