window.print —— 瀏覽器列印掃盲

Jsonz發表於2019-03-04

部落格地址jsonz1993.github.io/2018/06/win…

github 歡迎start follow

近日有個需求是做頁面列印的,趁這個機會補一下比較冷門的瀏覽器列印知識。本文只討論 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> 裡面的
  • 背景都不會被列印出來,包括背景色啊背景圖片啊等等
  • 如果圖片是懶載入的,需要特殊處理,不然列印的時候會直接空白

參考:

blog.csdn.net/fengshuiyue…

Mozilla print

Mozilla Using_a_print_style_sheet

相關文章