请教一个html打印问题,困扰了好久?

需求:打印自提点订单面单。用的是window自带的print,但是发现细节很多。
主要的问题有。
1、第一步需要将需要打印的页面呈现出来,如何设置页面和打印的页面保持一比一呢?我百度了一下,a4纸的大小,px和cm都尝试了,但是还是和打印页面不一致。为什么要一比一还原呢?是因为在网页上面显示了10条数据,但是打印界面10条数据却放不下跑到第二页了。

2、如何确定每页的表格要显示多少条数据呢?因为有的数据占2行,有的占1行,有的占3行。

因为真实的情况,涉及到单元格的合并,打印指定的区域(下面代码已实现)等等需求。
所以,我需要先确定好每页展示多少条数据,不然的话,有可能这页的数据跑到了下一页,就变的很难看。有时候恰好最后一个数据是合并的数据就更麻烦了。

我的思路是先确定好每页显示多少条,然后才知道要分多少页。单独对每页的数据再做合并操作。
要确定多少条就要知道真实情况下a4纸的宽高,以及针对商品名称超长的时候,分多行显示,表格最多容纳多少条数据。

下面是多多的提货单

image.png

image.png

代码如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <!-- import CSS -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <style>
        .main {
            /*width: 800px ;*/
            /* border: 1px solid red; */
            margin: 0 auto;

        }

        .item {
            width: 595px;
            height: 842px;
            /*border: 1px solid gray;*/
            margin-bottom: 5px;
        }

        table {
            font-size: 10px;
        }

        td {
            page-break-inside: avoid;
        }
    </style>

    <style media="print">
        @page {
            size: A4 portrait;  /*设置纸张及其方向    这里表示使用A4纸张,打印方向为纵向*/
            margin: 0; /* 设定页边距 */
        }
        .item {
            page-break-after: always;
        }
    </style>
</head>
<body>
<div id="app">
    <el-button @click="print">打印</el-button>

    <div id="printDiv" class="main">
        <div class="item">
            <div style="display: flex;justify-content: center;font-size: 25px">
                幸福里超市 - 用户提货单
            </div>
            <div>
                <span>提货日期:2023-10-23</span>
                <br>
                <span>门店地址:xxxxxxxxxxxxxxxxxxx</span>
            </div>
            <div>
                订单按照手机号最后一位从小到大0~9排列
            </div>
            <table border="1" bordercolor="black" width="100%" cellspacing="0" cellpadding="1">
                <tr>
                    <th>手机号</th>
                    <th>订单号</th>
                    <th>商品条码</th>
                    <th>商品名称</th>
                    <th width="35px">数量</th>
                </tr>
                <tr v-for="(item,index) in 17">
                    <td>
                        <p>15515656xxx</p>
                        <p>张三</p>
                    </td>
                    <td>20231004220109744001</td>
                    <td>15672657382</td>
                    <td>常规款-送亲果定制手提袋|约3斤/箱送亲果定制手提袋|约3斤/箱送亲果定制手提袋|约3斤/箱提袋|约3斤/箱送亲果定制手提袋|约3斤/箱</td>
                    <td>23</td>
                </tr>
            </table>
            <div style="display: flex;align-items: center; justify-content: center;">
                第1页,共3页
            </div>
        </div>
        <div class="item">第二页</div>
        <div class="item">第三页</div>
    </div>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

<script>
    new Vue({
        el: '#app',
        data: function () {
            return {
            }
        },
        created() {
        },
        methods: {
            print() {
                myPrint(document.getElementById('printDiv'))
            },
        }
    })


    const myPrint = (dom) => {
        writeIframe(dom);

        // 写入iframe
        function writeIframe(dom) {
            const iframe = document.createElement("iframe");
            iframe.setAttribute("style", "position:absolute;width:0;height:0;top:-10px;left:-10px;");
            document.body.appendChild(iframe);
            const doc = iframe.contentDocument;

            doc.open();
            doc.write(getStyle() + getHtml(dom));
            doc.close();

            iframe.onload = function () {
                iframe.contentWindow.print();

                setTimeout(() => {
                    document.body.removeChild(iframe);
                }, 100);
            };
        }

        // 获取样式
        function getStyle() {
            const styles = document.querySelectorAll("style,link");
            let str = "";

            for (let i = 0; i < styles.length; i++) {
                str += styles[i].outerHTML;
            }
            return str;
        }

        // 获取dom
        function getHtml(dom) {
            return dom.outerHTML;
        }
    };
</script>
</html>

2023-20-09 01:25:00 补充

可能我表达的不是太清楚,目前其实只有一个问题,就是web页面和打印的页面 实现不了 一致性。

我目前能做到的这是这样的效果,也还能接受,每页显示30条的数据,下方留了大片的空白,就是为了防止商品名称不可控,万一这30条数据的名字都是占了两行,也不会超过这一页的高

你看同样的大小的页面,同样的数据,打印页面下面就有一大片的空白,但是web页面基本上就占满了。 我设置的.item的大小为A4纸的大小

.item {
    page-break-after: always;
    height: 297mm;
    width: 210mm;
  }

image.png

image.png

image.png

2023-10-09 最新更新

上面的打印界面和真实的打印也有很大的差别。绝了。

1、下方空白地方太多了,打印界面 的空白地方占1/3,真实打印出来占了1/2
2、右侧少了一列数据

微信图片_20231009220010.jpg

阅读 1.9k
2 个回答

其实就是在合适的元素增加 page-break 这个断页CSS属性。比如说你这个情况 👇,也就是因为你给 .item 元素断页了所以导致的。

图片.png

可以给 <tr> 元素添加,这样的话,就会使整行 tr 被移动下一页了。就不会出现OP你提到的这个整个被断页的问题了,也不会出现一半的文字在第一页,一半的文字在第二页这样的情况。

另外需要检查打印设置中的页边距配置。这个配置没办法有效通过API来控制(浏览器兼容问题),所以最好在打印时手动确认一下。

可以参考一下我之前写过的一篇笔记 👉 HTML API + CSS 控制页面打印内容和样式

emm
一个简单的问题,
CSS 的 @media print 能对打印的页面做针对性的样式调整,
后面都是项目设计的问题:
你没法解决某人的300项存货单的单页打印问题,
只能分类讨论,单页的容纳量的

Q1 对应的 A1:
可能是 box 的边距的问题,不介意偏差的话在 @media print 添加一个缩放

Q2 对应的 A2:
需要测试出单个表格在不包括行合并的情况下的容纳量,
在计算行合并的时候注意分配合并数量 或者 分页

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题