美文网首页
小兄弟,10块钱一本的模板页打印大法,你想学吗?

小兄弟,10块钱一本的模板页打印大法,你想学吗?

作者: 晴天小雨不感冒 | 来源:发表于2020-05-31 23:31 被阅读0次

一个打印页面局部内容的需求

我假设你是一名挺有经验的开发人员,你现在碰到一个这样的需要,你需要在网页编辑区域输入一些基本信息,通过点击打印按钮将你录入的基本信息作为一份清单打印出来。例如,打印一份学生的成绩清单。网页的整体结构有顶层导航栏,左侧菜单栏,以及和菜单栏并列的内容区。你仔细分析了需求,知道菜单栏和导航栏肯定不能输出到打印内容里面。因此,不能将整个页面直接打印,而是打印局部区域,即打印内容取悦。而且作为局部区域,对于打印格式来说,仍然是有要求的,显然像页面元素的输入框,列表框,多行文本域直接打印到纸质页面里那就相当的不专业。因此,你需要获取页面的内容区域的元素内容,将该内容格式化为对于打印格式来说更为友好方式进行输出。在我的印象中,除了51job等一些求职类网页有打印功能,真的很少有网页需要打印功能。网页的出现明明就是为了“无纸化”办公,然而只有你想不到的需求,没有我做不了的功能。如果你在网上查找资料,很容易找到下面一段代码:

function printDeal(){
            var printBox = document.getElementById('printBox');
            //拿到打印的区域的html内容
            var newContent =printBox.innerHTML;
            //将旧的页面储存起来,当打印完成后返给给页面。
            var oldContent = document.body.innerHTML;
            //赋值给body
            document.body.innerHTML = newContent;
            //执行window.print打印功能
            window.print();
            // 重新加载页面,以刷新数据。以防打印完之后,页面不能操作的问题
            window.location.reload();
            document.body.innerHTML = oldContent;
            return false;
        }

这端代码虽然能满足一般的打印需求。但存在两个问题:1.只能打印静态页面。2.如果这是一个复杂页面,比如页面是通过layout布局将导航栏,菜单栏,内容区整合到一起,这时如果对内容区进行局部打印,那么打印格式将和页面格式存在非常大的差异。关于第二点,可能和layout的布局细节有关系,因时间关系,暂时无法深究,据本人的经验是,内容都打出来了,格式却是一团糟。 那么,有没有什么办法呢?

模板页打印法

在分析基本原理前,我们需要仔细分析上面的代码。很明显,window.print不能传递参数,因此,它自身是不能支持局部打印,只能整个页面打印。以上代码的基本逻辑就是:在页面打印前,将打印区域单独拿出来,对页面内容进行重新赋值,执行完打印后,再将旧的内容替换回去,从而实现局部打印。那么静态页面打印的基本原理是:将一个静态页面做为格式化打印 模板,通过window.open传递location参数将打印内容传递过去,静态页面通过js获得location参数后将内容填充到模板页中,然后打印模板页。以下为一个内容编辑页面:

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

<head>
    <meta charset="UTF-8">
    <style>
        td{
            height: 100px;
        }
    </style>
</head>

<body>
    <div>
        <table border="0" bordercolor="black" style="text-align: center; height: 219px;" width="100%"  cellspacing="0" cellpadding="5">
            <tr>
                <td colspan="5"><h2><span id="name">吴水金</span>的成绩单</h2></td>
                <!--<td>1.2</td>-->
                <!--<td>1.3</td>-->
            </tr>
            <tr>
                <td colspan="2"><b>语文:<span id="language">22</span></b></td>
                <td colspan="1"></td>
                <td colspan="2"><b>英语:<span id="english">22</span></b></td>
            </tr>
            <tr>
                <td colspan="2"><b>数学:<span id="math">22</span></b></td>
                <td colspan="1"></td>
                <td colspan="2"><b>物理:<span id="physics">22</span></b></td>
            </tr>
            <tr>
                <td colspan="2"><b>历史:<span id="history">22</span></b></td>
                <td colspan="1"></td>
                <td colspan="2"><b>政治:<span id="policy">22</span></b></td>
            </tr>
            <tr>
                <td colspan="2"><b>音乐:<span id="music">22</span></b></td>
                <td colspan="1"></td>
                <td colspan="2"><b>体育:<span id="sport"">22</span></b></td>
            </tr>
            <tr>
                <td colspan="5" ><b>综合评价:  <span id="des">xxxxxxxxxxxxxxxxxxxxxxxdddddddddddddddxxxxxxxxxxxxx</span></b></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </table>
    </div>
</body>
</html>

以上为本人做的一个模板页,是一个学生的成绩单,页面样式较为简单,只为演示原理,你完全可以根据需要自行调整。可以看到,上面的需要动态填充的元素都设置了id。这个页面是完全按照打印格式设置的。那么,我们再做一个内容编辑页面,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>

    <table width='100%' border='1' style="text-align: center;"  cellpadding="0">
        <tr>
            <th colspan="2">
                <div style="float: right;">
                    <button onclick="print()">打印</button>
                </div>
                <div>导航栏</div>

            </th>
        </tr>
        <tr>
            <td rowspan="2" style="width: 20%;">
                <div style="height: 500px;">菜单栏</div>
            </td>
            <td colspan="2">
                <table width='100%' border='0' cellpadding='30px' cellpadding="0">
                    <tr>
                        <th colspan="2">姓名: <input id="name" value="周杰伦"/></th>
                    </tr>
                    <tr>
                        <td>语文: <input id="language" value="100"/></td>
                        <td>英语: <input id="english" value="88"/></td>
                    </tr>
                    <tr>
                        <td>数学: <input id="math" value="89"/></td>
                        <td>物理: <input id="physics" value="89"/></td>
                    </tr>
                    <tr>
                        <td>历史: <input id="history" value="89"/></td>
                        <td>政治: <input id="policy" value="56"/></td>
                    </tr>
                    <tr>
                        <td>音乐: <input id="music" value="89"/></td>
                        <td>体育: <input id="sport" value="89"/></td>
                    </tr>
                    <tr>
                        <td colspan="2">综合评价: <textarea id="des" rows="5" cols="100" style="vertical-align: top;">周杰伦是个好孩子</textarea></td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
    <iframe id="printf" src="./model/index.html" width="0" height="0" frameborder="0"></iframe>
</body>
</html>

这是一个成绩单的编辑页面,这里模拟了一个layout的布局模式,即经典的导航栏,菜单栏,内容区的布局模式。为了达到只打印内容区,并且打印格式必须按打印格式进行格式化输出的效果。我们希望将内容区的编辑内容传递到模板页面,模板页填充内容后执行打印。那么,我们在编辑页面的head加入如下代码:

<script>
        function print() {
            //获取元素值
            let name = document.getElementById('name').value;
            let language = document.getElementById('language').value;
            let english = document.getElementById('english').value;
            let math = document.getElementById('math').value;
            let physics = document.getElementById('physics').value;
            let history = document.getElementById('history').value;
            let policy = document.getElementById('policy').value;
            let music = document.getElementById('music').value;
            let sport = document.getElementById('sport').value;
            let des = document.getElementById('des').innerHTML;
           //用模板字符串拼接请求。注意模板页路径,根据实际情况修改。
            let location = `./model/index.html?${'name=' + name}
            ${'&english=' + english}
            ${'&language=' + language}
            ${'&math=' + math}
            ${'&physics=' + physics}
            ${'&history=' + history}
            ${'&policy=' + policy}
            ${'&music=' + music}
            ${'&sport=' + sport}
            ${'&des=' + des}
            `;
            //打开新窗口并传递打印内容
             const win = window.open(encodeURI(location),
                 'newwindow',
                 'height=0, width=400, top=100, left=100, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no'
             );
             win.print();
}
</script>

以上代码逻辑非常简单,值得注意的模板字符串的写法,这是ES6标准的新写法,还是非常好用的。另外一点值得注意的是这里是通过window.open传递查询字符串将内容传递到静态模板页中。其他参数无关紧要。win.print没什么好说的,就是打印模板页。这边的内容传递过去了,那么,现在需要在模板页中接收,并且将接收的内容填充的模板页中的待填充区域。即上面的已经预留好的带id的模板页元素。在模板页中加入以下代码,加在body元素的末尾:

<script>
        //循环遍历进行赋值
        let params = decodeURI(window.location.search).substr(1).split('&');
        for(let p of params){
            let keyValue = p.split('=');
            document.getElementById(keyValue[0]).innerHTML = keyValue[1];
        }
</script>

window.location.search为查询字符串,我们对它进行切割,即能找出对应的字段和值。由于我们定义参数时即有意将参数名和模板页元素id进行一一对应。因此,这里我们只需要一个循环就能对模板页中所有待填充元素进行赋值。
好了,到此为止,所有代码都完成了。如果你ctrl+c,ctrl+v大法用的比较熟练,想必已经实现打印效果了。尽管已经实现了打印,但该打印仍有不足的地方:1.打印时会弹出一个多余的模板页页面。2.该打印没有走后台系统,也就是说这些打印内容没有提交后台保存即进行了打印,因此如果编辑内容没有提交保存就打印,就会出现后台没有任何记录的纸质打印清单。对于第二点,这是业务逻辑方面需要考虑的,和纯粹的打印功能无关。关于第一点,本人还想介绍下iframe打印大法,但由于篇幅所限,另外,本人亲身试验,iframe传值有问题,就不再这里介绍了。
好了,就到这里吧,我要睡觉了,希望你有所收获。

相关文章

网友评论

      本文标题:小兄弟,10块钱一本的模板页打印大法,你想学吗?

      本文链接:https://www.haomeiwen.com/subject/ctpdzhtx.html