在实际的业务开发中,我们经常会遇到需要为列表里的每一个元素单独打印一张票据的需求,比如电商场景下的订单小票打印、仓库管理中的库存标签打印、餐饮行业的后厨出单等。这种需求的核心是要保证每个列表元素对应的内容都能独立生成一张完整的打印页,不会出现多个元素内容挤在同一页的情况。

核心实现思路
实现这个需求的核心逻辑可以分为三个步骤:
- 遍历待打印的列表,获取每一个元素的具体数据
- 根据单个元素的数据渲染对应的票据模板,保证模板样式符合打印要求
- 针对每一个渲染好的票据内容,单独触发打印操作,或者生成独立的打印页面
前端实现方案
如果是纯前端场景,我们可以利用浏览器的打印API来实现。下面是一个基于JavaScript的实现示例,假设我们有一个订单列表,需要为每个订单单独打印小票:
// 待打印的订单列表
const orderList = [
{ id: '001', goodsName: '笔记本', price: 4999, count: 1 },
{ id: '002', goodsName: '鼠标', price: 199, count: 2 },
{ id: '003', goodsName: '键盘', price: 399, count: 1 }
];
// 渲染单个订单的票据内容
function renderOrderTicket(order) {
return `
<div class="ticket">
<h3>订单小票</h3>
<p>订单号:${order.id}</p>
<p>商品名称:${order.goodsName}</p>
<p>单价:${order.price}元</p>
<p>数量:${order.count}</p>
<p>总价:${order.price * order.count}元</p>
<p>感谢您的购买</p>
</div>
`;
}
// 为单个元素打印票据
function printSingleTicket(order) {
// 创建新的打印窗口
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>打印票据</title>
<style>
.ticket {
width: 80mm;
padding: 10px;
font-family: '微软雅黑';
}
.ticket h3 {
text-align: center;
margin-bottom: 10px;
}
.ticket p {
margin: 5px 0;
}
@media print {
body {
margin: 0;
}
}
</style>
</head>
<body>
${renderOrderTicket(order)}
</body>
</html>
`);
printWindow.document.close();
// 等待内容加载完成后触发打印
printWindow.onload = () => {
printWindow.print();
// 打印完成后关闭窗口
printWindow.onafterprint = () => {
printWindow.close();
};
};
}
// 遍历列表为每个元素打印票据
function printAllTickets(list) {
list.forEach(order => {
printSingleTicket(order);
});
}
// 调用方法执行打印
printAllTickets(orderList);
注意事项
前端实现时需要注意几个问题:
- 打印样式要单独适配,因为浏览器的打印模式和普通显示模式样式可能有差异,建议通过
@media print写专门的打印样式 - 如果列表元素很多,连续打开多个打印窗口可能会被浏览器拦截,这种场景下可以先把所有票据渲染到一个页面,通过CSS的分页属性让每个票据单独占一页,再统一打印
后端实现方案
如果是后端生成打印内容,比如用Python生成PDF格式的票据,再返回给前端打印,也可以实现每个列表元素对应一张独立票据。下面是Python的示例:
from reportlab.lib.pagesizes import A7
from reportlab.pdfgen import canvas
import os
# 单个订单数据
order_data_list = [
{"id": "001", "goods_name": "笔记本", "price": 4999, "count": 1},
{"id": "002", "goods_name": "鼠标", "price": 199, "count": 2},
{"id": "003", "goods_name": "键盘", "price": 399, "count": 1}
]
def generate_single_ticket(order, output_path):
"""生成单个订单的PDF票据"""
c = canvas.Canvas(output_path, pagesize=A7)
width, height = A7
# 设置字体,支持中文需要注册中文字体,这里省略注册步骤,假设已经注册了中文字体
c.setFont("SimHei", 12)
# 绘制票据内容
c.drawString(20, height - 30, "订单小票")
c.drawString(20, height - 50, f"订单号:{order['id']}")
c.drawString(20, height - 70, f"商品名称:{order['goods_name']}")
c.drawString(20, height - 90, f"单价:{order['price']}元")
c.drawString(20, height - 110, f"数量:{order['count']}")
c.drawString(20, height - 130, f"总价:{order['price'] * order['count']}元")
c.drawString(20, height - 150, "感谢您的购买")
c.save()
def generate_all_tickets(order_list, output_dir):
"""为列表所有元素生成独立票据"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
for order in order_list:
output_path = os.path.join(output_dir, f"ticket_{order['id']}.pdf")
generate_single_ticket(order, output_path)
print(f"已生成票据:{output_path}")
# 执行生成
generate_all_tickets(order_data_list, "./tickets")
常见问题解决
在实现过程中可能会遇到一些问题:
- 打印内容截断:需要检查票据模板的高度是否超过了打印纸的尺寸,调整内容的布局或者打印纸大小设置
- 样式错乱:如果是前端打印,要确认打印样式是否生效,避免使用flex等打印模式下支持不好的布局属性
- 批量打印卡顿:如果列表元素过多,建议分批处理,避免同时触发大量打印任务导致浏览器或系统卡顿
实现为列表中每个元素单独打印票据的核心就是保证每个元素的内容独立渲染、独立输出,根据具体的场景选择前端或者后端实现方案即可。