【问题标题】:Twitter Bootstrap: Print content of modal windowTwitter Bootstrap:打印模态窗口的内容
【发布时间】:2012-08-24 06:56:24
【问题描述】:

我正在使用 Bootstrap 开发一个网站,该网站有 28 个模式窗口,其中包含有关不同产品的信息。我希望能够在打开的模式窗口中打印信息。每个窗口都有一个id

<!-- firecell panel & radio hub -->
           <div class="modal hide fade" id="fcpanelhub">
              <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">X</button>
                <h3>5000 Control Panel & Radio Hub</h3>
              </div>
              <div class="modal-body">
                <img src="../site/img/firecell/firecell-panel-info-1.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-panel-info-2.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-radio-hub-info-1.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-radio-hub-info-2.png" alt=""/>
              </div>
              <div class="modal-footer">
                <a href="#" class="btn" data-dismiss="modal">Close</a>
              </div>    
           </div>

因此,如果我在modal-footer 中添加一个新按钮 - “打印”,并且单击它,我希望打印该模式。我说会使用javascript是对的吗?如果是这样,我如何告诉 javascript 只打印打开的模式,而不是其他模式?

感谢所有帮助。

【问题讨论】:

标签: javascript printing twitter-bootstrap modal-dialog


【解决方案1】:

所以我有一个 React 应用程序,它作为一个 Web 组件存在于多个旧网站上。这些解决方案都不是我想要的。接受的答案有缺点。假设我们有这个 CSS:

@media print {
  body * {
    visibility:hidden;
  }
  #printSection, #printSection * {
    visibility:visible;
  }
  #printSection {
    position:absolute;
    left:0;
    top:0;
  }
}

body * {visibility : hidden} 将阻止用户在按下 CTRL+P 时打印页面。

这也不考虑多个打印 UX 工作流程,以防用户可能需要从同一页面上的模态和抽屉打印页面。这是一种罕见的情况,但同样没有考虑到这一点

解决方案

我选择的解决方案是在正文上应用顶级 CSS 类。在我的 React Modal 组件中,我使用了 useEffect 调用

import React, { useEffect } from 'react'

export const ModalPane = (props) => {
  useEffect(() => {
    const body = document.querySelector('body')
    if (body) {
      body.classList.add('hide-on-print')
    }
    return () => {
      if (body) {
        body.classList.remove('hide-on-print')
      }
    }
  }, [])

  const handlePrint = () => {
    // add any prework or analytics tracking here etc
    window.print()
  }

  return (
    <div className="print-me">
      <h1>Modal content stuff here</h1>
      <button type="button" onClick={handlePrint}>Print</button>
    </div>
  )
}

一旦呈现此模态(也就是用户正在查看预期的模态),将仅打印模态的内容。不管他们是点击打印按钮还是按 CTRL+P

这会在 body 元素上应用一个名为 hide-on-print 的类。然后应用此媒体样式,其范围专门针对此打印 UX 实例(您可以为其他特定打印查询向正文添加更多类)

@media print {
  body.hide-for-print {
    visibility: hidden !important;
  }
  body.hide-for-print .print-me {
    visibility: visible;
  }
}

TLDR

使用仅在渲染时应用 hide-for-print 类的 react useEffect 组件。将 @print 媒体查询包装在此类后面。这可以处理所有预期的 UX 打印用例,并且可以扩展到任何其他特定的打印 UX 用例

【讨论】:

    【解决方案2】:

    我只是使用了一点 jQuery/javascript:

    html:

    <h1>Don't Print</h1>
    
    <a data-target="#myModal" role="button" class="btn" data-toggle="modal">Launch modal</a>
    
    <div class="modal fade hide" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"      aria-hidden="true">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
         <h3 id="myModalLabel">Modal to print</h3>
      </div>
      <div class="modal-body">
        <p>Print Me</p>
      </div>
      <div class="modal-footer">
        <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
        <button class="btn btn-primary" id="printButton">Print</button>
      </div>
    </div>
    

    js:

    $('#printButton').on('click', function () {
        if ($('.modal').is(':visible')) {
            var modalId = $(event.target).closest('.modal').attr('id');
            $('body').css('visibility', 'hidden');
            $("#" + modalId).css('visibility', 'visible');
            $('#' + modalId).removeClass('modal');
            window.print();
            $('body').css('visibility', 'visible');
            $('#' + modalId).addClass('modal');
        } else {
            window.print();
        }
    });
    

    这里是the fiddle

    【讨论】:

    • 我注意到的问题是页面内容(如果很长)仍然会占用打印空间。
    【解决方案3】:

    您可以从此源下载 printThis 库 https://github.com/jasonday/printThis/blob/0a7f799693af8a8303bf0b8df0efc80c2694af81/printThis.js 并将其包含在您的 html 页面中

    调用下面的jquery来打印所有的内容,包括不可见的内容。如果您有多个 css 文件,您可以将 css 文件包含在一个数组中。

    $("#modalDiv").printThis({ 
        debug: false,              
        importCSS: true,             
        importStyle: true,         
        printContainer: true,       
        loadCSS: "../css/style.css", 
        pageTitle: "My Modal",             
        removeInline: false,        
        printDelay: 333,            
        header: null,             
        formValues: true          
    }); 
    

    【讨论】:

      【解决方案4】:

      另一种解决方案

      这是基于same question 中的Bennett McElwee answer 的新解决方案,如下所述。

      在 IE 9 & 10、Opera 12.01、Google Chrome 22 和 Firefox 15.0 上测试。
      jsFiddle example

      1.) 将此 CSS 添加到您的网站:

      @media screen {
        #printSection {
            display: none;
        }
      }
      
      @media print {
        body * {
          visibility:hidden;
        }
        #printSection, #printSection * {
          visibility:visible;
        }
        #printSection {
          position:absolute;
          left:0;
          top:0;
        }
      }
      

      2.) 添加我的 JavaScript 函数

      function printElement(elem, append, delimiter) {
          var domClone = elem.cloneNode(true);
      
          var $printSection = document.getElementById("printSection");
      
          if (!$printSection) {
              $printSection = document.createElement("div");
              $printSection.id = "printSection";
              document.body.appendChild($printSection);
          }
      
          if (append !== true) {
              $printSection.innerHTML = "";
          }
      
          else if (append === true) {
              if (typeof (delimiter) === "string") {
                  $printSection.innerHTML += delimiter;
              }
              else if (typeof (delimiter) === "object") {
                  $printSection.appendChild(delimiter);
              }
          }
      
          $printSection.appendChild(domClone);
      }​
      

      您已准备好在您的网站上打印任何元素!
      只需使用您的元素调用 printElement() 并在完成后执行 window.print()

      注意: 如果您想在打印之前修改内容(并且仅在打印版本中),请查看此示例(由 cmets 中的 waspina 提供):http://jsfiddle.net/95ezN/121/

      也可以使用 CSS 来显示打印版本中的附加内容(并且仅在打印版本中)。


      以前的解决方案

      我认为,您必须通过 CSS 隐藏网站的所有其他部分。

      最好将所有不可打印的内容移动到单独的DIV

      <body>
        <div class="non-printable">
          <!-- ... -->
        </div>
      
        <div class="printable">
          <!-- Modal dialog comes here -->
        </div>
      </body>
      

      然后在你的 CSS 中:

      .printable { display: none; }
      
      @media print
      {
          .non-printable { display: none; }
          .printable { display: block; }
      }
      

      致谢Greg 已经回答了类似问题:Print <div id="printarea"></div> only?

      使用 JavaScript 存在一个问题:用户看不到预览 - 至少在 Internet Explorer 中!

      【讨论】:

      • 但是,如果您有一个模态弹出窗口,其可打印区域覆盖在原始可打印区域之上呢?
      • @MattSull87 我添加了另一个解决方案 - 这应该会更好!这是一个示例:jsfiddle.net/95ezN/1
      • @waspinator 我的“打印”元素(你提供给printElement() 的元素)和它的子元素没什么特别的。只需使用getElementById()querySelector[All]()
      • @waspinator 调用printElement(yourContainer);,修改你的子元素并最终调用window.print()printElement() 只准备打印过程,但不会触发打印本身。
      • @BennettDill 如果当前显示模式,您可以通过 JavaScript 向 添加一个类:if (modalShown) { body.classList.add('printModal'); }。然后,将body.printModal 添加到 CSS 规则中,这样它们只会在您实际打印模态对话框时生效。
      【解决方案5】:

      @media print{
      	body{
      		visibility: hidden; /* no print*/
      	}
      	.print{
      		
      		visibility:visible; /*print*/
      	}
      }
      <body>
        <div class="noprint"> <!---no print--->
        <div class="noprint"> <!---no print--->
        <div class="print">   <!---print--->
        <div class="print">   <!---print--->
      
      
      </body>

      【讨论】:

        【解决方案6】:

        这是一个使用 JQuery 扩展的选项,我根据接受答案的 cmets 中的 waspinator 代码制作:

        jQuery.fn.extend({
            printElem: function() {
                var cloned = this.clone();
                var printSection = $('#printSection');
                if (printSection.length == 0) {
                    printSection = $('<div id="printSection"></div>')
                    $('body').append(printSection);
                }
                printSection.append(cloned);
                var toggleBody = $('body *:visible');
                toggleBody.hide();
                $('#printSection, #printSection *').show();
                window.print();
                printSection.remove();
                toggleBody.show();
            }
        });
        
        $(document).ready(function(){
            $(document).on('click', '#btnPrint', function(){
                $('.printMe').printElem();
            });
        });
        

        JSFiddle:http://jsfiddle.net/95ezN/1227/

        如果您不想将其应用于每一个打印件,而只是在您的自定义打印按钮上执行此操作(这是我的情况),这可能会很有用。

        【讨论】:

        • 这很好用。也可以按元素 ID 选择。
        【解决方案7】:

        我面临两个问题 问题1:所有领域都一个接一个地出现, 问题 2 用于从弹出窗口打印时页面底部的空白。

        我解决了这个问题

        display none 对所有 body * 元素进行显示

            @media print {
                body * {
                   display:none;
                width:auto;
                height:auto;
                margin:0px;padding:0px; 
                }
                #printSection, #printSection * {
                    display:inline-block!important;
                }
                #printSection {
                    position:absolute;
                    left:0;
                    top:0;  
                    margin:0px; 
                    page-break-before: none;
                    page-break-after: none;
                    page-break-inside: avoid;      
                }
        #printSection .form-group{
        
              width:100%!important;
              float:left!important;
              page-break-after: avoid;
            }
        #printSection label{
                float:left!important;
                width:200px!important;
                display:inline-block!important;
              }
        
        #printSection .form-control.search-input{
                float:left!important;
                width:200px!important;
                display: inline-block!important;
              }
        }
        

        【讨论】:

          【解决方案8】:

          这是一个没有 Javascript 或插件的解决方案 - 只是一些 css 和标记中的一个额外类。 此解决方案使用 BootStrap 在打开对话框时将类添加到正文的事实。然后我们使用这个类来隐藏正文,只打印对话框。

          为了确保我们可以确定页面的主体,我们需要在 div 中包含主页内容中的所有内容 - 我使用了 id="mainContent"。下面的示例页面布局 - 有一个主页和两个对话框

          <body>
           <div class="container body-content">
          
            <div id="mainContent">
                 main page stuff     
            </div>
            <!-- Dialog One -->
            <div class="modal fade in">
             <div class="modal-dialog">
              <div class="modal-content">
                    ...
              </div>
             </div>
            </div>
          
            <!-- Dialog Two -->
            <div class="modal fade in">
             <div class="modal-dialog">
              <div class="modal-content">
                    ...
              </div>
             </div>
            </div>
          
           </div>
          </body>
          

          然后在我们的 CSS 打印媒体查询中,我使用 display: none 来隐藏我不想显示的所有内容 - 即当对话框打开时的 mainContent。我还使用了一个特定的类 noPrint 用于页面的任何不应该显示的部分——比如操作按钮。在这里,我还隐藏了页眉和页脚。您可能需要对其进行调整才能完全满足您的需求。

          @media print {
              header, .footer, footer {
                  display: none;
              }
          
              /* hide main content when dialog open */
              body.modal-open div.container.body-content div#mainContent {
                  display: none;
              }
          
              .noPrint {
                  display: none;
              }
          }
          

          【讨论】:

            【解决方案9】:

            这是一个修改后的解决方案,也适用于使用 Grails 模板呈现的模态窗口,您可以在同一个正文中多次调用相同的模态模板(使用不同的值)。这个帖子对我帮助很大,所以我想我会分享它,以防其他 Grails 用户在这里找到他们的方式。

            对于那些好奇的人来说,接受的解决方案对我不起作用,因为我正在渲染一个表格;每行都有一个按钮,可以打开一个模式窗口,其中包含有关记录的更多详细信息。这导致多个 printSection div 被创建并打印在彼此之上。因此,我不得不修改 js 以在打印完成后清理 div。

            CSS

            我将此 CSS 直接添加到我的模态 gsp 中,但将其添加到父级具有相同的效果。

            <style type="text/css">
               @media screen {
                    #printSection {
                       display: none;
                    }
               }
            
               @media print {
                    body > *:not(#printSection) {
                       display: none;
                    }
                    #printSection, #printSection * {
                        visibility: visible;
                    }
                    #printSection {
                        position:absolute;
                        left:0;
                        top:0;
                    }
               }
            </style>
            

            将它添加到站点范围的 CSS 会终止站点其他部分的打印功能。我从ComFreak 接受的答案(基于Bennett McElwee answer)中得到了这个,但它是使用fanfavoritePrint <div id=printarea></div> only? 的答案中的':not' 功能进行修改的。我选择了“显示”而不是“可见性”,因为我的不可见正文内容创建了额外的空白页,这对我的用户来说是不可接受的。

            js

            这是我的 javascript,修改自 ComFreak 接受的这个问题的答案。

            function printDiv(div) {    
                // Create and insert new print section
                var elem = document.getElementById(div);
                var domClone = elem.cloneNode(true);
                var $printSection = document.createElement("div");
                $printSection.id = "printSection";
                $printSection.appendChild(domClone);
                document.body.insertBefore($printSection, document.body.firstChild);
            
                window.print(); 
            
                // Clean up print section for future use
                var oldElem = document.getElementById("printSection");
                if (oldElem != null) { oldElem.parentNode.removeChild(oldElem); } 
                                      //oldElem.remove() not supported by IE
            
                return true;
            }
            

            我不需要附加元素,因此我删除了该方面并更改了函数以专门打印一个 div。

            HTML (gsp)

            还有模态模板。这将打印模态页眉和正文,并排除按钮所在的页脚。

            <div class="modal-content">
                <div id="print-me"> <!-- This is the div that is cloned and printed -->
                    <div class="modal-header">
                        <!-- HEADER CONTENT -->
                    </div>
                    <div class="modal-body">
                         <!-- BODY CONTENT -->
                    </div>
                </div>
                <div class="modal-footer">
                                             <!-- This is where I specify the div to print -->
                    <button type="button" class="btn btn-default" onclick="printDiv('print-me')">Print</button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </div>
            </div>
            

            希望对大家有所帮助!

            【讨论】:

            • 谢谢你,卡拉!这个解决了我遇到的一个棘手问题。此外,如果您取消打印功能,然后再次尝试打印,@comFreek 的解决方案会导致我出错(不是他的代码,这是 Angular 的问题)。
            • @Hairgami_Master 很高兴能帮上忙!我花了很长时间才完成这项工作,所以不分享是不对的。
            【解决方案10】:

            使用当前接受的解决方案,您无法再打印包含对话框本身的页面。这是一个更加动态的解决方案:

            JavaScript:

            $().ready(function () {
                $('.modal.printable').on('shown.bs.modal', function () {
                    $('.modal-dialog', this).addClass('focused');
                    $('body').addClass('modalprinter');
            
                    if ($(this).hasClass('autoprint')) {
                        window.print();
                    }
                }).on('hidden.bs.modal', function () {
                    $('.modal-dialog', this).removeClass('focused');
                    $('body').removeClass('modalprinter');
                });
            });
            

            CSS:

            @media print {
                body.modalprinter * {
                    visibility: hidden;
                }
            
                body.modalprinter .modal-dialog.focused {
                    position: absolute;
                    padding: 0;
                    margin: 0;
                    left: 0;
                    top: 0;
                }
            
                body.modalprinter .modal-dialog.focused .modal-content {
                    border-width: 0;
                }
            
                body.modalprinter .modal-dialog.focused .modal-content .modal-header .modal-title,
                body.modalprinter .modal-dialog.focused .modal-content .modal-body,
                body.modalprinter .modal-dialog.focused .modal-content .modal-body * {
                    visibility: visible;
                }
            
                body.modalprinter .modal-dialog.focused .modal-content .modal-header,
                body.modalprinter .modal-dialog.focused .modal-content .modal-body {
                    padding: 0;
                }
            
                body.modalprinter .modal-dialog.focused .modal-content .modal-header .modal-title {
                    margin-bottom: 20px;
                }
            }
            

            例子:

            <div class="modal fade printable autoprint">
              <div class="modal-dialog">
                <div class="modal-content">
                  <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 class="modal-title">Modal title</h4>
                  </div>
                  <div class="modal-body">
                    <p>One fine body&hellip;</p>
                  </div>
                  <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary" onclick="window.print();">Print</button>
                  </div>
                </div><!-- /.modal-content -->
              </div><!-- /.modal-dialog -->
            </div><!-- /.modal -->
            

            【讨论】:

            • 嗨,您的解决方案很好,但在我的情况下,我的模态内容高于后页高度,因此,在打印视图中,我的模态内容正在被剪切,部分。你有什么解决办法吗?示例:打印版本需要 2 页的所有模态内容,但它只考虑一页(因为背景“正文”页面的高度)。
            • @Massa,我也在和这个作斗争。似乎问题出在模态的position: fixed 上。我找到的解决方案是,在打印时,将模态的位置更改为absolute 设置bottom: auto
            • @Massa:你有没有找到将模态内容打印到多个页面的解决方案。
            【解决方案11】:

            我建议你试试这个 jQuery 插件print element

            它可以让你只打印你选择的元素。

            【讨论】:

            • 网站上的示例在 IE 10 (Windows 8 RTM) 上对我来说工作。
            • 真的吗?我还没有尝试过 IE10,但它不适用于 IE10 听起来很奇怪。我在IE7-9上使用它没有问题。您是否在其他浏览器上尝试过,以确保您没有错过其他内容?
            • 好的,现在可以正常使用了!那是因为 GitHub 没有发送正确的 MIME 类型,而 IE 10 会阻止该脚本。 Working jsFiddle here.
            • 这是恕我直言的最佳解决方案,减少了麻烦和代码添加。只需在您的 javascript 之后包含此文件 code.jquery.com/jquery-migrate-1.0.0.js 以避免浏览器错误。
            • 使用 printElement 时,请确保设置弹出设置,使其不会使用 iFrame,因为根据我的经验,它在 IE 中无法正常工作。 $(elementToPrintId).printElement({printMode: 'popup'});
            猜你喜欢
            • 2023-03-04
            • 2011-12-13
            • 2012-10-10
            • 1970-01-01
            • 1970-01-01
            • 2010-10-02
            • 2012-12-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多