js依赖网页打印实现自动分页和纸张大小设定

先看效果:


image.png

上代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="print pickingPrint" id="pickingPrint">
    </div>
</body>
<style>
    * {
        margin: 0;
        padding: 0;
    }
    /* 详细设置:https://developer.mozilla.org/en-US/docs/Web/CSS/@page */
    @media print {
        @page {
            margin: 0mm;
            size: a4 landscape;
            msn-header: none;
            msn-footer: none;
        }

        .noPrint {
            display: none;
        }
    }

    .pickingPrint {
        margin: 0;
        font-size: 14px;
        box-sizing: border-box;
    }

    .pickingPrint h3 {
        font-size: 26px;
        text-align: center;
        font-weight: normal;
        height: 35px;
    }

    .pickingPrint .flex {
        display: flex;
    }

    .pickingPrint .flex1 {
        flex: 1;
    }

    .pickingPrint .just-right {
        justify-content: flex-end;
    }

    .pickingPrint .align-center {
        align-items: center;
    }

    .pickingPrint .flex-wrap {
        flex-wrap: wrap;
    }

    .pickingPrint .head {
        padding: 15px 0;
        white-space: nowrap;
        line-height: 1.5em;
        height: 72px;
        box-sizing: border-box;
    }

    .pickingPrint .headCode {
        padding-left: 8%;
        position: relative;
    }

    .pickingPrint .headCode .qrCode {
        position: absolute;
        top: 0;
        left: 0;
    }

    .pickingPrint .tableHead {
        height: 27px;
    }

    .pickingPrint .head .item1 {
        width: 35%;
    }

    .pickingPrint .head .item2 {
        width: 28.5%;
        padding-left: 5.5%;
    }

    .pickingPrint .head .item3 {
        width: 21%;
    }

    .pickingPrint .headCode .item1 {
        width: 35%;
    }

    .pickingPrint .headCode .item2 {
        padding-left: 0;
        width: 30%
    }

    .pickingPrint .headCode .item3 {
        width: 30%;
    }

    .pickingPrint .table .item {
        padding: 4px 2px;
        box-sizing: border-box;
        align-items: center;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: flex-start;
    }

    .pickingPrint .table .item1 {
        width: 12%;
    }

    .pickingPrint .table .item2 {
        width: 12%;
    }

    .pickingPrint .table .item3 {
        flex: 1;
    }

    .pickingPrint .table .item4 {
        width: 10%;
    }

    .pickingPrint .table .item5 {
        width: 12%;
    }

    .pickingPrint .table .item6 {
        width: 10%;
    }

    .pickingPrint .table .item7 {
        width: 7%;
    }

    .pickingPrint .table .item8 {
        width: 8%;
    }

    .pickingPrint .table .item .number~.number {
        border-top: 1px solid #eee;
    }

    .pickingPrint .tableBox {
        border: 1px solid #999;
        border-bottom: 0;
        font-size: 12px;
        box-sizing: border-box;
    }

    .pickingPrint .tableBox .table {
        border-bottom: 1px dashed #999;
    }

    .pickingPrint .tableBox .table:last-child {
        border-bottom-style: solid;
    }

    .pickingPrint .page {
        height: 19px;
        font-size: 14px;
        align-items: center;
    }

    .pickingPrint .break {
        page-break-after: always
    }
</style>
<script>
    var tmpNode = document.createElement("DIV");
    tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
    document.body.appendChild(tmpNode);
    const xdpi = tmpNode.offsetWidth;
    const ydpi = tmpNode.offsetHeight;
    tmpNode.parentNode.removeChild(tmpNode);
    const widthValue = Math.floor(xdpi / 2.54 * 21);
    const heightValue = ydpi / 2.54 * 29.7;
    document.querySelector("#pickingPrint").style.width = `${heightValue}px`;
    const date = new Date();
    const zoneOffset = date.getTimezoneOffset();
    let offsetHour = Math.abs(zoneOffset / 60);
    let offsetHourString = "";
    if (zoneOffset <= 0) {
        offsetHourString = `+${offsetHour}`
    }
    if (zoneOffset > 0) {
        offsetHourString = `-${offsetHour}`
    }
    const lanSet = {
        cn: {
            title: '标题',
            number: "字段",
            typeNumber: "字段",
            totalNumber: "字段",
            printedBy: "字段",
            printTime: "字段",
            printingTimes: "字段",
            barCode: "字段",
            sku: "字段",
            goodName: '字段',
            specification: "字段",
            brand: "字段",
            classification: "字段",
            quantity: "字段",
            gift: "字段",
            page: "字段"
        }
    };
    renderPage(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], 'cn');
    function renderPage(index, list, lan) {
        const char1 = `${lanSet[lan].number}: 字段`;
        const char2 = `${lanSet[lan].typeNumber}:1`;
        const char3 = `${lanSet[lan].totalNumber}:1`;
        const char4 = `${lanSet[lan].printedBy}:管理员账号`;
        const char5 = `${lanSet[lan].printTime}: ${date.toLocaleDateString() + " " + date.toLocaleTimeString()} ${offsetHourString}`;
        const char6 = `${lanSet[lan].printingTimes}: ${index + 1}`;
        const char7 = `OWCU/${lanSet[lan].barCode}`;
        const char8 = `sku/${lanSet[lan].sku}`;
        const char9 = `${lanSet[lan].goodName}`;
        const char10 = `${lanSet[lan].specification}`;
        const char11 = `${lanSet[lan].brand}`;
        const char12 = `${lanSet[lan].classification}`;
        const char13 = `${lanSet[lan].quantity}`;
        const char14 = `${lanSet[lan].gift}`;
        const pageItem = document.createElement("div");
        pageItem.style.padding = `${ydpi / 2.54}px`;
        pageItem.innerHTML = `
        <h3>${lanSet[lan].title}</h3>
        <div class="flex flex-wrap head">
            <div class="item1">${char1}</div>
            <div class="item2">${char2}</div>
            <div class="item3">${char3}</div>
            <div class="item1">${char4}</div>
            <div class="item2">${char5}</div>
            <div class="item3">${char6}</div>
        </div>
        <div class="flex table tableHead">
            <div class="item item1">${char7}</div>
            <div class="item item2">${char8}</div>
            <div class="item item3">${char9}</div>
            <div class="item item4">${char10}</div>
            <div class="item item5">${char11}</div>
            <div class="item item6">${char12}</div>
            <div class="item item7">${char13}</div>
            <div class="item item8">${char14}</div>
        </div>

        <div class="tableBox">

        </div>

        <div class="flex just-right page">${index + 1}/<span class="totalPage"></span>${lanSet[lan].page}</div>
        `;
        if (index > 0) {
            pageItem.classList.add("break");
        }
        document.querySelector("#pickingPrint").appendChild(pageItem);
        document.querySelectorAll("#pickingPrint .totalPage").forEach(totalPage => {
            totalPage.innerText = index + 1;
        });
        renderItem(0);
        console.log(widthValue * (index + 1), "1111");
        function renderItem(itemIndex) {
            const item = list[itemIndex];
            const tableItem = document.createElement("div");
            tableItem.className = "flex table";
            tableItem.innerHTML = `
            <div class="item item1">
                    <div class="number">字段</div>
                    <div class="number">字段</div>
                </div>
                <div class="item item2">
                    <div class="number">字段</div>
                    <div class="number">字段</div>
                </div>
                <div class="item item3">字段</div>
                <div class="item item4">字段</div>
                <div class="item item5">字段</div>
                <div class="item item6">字段</div>
                <div class="item item7">${itemIndex}</div>
                <div class="item item8">字段</div>
            `;
            document.querySelectorAll("#pickingPrint .tableBox")[index].appendChild(tableItem);
            if (pageItem.offsetHeight > widthValue) {
                //有下一页
                document.querySelectorAll("#pickingPrint .tableBox")[index].removeChild(tableItem);
                if (list.slice(itemIndex, list.length).length > 0) {
                    renderPage(index + 1, list.slice(itemIndex, list.length), lan);
                } else {
                    window.print();
                }
            } else {
                //没有下一页
                if (list[itemIndex + 1]) {
                    renderItem(itemIndex + 1);
                } else {
                    // 没有数据了
                    window.print();
                }
            }
        }
    }
</script>

</html>

核心点:
1、计算A4纸张在宿主屏幕中的实际大小,计算方法:设置一个1英寸的元素,根据实际大小算出实际占用像素,然后根据宽高像素值反推A4纸大小。
2、根据元素动态创建高度,实现分页,分页样式: page-break-after: always
3、设置打印样式:@media print,详细参数见备注链接,我将页面大小设置成了auto,因为我前面已经精准算出了分页符的位置,所以打印时候会自动分页。也就是每页都会分成A4纸的大小。

拓展:
电商类的标签打印,也可以使用这个方案,比如打印100*100的物流面单。可以动态插入一条打印样式

@media print { @page {  size:${width}px ${height}px;  }}

彩蛋:
当前页面直接打印,一个小魔法。

@media print {
    body { height: auto; }
    body>:not(.printArea) { display: none;}
    #printBody {height: auto !important;}
  }
  
  #printBody {
    width: 100%;
    height: 0;
    overflow: hidden;
  }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容