Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

window.print——关于浏览器打印:2018-6-28 #11

Open
jsonz1993 opened this issue Jul 27, 2021 · 0 comments
Open

window.print——关于浏览器打印:2018-6-28 #11

jsonz1993 opened this issue Jul 27, 2021 · 0 comments

Comments

@jsonz1993
Copy link
Owner

本文为博客迁移过来,原文链接: window.print——关于浏览器打印:2018-6-28

近日有个需求是做页面打印的,趁这个机会补一下比较冷门的浏览器打印知识。本文主要讨论 Chrome、Safari、Firefox浏览器的情况。

打印接口

首先浏览器打印是一个很成熟的应用~ 至少是很早就已经有应用的功能,所以不会有什么兼容问题

最简单的打印就是直接调用 window.print(),当然用 document.execCommand('print') 也可以达到同样的效果。

这时候在Safari和Chrome都会弹起打印预览的窗口,FireFox没有预览而是直接让你选择打印机,OSx下可以通过预览PDF来预览~

一般这种直接在网页上调用 print 的方法是没办法满足我们的业务需求,比如说:

  • 调整布局和字体大小来适应A4纸
  • 打印的时候用不同的样式风格
  • 使用更高清的图片来打印
  • 某一些不相关的东西不出现在打印中等等等等

那么有哪些方法可以帮助我们改善打印的用户体验呢?

使用 print style sheet (打印样式表)

我们可以在 link 上加上一个 media="print" 来标识这是打印机才会应用的样式表, 如:

<link href="/example.css" media="print" rel="stylesheet" />

这样打印的时候,就会默认将该样式表应用到文档中

使用媒介查询

兼容性: IE9+ 其他主流浏览器都支持
当我们要修改的样式没有那么多的时候,其实完全不需要重新写个样式表,只要写上一个媒介查询也可以达到同样的效果,如:

h1 {
  font-size: 14px;
}
@media print {
  h1 {
    font-size: 20px;
  }
}

事件监听

beforeprint && afterprint

有两个事件可以监听到到打印事件,一个是beforeprint,一个是afterprint,分别表示打印事件触发前后。
这个事件在 IE6 就已经支持了,不过一点都不惊讶~ 毕竟IE很早就支持很多接口调用,之前好像做过IE打开Excel的需求~
兼容大概是 Firefox、IE全支持, Chrome63+支持, Safari暂不支持,算是一半一半吧。

window.addEventListener('beforeprint', ()=> {
  document.body.innerHTML = '正在打印...';
});
window.addEventListener('afterprint', ()=> {
  document.body.innerHTML = '打印完成...';
});

window.matchMedia 测试媒体查询接口

如果你想要兼容Safari或许可以试一下 window.matchMedia
兼容是 IE10+,其他主流浏览器完全没问题。

这个的用法稍微有点不一样,首先创建一个MediaQueryList对象,再通过他监听变化,如:

const printMedia = window.matchMedia('print');
function printChange({ matches, }) {
  document.body.innerHTML = matches? '正在打印...': '打印完成/取消';
}
printMedia.addListener(printChange);

更加个性化定制打印区域/打印内容

如果项目上用的是jq等,或者想简单粗暴的打印某个区域又不想重新写样式表啊,什么的。
最傻瓜版的方式就是直接用jq插件 jQuery.print

也可以自己写一个去处理,大概的思路是创建一个iframe,把要打印的dom和样式表都丢进去,再调用iframe的打印事件。 这里写一个简单的 demo

function printPartial(dom, { title= document.title,}= {}) {
  if (!dom) return;
  let copyDom = document.createElement('span');
  const styleDom = document.querySelectorAll('style, link, meta');
  const titleDom = document.createElement('title');
  titleDom.innerText = title;

  copyDom.appendChild(titleDom);
  Array.from(styleDom).forEach(item=> {
    copyDom.appendChild(item.cloneNode(true));
  });
  copyDom.appendChild(dom.cloneNode(true));

  const htmlTemp = copyDom.innerHTML;
  copyDom = null;

  const iframeDom = document.createElement('iframe');
  const attrObj = {
    height: 0,
    width: 0,
    border: 0,
    wmode: 'Opaque'
  };
  const styleObj = {
    position: 'absolute',
    top: '-999px',
    left: '-999px',
  };
  Object.entries(attrObj).forEach(([key, value])=> iframeDom.setAttribute(key, value));
  Object.entries(styleObj).forEach(([key, value])=> iframeDom.style[key] = value);
  document.body.insertBefore(iframeDom, document.body.children[0]);
  const iframeWin = iframeDom.contentWindow;
  const iframeDocs = iframeWin.document;
  iframeDocs.write(`<!doctype html>`);
  iframeDocs.write(htmlTemp);
  iframeWin.focus();
  iframeWin.print();
  document.body.removeChild(iframeDom);
}

printPartial(document.querySelector('#description'));

最后一些注意的事情

  • 打印会打印document下所有可见元素, 包括 <header> 里面的
  • 背景都不会被打印出来,包括背景色啊背景图片啊等等
  • 如果图片是懒加载的,需要特殊处理,不然打印的时候会直接空白

参考:
https://blog.csdn.net/fengshuiyue/article/details/57483057
Mozilla print
Mozilla Using_a_print_style_sheet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant