/ 处理打印元素项, 修复分页后被切割的元素 @param printContainerRef 打印内容div容器 @param itemClassName 打印最小元素标识类名 @param outFlowClassName 分开文档流的元素标识类名 /export function handlePrintItem( printContainerRef: HTMLElement, itemClassName: string = 'print-item', outFlowClassName: string = 'print-out-flow'): void { const rootClientRect = printContainerRef.getBoundingClientRect(); // 初始化页面干系数据 const totalHeight = rootClientRect.height; // 内容总高度 const a4PageHeight = (printContainerRef.clientWidth / 595.28) 841.89; // a4纸高度 let pageNum = Math.ceil(totalHeight / a4PageHeight); // 总页数 let addPageHeight = 0; // 改动被分割元素而增加的页面高度总和 let currentPage = 1; // 当前正在处理切割的页面 const splitItemObj: { [key: number]: HTMLElement[] } = {}; // 内容中各页被切割元素存储工具 const printItemNodes: NodeListOf<HTMLElement> = printContainerRef.querySelectorAll(`.${itemClassName}`); for (let item of printItemNodes) { // 如果当前页已经是末了一页, 则中断判断 if (currentPage >= pageNum) { break; } // 获取元素绝对定位数据 const clientRect = item.getBoundingClientRect(); let top = clientRect.top; const selfHeight = clientRect.height; // 如果当前元素间隔顶部高度大于当前页面页脚高度, 则开始判断下一页页脚被切割元素 if (top > currentPage a4PageHeight) { // 换页前改动上一页被切割元素 addPageHeight += fixSplitItems(currentPage, a4PageHeight, splitItemObj[currentPage], outFlowClassName); pageNum = Math.ceil((totalHeight + addPageHeight) / a4PageHeight); top = item.getBoundingClientRect().top; currentPage++; } // 如果元素刚好处于两页之间, 则记录该元素 if (top > (currentPage - 1) a4PageHeight && top < currentPage a4PageHeight && top + selfHeight > currentPage a4PageHeight) { if (!splitItemObj[currentPage]) { splitItemObj[currentPage] = []; } splitItemObj[currentPage].unshift(item); // 如果当前元素是末了一个元素, 则直接处理切割元素, 否则交由处理下一页元素时再处理切割 if (item === printItemNodes[printItemNodes.length - 1]) { fixSplitItems(currentPage, a4PageHeight, splitItemObj[currentPage], outFlowClassName); } } }}/ 修复当前页所有被切割元素 @param currentPage 当前页 @param pageHeight 每页高度 @param splitElementItems 当前被切割元素数组 @param outFlowClassName 分开文档流的样式类名 /function fixSplitItems( currentPage: number, pageHeight: number, splitElementItems: HTMLElement[], outFlowClassName: string): number { if (!splitElementItems || !splitElementItems.length) { return 0; } const yMargin = 5; // y方向间隔页眉的间隔 const splitItemsMinTop = getSplitItemsMinTop(splitElementItems); if (!splitItemsMinTop) { return 0; } let fixHeight = currentPage pageHeight - splitItemsMinTop + yMargin; const outFlowElement = splitElementItems.find((item) => item.classList.contains(outFlowClassName)); if (outFlowElement && outFlowElement.parentElement) { const parentPreviousElement = outFlowElement.parentElement.previousElementSibling as HTMLElement; fixHeight += getMarinTopNum(parentPreviousElement, outFlowElement.parentElement); outFlowElement.parentElement.style.marginTop = `${fixHeight}px`; return fixHeight; } splitElementItems.forEach((splitElement) => { splitElement.style.marginTop = `${fixHeight}px`; }); return fixHeight;}/ 获取被切割元素数组中最小高度值(如一行有多个元素被切割,则选出间隔顶部最小的高度值) @param splitElementItems 当前被切割元素数组 /function getSplitItemsMinTop( splitElementItems: HTMLElement[]): number | undefined { // 获取元素中最小top值作为基准进行改动 let minTop: number | undefined; let minElement: HTMLElement | undefined; splitElementItems.forEach((splitElement) => { let top = splitElement.getBoundingClientRect().top; if (minTop) { minTop = top < minTop ? top : minTop; minElement = top < minTop ? splitElement : minElement; } else { minTop = top; minElement = splitElement; } }); // 改动当前节点及其前面同层级节点的margin值 if (minTop && minElement) { const previousElement = splitElementItems[splitElementItems.length - 1].previousElementSibling as HTMLElement; minTop -= getMarinTopNum(previousElement, minElement); } return minTop;}/ 通过前一个兄弟元素和元素自身的位置确认一个间隔顶部高度改动值 @param previousElement 前一个兄弟元素 @param curElement 当前元素 /function getMarinTopNum(previousElement: HTMLElement, curElement: HTMLElement): number { let preMarginNum = 0; let curMarginNum = 0; if (previousElement) { // 获取外联样式须要getComputedStyle(), 直接.style时工具的值都为空 const previousMarginBottom = window.getComputedStyle(previousElement).marginBottom; preMarginNum = previousMarginBottom ? Number(previousMarginBottom.replace('px', '')) : 0; } const marginTop = window.getComputedStyle(curElement).marginTop; curMarginNum = marginTop ? Number(marginTop.replace('px', '')) : 0; return preMarginNum > curMarginNum ? preMarginNum : curMarginNum;}
以上纯原创!
欢迎加关注、加收藏、点赞、转发、分享(代码闲聊站)~