如何用PHP和JavaScript动态替换HTML表格中的占位符
问题描述
我开发了一款发票模板设计器,可用于设计发票模板,模板创建完成后,其HTML会保存到数据库中待用。现在用户使用该模板创建发票时遇到了问题:模板是带有占位符的表格(表格中包含[course_no_0]、[product_0]这类带索引的占位符),由于表格是动态生成的,无法直接通过PHP循环访问表格单元格,请问该如何替换表格单元格的值?需要相关思路及示例。
现有代码
if (!empty($_GET['invoice_id']) && $_GET['invoice_id']) { $invoice_id = $_GET['invoice_id']; $invoiceValues = getInvoice($invoice_id); $invoiceItems = getInvoiceItems($invoice_id); } $invoiceDate = date("d/M/Y, H:i:s", strtotime($invoiceValues['order_date'])); $template_name = getinvoicetemplatename(); $template = get_template($template_name[0]); // 替换模板变量 $token = array( '[Business_Name]' => 'http://www.codexworld.com', '[Business_Address_1]' => 'CodexWorld', '[City]' => $userName, '[State]' => $userEmail, '[Postal_Code]' => 'http://www.codexworld.com', '[Business_Phone_Number]' => 'CodexWorld', '[Business_Email_Address]' => $userName, '[Client_Name]' => $userEmail, '[Client_Address_line_1]' => 'http://www.codexworld.com', '[Invoice_Number]' => 'CodexWorld', '[Date]' => $invoiceDate ); foreach ($token as $key => $value){ $output = str_replace($key, $value, $template[0]); } $i = 0; foreach ($invoiceItems as $invoiceItem) { $i++; $output = str_replace("[course_no_{$i}]", $invoiceItem["item_code"], $output); $output = str_replace("[product_{$i}]", $invoiceItem["item_name"], $output); $output = str_replace("[delegates_no_{$i}]", $invoiceItem["order_item_quantity"], $output); $output = str_replace("[price_{$i}]", $invoiceItem["order_item_price"], $output); $output = str_replace("[total_{$i}]", $invoiceItem["order_item_final_amount"], $output); }
模板HTML字符串
<div id="items-list"> <table id="table-invoice" class="table table-bordered table-condensed items-table" width="100%"> <thead> <tr id="table_invoice_header"> <th id="table_invoice_header1">Course No</th> <th id="table_invoice_header2">Course Name</th> <th id="table_invoice_header3">No of Delegates</th> <th id="table_invoice_header4" width="100">Price</th> <th id="table_invoice_header5" width="100">Total</th> </tr> </thead> <tbody> <tr> <td class="total-rown">[course_no_0] </td> <td class="total-rown">[product_0] </td> <td class="total-rown">[delegates_no_0] </td> <td class="total-rown">[price_0] [curr]</td> <td class="total-rown">[total_0] [curr]</td> </tr> <tr> <td class="total-rown">[course_no_1] </td> <td class="total-rown">[product_1] </td> <td class="total-rown">[delegates_no_1] </td> <td class="total-rown">[price_1] [curr]</td> <td class="total-rown">[total_1] [curr]</td> </tr> <tr> <td class="total-rown">[course_no_2] </td> <td class="total-rown">[product_2] </td> <td class="total-rown">[delegates_no_2] </td> <td class="total-rown">[price_2] [curr]</td> <td class="total-rown">[total_2] [curr]</td> </tr> <tr> <td class="total-rown">[course_no_3] </td> <td class="total-rown">[product_3] </td> <td class="total-rown">[delegates_no_3] </td> <td class="total-rown">[price_3] [curr]</td> <td class="total-rown">[total_3] [curr]</td> </tr> <tr> <td class="total-rown">[course_no_4] </td> <td class="total-rown">[product_4] </td> <td class="total-rown">[delegates_no_4] </td> <td class="total-rown">[price_4] [curr]</td> <td class="total-rown">[total_4] [curr]</td> </tr> </tbody> <tfoot> <tr class="totals-row"> <td colspan="3" class="wide-cell"></td> <td id="tableheader"><strong>Sub Total</strong></td> <td class="total-rown sub-total" coslpan="2">[sub_total] [curr]</td> </tr> <tr class="totals-row"> <td colspan="3" class="wide-cell"></td> <td class="total-rown" id="tableheader">Tax Rate</td> <td class="total-rown tax-rate" coslpan="2">[tax_rate] %</td> </tr> <tr class="totals-row"> <td colspan="3" class="wide-cell"></td> <td class="total-rown">Tax Amount</td> <td class="total-rown tax-amount" coslpan="2">[tax_amount] [curr]</td> </tr> <tr class="totals-row"> <td colspan="3" class="wide-cell"></td> <td id="tableheader1"><strong>Total</strong></td> <td class="total-rown invoice-total" coslpan="2">[total] [curr]</td> </tr> </tfoot> </table> </div>
解决方案
核心思路
- 修正基础变量替换逻辑:原代码每次替换token都从原始模板重新处理,导致只有最后一个token生效,需先初始化
$output为模板内容,再循环替换所有token。 - 对齐占位符索引:模板占位符从
0开始,但原代码$i先自增再替换,导致第一个数据项匹配错误,需调整索引起始值。 - 清理多余空行:模板有固定行数,若实际发票项少于模板行数,需移除未被替换的占位符行,避免显示无效内容。
- 批量替换优化:使用
strtr()或批量str_replace()提升替换效率,减少重复操作。
修正后的代码示例
if (!empty($_GET['invoice_id']) && $_GET['invoice_id']) { $invoice_id = $_GET['invoice_id']; $invoiceValues = getInvoice($invoice_id); $invoiceItems = getInvoiceItems($invoice_id); } $invoiceDate = date("d/M/Y, H:i:s", strtotime($invoiceValues['order_date'])); $template_name = getinvoicetemplatename(); $template = get_template($template_name[0]); // 初始化输出为模板内容 $output = $template[0]; // 替换全局静态变量 $token = array( '[Business_Name]' => 'http://www.codexworld.com', '[Business_Address_1]' => 'CodexWorld', '[City]' => $userName, '[State]' => $userEmail, '[Postal_Code]' => 'http://www.codexworld.com', '[Business_Phone_Number]' => 'CodexWorld', '[Business_Email_Address]' => $userName, '[Client_Name]' => $userEmail, '[Client_Address_line_1]' => 'http://www.codexworld.com', '[Invoice_Number]' => 'CodexWorld', '[Date]' => $invoiceDate, // 补充合计相关变量替换 '[sub_total]' => $invoiceValues['sub_total'], '[tax_rate]' => $invoiceValues['tax_rate'], '[tax_amount]' => $invoiceValues['tax_amount'], '[total]' => $invoiceValues['total'], '[curr]' => $invoiceValues['currency'] ); // 批量替换全局变量,效率更高 $output = strtr($output, $token); // 替换发票明细项,索引从0开始 foreach ($invoiceItems as $i => $invoiceItem) { $output = str_replace("[course_no_{$i}]", $invoiceItem["item_code"], $output); $output = str_replace("[product_{$i}]", $invoiceItem["item_name"], $output); $output = str_replace("[delegates_no_{$i}]", $invoiceItem["order_item_quantity"], $output); $output = str_replace("[price_{$i}]", $invoiceItem["order_item_price"], $output); $output = str_replace("[total_{$i}]", $invoiceItem["order_item_final_amount"], $output); } // 移除未被替换的空行(匹配包含未替换占位符的<tr>行) $output = preg_replace('/<tr>(.*?)\[course_no_\d+\](.*?)<\/tr>/s', '', $output);
代码说明
- 全局变量替换:使用
strtr()一次性替换所有静态变量,比循环str_replace()更高效。 - 明细项索引对齐:直接使用foreach的键值
$i作为占位符索引,和模板的0起始索引匹配。 - 空行清理:通过正则表达式匹配包含未替换占位符的表格行,直接移除,避免显示无效内容。
- 补充合计变量:添加了模板中存在的
[sub_total]、[curr]等合计相关变量的替换,完善模板内容。
内容的提问来源于stack exchange,提问作者Landry
相关产品推荐
相关产品推荐

