详解window.print(),实现长列表打印分页
相信大家平时做项目时,打印需求很常见,但想把打印做好,还是要花点时间的。特别是长列表要分页的情况。
我们知道浏览原生 API `window.print()` 可以用于印当前窗口(window.document)视图内容。调用此方法会产生一个打印预览弹框,用户可以根据具体设置来得到打印结果。
一、window的打印事件
默认情况下,调用 window.print() 会对整个 document.body 进行打印,当需要打印指定容器内容时,可以这样做:
1、先获取指定容器中的内容,将body的内容替换掉,调用了打印方法后,再把原来的body恢复。
<body><div id="container1"><p>这是第一个段落</p></div><div id="container2"><p>这是第二个段落</p></div><input type="button" value="打印此页面" onclick="printPage()" /><script>const printPage= () => {let newstr = document.getElementById("container1").innerHTML;let oldstr = document.body.innerHTML;document.body.innerHTML = newstr;window.print();document.body.innerHTML = oldstr;</script>
</body>
2、监听打印前、后事件实现区域打印
window.onbeforeprint()、window.onafterprint()
<body><div id="container"><p>这是一个段落</p><h1 id="title">这是一个标题</h1></div><input type="button" value="打印此页面" onclick="printPage()" /><script>const printPage= () => {window.print();}// 打印前事件window.onbeforeprint = function() {// 隐藏不需要打印的元素document.getElementById('title').style.display = 'none';}// 打印完成后window.onafterprint = function() {// 放开隐藏的元素document.getElementById('title').style.display = 'block';}</script>
</body>
二、打印样式
我们页面的样式和打印页面时的样式是两个不同的样式,打印时会默认携带页面的样式,同时呢我们也可以修改页面打印时的样式。修改打印样式的方法:
1、使用内联media属性
<style media="print">.container{width:800px;}
</style>
2、使用媒体查询
<style>@media print {h1{color: #333;background: #ccc;}}
</style>
3、引入打印样式表
例如:print.css
@media print {@page {size: auto;margin: 20px 30px;}#mainBody{margin-top:0 !important;margin-bottom:0 !important;}
}
用link引入
<link rel="stylesheet" type="text/css" href="./css/print.css" media="print" />
注意:
1、如果是前后不分离的项目,在样式中用到`@`时可能会报错:"上下文中未定义@media或@page",这时候我们可以用`<link>`的方式引入。
2、修改打印样式时必须确保打印机样式实际上确实覆盖了主样式表。可以使用!important。
3、@page属性可以控制打印页面的边距大小和页眉页脚
@media print {@page {size: auto; // {size:A4}、{size: 800px 1200px}、{size:portrait}竖向打印、{size:landscape}横向打印margin: 20px 30px; // 边距,可去除页眉页脚}// 覆盖页面原有样式#container{margin-top:0 !important;margin-bottom:0 !important;} }4、-webkit-print-color-adjust:是一个在浏览器中强制打印背景颜色和字体颜色的css属性,当打印出来的某些元素的背景颜色没有被显示时,可以使用
-webkit-print-color-adjust:exact
5、当需要自定义打印分页时机时,可通过如下方式将指定 DOM 设为分割点。@media print {h1 {page-break-before: always; //在指定元素前面添加分页符}#title {page-break-after: always;//在指定元素后面添加分页符} }了解更多:page-break-after - CSS:层叠样式表 | MDN
三、长列表打印
打印长列表时会要求自动分页,但添加了分页符效果可能并不理想。最常见的就是表格行被从中间截断,那要怎么解决呢?
其实我们只要控制打印的行数就可以了。我们需要知道打印元素的高度和表格行的高度,算出一页纸可以打印多少行,超出的部分放到下一页打印。(一页放多少行没必要计算,根据打印元素的高度估算下就可以了。)
示例:
<style>body {font-family: "微软雅黑",Verdana,SimHei,"Microsoft JhengHei",Tahoma;line-height: 1.5;background-color: #ffffff;margin: 0;}// 打印容器#mainBody {margin: 20px 20px 0 20px;}table {border: 1px solid #000;border-collapse: collapse;width: 100%;}table td {border: 1px solid #000;height: 30px;text-align: center;}table th {border: 1px solid #000;height: 30px;text-align: center;}.printContainer {margin: 0 auto;// 打印内容宽高width: 1052px;height: 1480px;position: relative;}.printTitle {font-size: 22px;font-weight: bold;text-align: center;}.printnav {display: flex;justify-content: space-between;}.signature_footer {position: absolute;width: 100%;bottom: -20px;display: flex;justify-content: space-around;font-size: 20px;}
</style>
<body><div id="mainBody"></div>
</body><script>$(document).ready(function () {getList()})//获取地址栏参数function getUrlParam(name) {var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象var r = window.location.search.substr(1).match(reg); //匹配目标参数if (r != null) return unescape(r[2]); return null; //返回参数值}// 将列表数据分页,array要分页的数据,subNum是每页多少条(根据纸张大小估算一页能展示多少条)function groupArray(array, subNum) {let index = 0let newArray = []while (index < array.length) {newArray.push(array.slice(index, (index += subNum)))}return newArray}// 获取数据源,页面添加元素function getList() {var params = {PatientID: getUrlParam('PatientID'),BedNo: getUrlParam('BedNo'),xdStartDate: getUrlParam('StartDate'),xdEndDate: getUrlParam('EndDate')}$.get('/IndexPrintList', params, function (res) {// 先清空上一次的数据$('#mainBody').empty()// 分页的数据,返回的数组长度即页数var arr = groupArray(res.alist, 14)if (arr.length) {for (let i = 0; i < arr.length; i++) {// 创建打印元素$('#mainBody').append(`<div class="printContainer"><div class="printTitle">${res.hospitalName}</div><div style="text-align:center;font-weight:bold;font-size:20px;margin:20px 0;">定点血糖记录表</div><div class="printnav" style="margin: 10px 0; font-size:14px;"><div>患者ID: ${res.patientModel.no}</div><div>姓名:${res.patientModel.name}</div><div>性别: ${res.patientModel.sex == 0 ? "男" : "女"}</div><div>病区:${res.patientModel.Bed.WardModel.wardName}</div><div>床号:${res.patientModel.Bed.innerOrder}</div><div>测量次数:${res.allNum}</div></div><div class="printContent"><table><thead><tr><th colspan="2">日期\监测点</th>${res.SortList.map(column => {return `<th>${column.name}</th>`}).join("")}</tr></thead><tbody>${arr[i].map(row => {return `<tr><td rowspan="3" style="width:90px">${row.measureTime}</td><td>血糖值(mmol/L)</td>${res.MeasurePointList.map(point => {if (row.dict[point.id]) {return `<td style="color:${row.dict[point.id].color}"> ${row.dict[point.id].Value}</td>`} else {return `<td></td>`}}).join("")}</tr><tr><td>操作者</td>${res.MeasurePointList.map(point => {if (row.dict[point.id]) {return `<td>${row.dict[point.id].AccountName}</td>`} else {return `<td></td>`}}).join("")}</tr><tr><td>测量时间</td>${res.MeasurePointList.map(point => {if (row.dict[point.id]) {return `<td>08:00</td>`} else {return `<td></td>`}}).join("")}</tr>`}).join("")}</tbody></table></div><div class="signature_footer"><div>医生手签:</div><div style="margin-right:30px;">质控护士手签:</div></div></div>`)}}window.print();})}</script>
代码解释:
1、首先给打印元素设置宽和高,高度根据需要或实际情况设置。(可根据A4纸大小来定)
2、通过接口拿到长列表数据,然后用`groupArray`方法计算需要打印几页。(groupArray函数返回一个二维数据,二维数组的长度就是页数,二维数组的每一项就是每页的数据)
3、根据这个二维数组循环创建要打印的元素。(类`.printContainer`是要打印的整体内容,即一页纸的内容,arr[i]就是每页的表格数据)
4、示例中每页都加了标题和签名,表格有合并单元格。
5、简单表格如下:
<table><thead><tr><th>检测日期</th><th>检测值</th><th>操作护士</th></tr></thead><tbody>${arr[i].map(item=>{return `<tr><td>${item.MeasureDateStr}</td><td>${item.value}</td><td>${item.AccountName}</td></tr>`}).join("")}</tbody>
</table>
相关文章:
详解window.print(),实现长列表打印分页
相信大家平时做项目时,打印需求很常见,但想把打印做好,还是要花点时间的。特别是长列表要分页的情况。 我们知道浏览原生 API window.print() 可以用于印当前窗口(window.document)视图内容。调用此方法会产生一个打印…...
使用Chatgpt编写的PHP数据库pdo操作类(增删改查)
摘要 将PDO封装成PHP类进行调用有很多好处,包括: 1、封装性和抽象性: 通过将PDO封装到一个类中,您可以将数据库操作逻辑与应用程序的其他部分分离开来,提高了代码的组织性和可维护性。这样,您只需在一个地…...
蓝桥杯2023年第十四届省赛真题-异或和之和--题解
目录 蓝桥杯2023年第十四届省赛真题-异或和之和 题目描述 输入格式 输出格式 样例输入 样例输出 【代码实现】 大家觉得写得可以的话,可以加入QQ群907575059. 蓝桥杯2023年第十四届省赛真题-异或和之和 时间限制: 3s 内存限制: 320MB 提交: 241 解决: 66 …...
Linux 常用命令学习笔记
Linux 常用命令学习笔记 文件操作 ls:列出当前目录下的文件和文件夹。 ls -l:以长格式显示文件和文件夹的详细信息。ls -a:显示所有文件,包括隐藏文件。 cd [目录]:切换到指定目录。pwd:显示当前工作目录…...
支撑电动汽车规模化,特来电智能化升级群充产品
9月26日,中国领先的充电网生态运营商特来电重磅发布智能群充4.0产品,标志着特来电群充产品体系进一步升级,充电行业迎来更高质量、更高性能的设备与系统,充电网基础设施将更好地支撑大规模电动汽车的发展。 群充技术路线引领充电…...
本次CTF·泰山杯网络安全的基础知识部分
简记23年九月参加的泰山杯网络安全的部分基础知识的题目,随时补充 1. 国密算法哪个属于公钥? SM2 a. 国产密码算法(国密算法)是指国家密码局认定的国产商用密码算法,目前主要使用公开的SM2、SM3、SM4三类算法&#x…...
通信协议:Uart的Verilog实现(下)
4、UART接收器 UART接收器负责接收串行比特流,去除起始位和停止位,并以并行格式将数据保存到与主机数据总线相连的寄存器里。接收器无法获得发送时钟,因此尽管数据以标准比特率到达,但数据未必与接收主机内的时钟同步。同步问题可…...
嵌入式MCU都有什么高级用法?
嵌入式MCU都有什么高级用法? 您举的几个例子,确实是MCU外设的一些高端玩法。只是不知道您是否想过,既然这些机制是被 人设计出来的,那它就是种标准用法。从微控制器的发展历程来看,许多硬件机制都是有了实际 需求后才…...
热启动和冷启动是什么,区别
app冷启动: 当应用启动时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用, 这个启动方式就叫做冷启动(后台不存在该应用进程)。冷启动因为系统会重新创建一个新的进程分配给它ÿ…...
每日一题 494目标和(0-1背包)(灵神笔记)
0-1背包模版 有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和? 当前操作?枚举第i个物品选还是不选,不选容量不变,选容量减少 子问题ÿ…...
软件测试工作步骤详情
软件测试步骤按照研发阶段一般分为5个部分:单元测试、集成测试、确认测试、系统测试、验收测试,下面将不同阶段需要的一些工作内容做一下梳理希望可以帮助到大家。 一、单元测试的内容:(白盒为主,黑盒为辅)…...
java项目之列车票务信息管理系统(ssm源码+文档)
项目简介 列车票务信息管理系统实现了以下功能: 管理员:个人中心、用户管理、车票信息管理、购票指南管理、管理员管理、论坛管理、我的收藏管理、系统管理、订单管理。前台首页:首页、车票信息、购票指南、我的收藏管理、论坛信息、我的、…...
【Pytorch笔记】3.数学运算
深度之眼官方账号 - 01-03-mp4-张量操作与线性回归 torch.add() 功能:逐元素计算inputalphaother。 torch.add(input,alpha1,other,outNone)input:tensor; alpha:other的系数,是个实数; other࿱…...
MeterSphere 监控方案
前言:在部署MeterSphere之后,很多时候需要看下MeterSphere服务的监控信息,虽然有监控告警脚本,但还不是太直观,所以就结合 PrometheusExporterGrafana 部署一套完整的MeterSphere监控方案。 首先我们先罗列一下需要监控…...
elementui-plus+ts+axios使用el-upload组件自定义上传
1.前言: 使用element ui有很多便捷之处,但是由于是封装的组件和自己写还是有些许的不一样,这里主要解决几个问题。 1. 如何获取子组件实例 2. 如何自定义上传方法 2.两个问题: ⛺️ 获取子组件实例 实际上vue一般通过ref获取子组…...
【STM32单片机】u8g2智能风扇设计
文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器,使用按键、IIC OLED模块、DS18B20温度传感器、直流电机、红外遥控等。 主要功能: 初始化后进入温度显示界面,系统初始状态为手动…...
Java中的IO流的缓冲流
不爱生姜不吃醋⭐️ 如果本文有什么错误的话欢迎在评论区中指正 与其明天开始,不如现在行动! 文章目录 🌴IO流体系结构🌴缓冲流1.提高效率的原理2.缓冲流的类型3.字符缓冲流两个特有方法 🌴总结 🌴IO流体系…...
7、SpringBoot_高级配置
一、配置高级 1.临时属性设置 1.1引出问题 如果目标电脑上8080端口已经使用,再次使用该端口会出现端口占用问题 解决方式 重新更换配置文件修改端口打包通过临时属性配置新端口更换配置文件 1.2添加临时属性配置 通过临时属性修改8080端口 java -jar 项目.jar…...
cocos2dx查看版本号的方法
打开文件:项目根目录\frameworks\cocos2d-x\docs\RELEASE_NOTES.md 知道引擎版本号的意义: 1.面试中经常被问到(面试官想知道你会不会查版本号,你会查也不一定会去看,如果你去看了说明你是一个有心人,或者想深入研究下…...
某高校的毕设
最近通过某个平台接的单子,最后Kali做的测试没有公开可以私聊给教程。 下面是规划与配置 1.vlan方面:推荐一个vlan下的所有主机为一个子网网段 连接电脑和http客户端的接口配置为access接口 交换机与交换机或路由器连接的接口配置为trunk接口---也可以…...
基于Slack与AI的IDE智能助手:架构设计与实战部署
1. 项目概述:当你的IDE拥有了“光标智能体” 如果你是一名开发者,每天在IDE(集成开发环境)里敲代码的时间超过8小时,那你一定对这样的场景不陌生:光标在代码行间跳跃,你正试图理解一个复杂的函…...
北京明光云振铎数据科技Java面经
Nacos、OpenFeign、Gateway 三个组件的作用及协作流程首先:Nacos 主要负责服务注册发现和配置中心Gateway 作为统一网关入口,负责路由、鉴权、限流OpenFeign 负责服务之间的远程调用用户请求先进入 GatewayGateway 会先做 JWT 鉴权,比如校验 …...
Mochi语言解析:轻量级编程语言的设计原理与应用实践
1. 项目概述:一个为现代应用而生的轻量级编程语言最近在社区里看到不少朋友在讨论mochilang/mochi这个项目,作为一个对编程语言设计和运行时实现有浓厚兴趣的老码农,我立刻就被吸引住了。简单来说,Mochi 是一个新兴的、以轻量级和…...
“梦想、汗水、坚持”2026 SNH48 GROUP年度青春盛典5月30日正式启动
“十三而砺,向新而行。”中国大型青春女团SNH48 GROUP运营方上海丝芭文化传媒集团有限公司即日宣布:2026 SNH48 GROUP第十三届年度青春盛典大型系列活动将于5月30日正式启动,本届年度青春盛典颁奖典礼暨汇报演唱会定档8月8日,落地…...
ARM核心板在POCT设备开发中的选型与应用实战
1. 项目概述:ARM核心板如何重塑POCT设备开发在医疗设备这个对稳定性和可靠性要求近乎苛刻的领域,每一次技术选型都像是一次精密的手术,容不得半点闪失。我接触过不少体外诊断(IVD)设备厂商,尤其是做即时检验…...
量子退火误差缓解:经典阴影与局部虚拟纯化技术
1. 量子退火中的误差挑战与经典阴影方法量子退火(Quantum Annealing, QA)作为量子计算领域的重要算法,在优化问题求解中展现出独特优势。然而,实际硬件实现时面临的退相干问题严重制约了其计算精度。传统量子纠错方案需要大量物理…...
OpenGL 调试方式
调试手段总览 API 级错误检查:glGetError、断言、包装宏调试输出机制:GL_KHR_debug、glDebugMessageCallback、QOpenGLDebugLogger着色器与程序调试:编译/链接日志、离线编译器、颜色编码调试渲染结果调试:FBO 检查、glReadPixels…...
ARMv8 PMU架构与性能监控实战指南
1. ARMv8 PMU架构深度解析在ARMv8架构中,性能监控单元(Performance Monitor Unit, PMU)是处理器微架构层面的重要组件,它为开发者提供了硬件级别的性能数据采集能力。不同于传统的软件性能分析工具,PMU通过专用寄存器直接监控处理器内部事件&…...
弃ReID跨镜,选镜像无感定位——打破跨镜追踪断链困局,实现全域精准无感感知
弃ReID跨镜,选镜像无感定位——打破跨镜追踪断链困局,实现全域精准无感感知在安防监控、智慧园区、商业综合体、交通枢纽等场景中,跨摄像头目标追踪是核心需求之一——无论是人员轨迹追溯、异常行为预警,还是资产安全管控、流量数…...
基于CRICKIT与CPX的交互式电子展板:从传感器到执行器的完整原型开发指南
1. 项目概述:打造一个会“思考”和“反应”的电子展板如果你对Arduino或树莓派这类微控制器项目感兴趣,但又觉得从零开始连接电机、灯带、传感器,还要处理复杂的电源和信号问题,过程太过繁琐和容易出错,那么这个项目可…...
