程序员

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

2023-12-05  本文已影响0人  Eason_0cce

先看效果:


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;  }}
上一篇下一篇

猜你喜欢

热点阅读