评论:原生js打印插件Print.js  [查看原文]

所属分类:其他-独立的部件,杂项

 115743  479  59
当前第2页 / 共3页
    zhangxianbin0
    2018/9/3 14:51:12
    大佬,问您个问题,代码能不能调打印横向纵向,打印纸张大小?如果您知道,请告诉我~
    打个比方说,我打印了这个页面纵向完全可以,横向就变成两张了,如果变成横向,有没有这个事件。
        charles2hang3
        2018/9/8 17:55:29
        1.从css样式的角度来看,应该是不能实现这种调节的,其实应该把它看做自适应的过程,打印效果是根据用户打印设置里的纸张大小(注意cm、mm对px、rem有一定的换算关系)来呈现的,就像一个没有做自适配的网站在电脑和手机端的效果不同一样。对于有打印预览的浏览器(chrome)来说,这种呈现可以实时看到:打印纸张的宽度如果小于body的宽度,那么body里每一行多出来的元素就会按盒模型被挤到下一行去,长度的情况类似。

        2.用户打印的设置都是在浏览器之外进行的,通过一些ActiveX控件(IE)或者第三方打印驱动(C-Lodop)也许可以读取到这样的设置,但是在js中是没有这样的监听事件的。

        3.如果说最终的目的是为了像自适配移动PC端那样,在用户打印设置不同大小的纸张以及打印的纵横向时,均能呈现合理的打印效果,最便捷的方式还是用媒体查询(@media print和screen)做适配,根据具体的打印尺寸如A1、A3(横向),A2、A4(纵向),或者符合产品需求的宽高度来写适配

        P.S. 媒体查询的具体数值px、rem对应多少cm、mm可直接用二分法粗略测出来,刻意追求精度可以考虑把dpi(打印像素精度)考虑进去。
        推荐文章:http://www.w3cplus.com/css3/7-habits-of-highly-effective-media-queries.html
        zhangxianbin0
        2018/9/25 9:16:57
        谢谢楼主大大精彩的回复,确实这个精准度不是很好,但是可以一点一点调,那个横纵已经解决了,现在问题就是调纸张大小,@page能否用js控制,因为我们需求就是用谷歌浏览器进行打印的,要求可以调横纵、纸张大小、还有边距,我再下方的评论中看到您回答了如何调这个边距的回答,但是纸张大小不是只能用这个@page来调不是?就是请问一下这个@page能否用js调整,谢谢楼主大大~
        charles2hang3
        2018/9/25 13:15:34

        1.目测你的需求可能类似于有一个下拉框让用户选择纸张大小,然后用js监听这个change事件在回调中动态改变相应的@page。所以你这个问题其实归结为js动态调整css的问题。那这样的问题其实比较容易解决,下面是两种思路
        2.css中在不同的class下定义不同的@page的pagetype页面类型,然后在js中给要打印的区域的父级盒添加不同的class。伪代码如下:

        <style>
            @page pagea4{ //声明一个页面类型pagea4,类似于@keyframe用法 声明一个动画
                size:A4 portrait;//定义大小以及纵横向,landscape横向,portrait纵向
            }
            @page pagea3{ //同上
                size:A3 landscape;
            }
            body.print-a3{
                page:pagea3; //使用page样式来指定一个页面类型
            }
            body.print-a4{
                page:pagea4;
            }
        </style>
        <script>
            document.getElementById('select').addEventListener('change',function(){
                if(this.value=='a4'){
                    document.body.className = 'print-a4'
                }
                if(this.value=='a3'){
                    document.body.className = 'print-a3'
                }
            })
        </script>

        3.另一种思路跟上面类似,在源码的getStyle中再加入一段js动态写入一段@page样式,伪代码如下:

        getStyle: function() {
            var str = "",
                styles = document.querySelectorAll('style,link');
            for (var i = 0; i < styles.length; i++) {
                str += styles[i].outerHTML; 
            }
            if(document.getElementById('select').value == 'a4'){
                str += '<style>@page{size:a4 portrait}</style>'
            }
            return str;
        }

        P.S.参考文档

        https://developer.mozilla.org/zh-CN/docs/Web/CSS/@page MDN文档 
        http://www.php.cn/css-tutorial-373189.html
        http://www.softwhy.com/article-5613-1.html
    回复
    charles2hang3
    2018/7/12 20:15:38

    借楼下的问题再分享下如何调试打印样式的问题。

    因为打印预览在chrome中是无法用devtool查看打印嵌入的<embed>插件对象样式的,所以打印样式没有符合预期时,一般调试都是去改打印前页面里的样式,再预览打印,就像不打断点调试js一样,相当耗时间。

    1.弹出打印预览时会把js线程挂起来(==临时断点),而且是像“截图”一样把打印时的页面截取成pdf,意味着如果在调用打印方法前,异步执行了大量DOM操作,很可能在DOM还没渲染完成就被“截取了”,所以这种场景下推荐延时400~600ms再调用打印,保证DOM渲染完成

    2.在主函数Print原型链上的writeIframe中是通过创建框架apped到body中,然后在同源下取得框架的contentWindowcontentDocument(=doc),再通过

    doc.open()→doc.write(html)→doc.close()

    打开文档流,写入DOM字符串,关闭文档流并渲染DOM来实现样式与html的“注入”。那么同样地,可以通过window.open()打开一个新窗口(标签页),同样取得window和document对象,再把要打印的html及其样式在新窗口中打开,此时就能用devtool调试不符合预期的样式了。代码示例如下:

    var newWin = window.open()
    var newDoc = newWin.document
    newDoc.title = "打印窗口"
    newDoc.open()
    newDoc.write('123')
    newDoc.close()
    回复
    zhangxianbin0
    2018/7/12 14:18:17
    楼主,我用那个拖拽然后在打印,但是会偏移打印阅览向右偏移了有100px左右,请问怎么破?
        charles2hang0
        2018/7/12 20:22:44
        其实,这位同学你没有很详细清楚的描述你的问题,需要你跳出你的思路来提问,来让人更好的理解。比如“用拖拽然后打印”含糊地说了一下思路,也没有上代码,很难猜测你用的是哪个拖拽插件,是在打印的什么时候调用的,对应的样式又是如何的,很容易导致无人问津。
        不过,楼上提供了一些解决办法的思路,希望能帮到你。
        My density0
        2018/8/28 18:02:08
        在不????方便加QQ有事情请教 1345728734
        charles2hang0
        2018/9/8 17:18:07
        不是很经常逛jq,有需要可联系QQ 584576916,欢迎讨论
    回复
    charles2hang3
    2018/7/9 23:09:41

    再分享三个打印的小窍门:
    1.怎么用css去掉页眉页脚但是保持页边距?如下:

    @page{ size:auto;margin:0mm; }

    这句css将页宽设为自适应、页边距设为0mm,浏览器发现没有页眉页脚空间,就不会加一堆网址、页码、时间、页面title的信息

    html{font-size:100%;} 
    body{padding:2.22rem 2.7rem;}

    这句则将1rem设定为16px,然后利用body的padding来留出页边距。这个padding数值是根据多次测试得来的,比较粗略,对应的是A4标准-上下2.54mm,左右3.09mm
    2.(可能有些情况不需要)有些打印机打出来发现顺时针歪了一个小角度,可以将body稍微旋转一下:

    body {
        transform: rotate(-0.1 deg); - webkit - transform - origin: center center;transform - origin: center center;
    }

    3.(可能有些情况不需要)有些页面点打印预览(非IE),发现最后多出来一页空白的,完全多余。

    body{height: calc(100% - 1px) !important}

    鼓捣了一下发现是因为body的高度为100%,撑满了页面,自动换行到下一页去了,多减掉1px(或者更多)貌似就可以了

        心像开满花的树0
        2018/8/30 9:35:50
        按照你的方法做了还是会多一个空白页啊。。。。
        charles2hang1
        2018/9/8 17:05:00
        可以肯定的是body内有元素(可能是最后一个元素,也可能是body本身的padding、margin或者伪元素定位)超出了body的高度,可以试一试以下方法:

        1.按上述第3点,多减一些,如20px、40px等,看是否生效。若生效则可用二分法快速找到一个阈值。

        2.如果第1种无效或者阈值的样式会影响整体的打印样式,参考上2楼第2点的方式,去调试找到body内某个元素(多余的margin、padding、伪元素)引起的撑满导致多余空白页问题
        charles2hang1
        2019/2/27 0:43:41

        1.针对第2点对第3点修正下,在某些页面下,把body transform变换也会导致多一个空白页。究其原因,就是body逆时针旋转了一个角度,把文档流当成一个父级盒,不难想象,body肯定会上下露出两个角来。而打印的范围是按照文档流来处理的,所以会莫名其妙多出来一个空白页。

        2.如果需要实现第2点的效果,可以给打印内容嵌套一个父级盒再使用上述的样式,但是依然不保证不会超出文档流,transform变换需要根据实际情况谨慎使用。

        3.除了上一点中提到的情况之外,普通情况调试页面下也可以通过添加

        html * { border:1px #f00 solid !important; } // 红色边框线或其他醒目的样式

        来查看到底是哪个元素超出了文档流,当然也不要忘记标准模式(content-box)和怪异模式(border-box)的影响

    回复
    charles2hang0
    2018/7/9 21:42:12
    哇,为了防范XSS,居然把我下面那条注释里面所有的[i][f][r][a][m][e]都给replace和谐掉了。[黑人问号??]
    诸位有看得不明白的地方,代码有缺失的地方,放一个[i][f][r][a][m][e]在那就好理解了 回复
    charles2hang3
    2018/7/9 21:31:49

    先说明非作者哈XD 

    简单注释下:
    主函数:

    初始化打印dom 排除非打印区域
    原型链:
    init:调用链方法getStyle和getHtml将样式与dom字符串组装起来 write将该组装片段写入中
    extend:对象浅层扩展封装
    getStyle:从当前页面获取style标签和link标签 附加no-print隐藏样式 以写入
    getHtml:获取主函数中附着在this原型上的指定dom对象 并且将当前input、textarea、select的状态、内容二次赋值,以便在写入的时候能渲染出一样的结果
    write:将组装好的html字符串写入的DOM,其中doc.open()为打开写入文档流,才能写入内容,doc.close()为关闭写入文档流,以结束的load状态,其他的应该不难理解。
    点击打印空白问题(有时):是因为加载与打印是异步执行的,很容易导致在document.execCommand('print')的时候,还没加载出来,所以是一片空白。针对修改如下,将write方法与toPrint方法合并了。

    write: function(content) {
        var w, doc, = document.createElement(''),
            f = document.body.appendChild();
        .id = "print-";
        .src = '';
        .style = "position:absolute;width:0;height:0px;top:-10px;left:-10px;";
    
        w = f.contentWindow || f.contentDocument;
        doc = f.contentDocument || f.contentWindow.document;
        doc.open();
        doc.write(content);
        doc.close();
        w.onload = function() {
            try {
                setTimeout(function() {
                    w.focus();
                    try {
                        if (!w.document.execCommand('print', false, null)) {
                            w.print();
                        }
                    } catch (e) {
                        w.print();
                    }
                    w.close();
                }, 10);
            } catch (err) {
                console.log('err', err);
            }
            setTimeout(function() {
                document.body.removeChild();
            }, 100);
        };
    }
    回复
    melody0
    2018/5/10 11:01:34
    请问一下支持table的打印吗 回复
    ?__Kiss丶不弃0
    2018/4/26 10:43:55
    怎么现实打印机打印不了啊?是需要改什么吗? 回复
    小卟╀0
    2018/4/25 16:19:27
    为什么有时候会出现空白的情况
    回复
    keleno0
    2018/4/8 12:05:39
    打印关闭事件无法触发什么鬼 回复
    For丨丶Tomorrow0
    2018/3/27 11:19:59
    如果是ie浏览器,我想调用打印预览怎么弄 回复
    油儿饭0
    2018/3/1 11:18:54
     刚试了感觉还可以,
    回复
    ??????0
    2018/2/27 17:48:59
    各位大神,ie10打印出来css为什么没有生效
    回复
    我行我素,爷乐意!0
    2018/1/31 18:23:50

    点击打印是空白的,为啥呀

    回复
    破碎D信果0
    2018/1/31 13:56:59

    请问各位大神, 为什么部分样式失效, 特别是使用定位,预览布局都乱的, 有什么好的方法解决吗

        jie40383
        2018/1/31 14:44:42

        插件中获取样式的代码:

        getStyle: function() {
          var str = "",
            styles = document.querySelectorAll('style,link');
          console.log(styles);
          for (var i = 0; i < styles.length; i++) {
            str += styles[i].outerHTML;
          }
          return str;
        }

        我简单试了一下fixed和absolute定位,打印预览时排版是正常的。建议依次排查原因:

        1. 因为使用了querySelectorAll,兼容性不是那么好,不知道你的浏览器是否支持。

        2.你可以把获取到的styles打印一下,看看是否完整。

        3.如果background-color丢失,在css中添加:

        @media print {
            body{-webkit-print-color-adjust:exact;} 
        }
    回复

讨论这个项目(59)回答他人问题或分享插件使用方法奖励jQ币 评论用户自律公约

取消回复