遇到的问题

在前端经常会使用到的打印功能,有很多前端库可以帮我们处理这个问题,比如print.js、vue中的vue-print-nb等等,但是这些还不足以解决更复杂的打印问题。

其中经常遇到的问题有以下几点:

  • 页面打印不完全,会遇到页面被裁边的问题,特别是在打印表格的时候
  • 页面在大量的文字使用v-for循环渲染的时候,会遇到文字重叠的问题
  • 无法代入样式到打印页面中,或者打印页面的样式被污染,这个是最烦人的

解决方案

使用原生html重画页面,比如checkbox,radio,table等等样式在前端组件库中的样式污染都是相当严重的。

所以我一般都会重画html页面,使用最原生的页面打印,看起来也是最舒服,最流畅的。

如果你只打印纯表格页面,我建议是使用print.js,基本上不会有问题,也不需要重画页面。

代码如下:

1

printJS({

2

documentTitle: "打印标题",

3

printable: this.dataList, // 传入数据

4

type: 'json', // 这里要设置为json

5

properties: [ // 设置要打的表格属性栏和对应的dataList中的字段

6

{ field: 'name', displayName: "姓名" },

7

{ field: 'age', displayName: "年龄" },

8

{ field: 'address', displayName: "住址" }

9

],

10

gridStyle: 'text-align: center; border: 1px solid lightgray; margin-bottom: -1px;'

11

})

打印效果如下:

default

其他复杂页面,比如像下面这样的页面,在dialog中展示的有表格有循环渲染的数据,几乎在我们的项目里100%出现文字重叠的情况的。

default

这个时候只能使用iframe来做打印功能,代码示例如下:

1

async print() {

2

const content = document.getElementById('shift-print').innerHTML; // 获取节点

3

// 打印的内容里用到的所有样式,写在这里面

4

const styles = `

5

body { font-family: Arial; font-size: 14px; }

6

h1 { color: #333; }

7

.page-break { page-break-after: always; }

8

table {

9

border-collapse: collapse;

10

border: 1px solid rgb(140 140 140);

11

letter-spacing: 1px;

12

margin: 1em 0;

13

width: 100%;

14

overflow: auto;

15

table-layout: fixed;

50 collapsed lines

16

}

17

18

th,

19

td {

20

border: 1px solid rgb(160 160 160);

21

padding: 8px;

22

}

23

`;

24

this.printWithIframe(content, styles)

25

},

26

printWithIframe(content, styles = '') {

27

const iframe = document.createElement('iframe');

28

iframe.style.position = 'absolute';

29

iframe.style.width = '0';

30

iframe.style.height = '0';

31

iframe.style.border = 'none';

32

33

document.body.appendChild(iframe);

34

35

const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

36

37

iframeDoc.open();

38

iframeDoc.write(`

39

<!DOCTYPE html>

40

<html>

41

<head>

42

<title>打印内容</title>

43

<style>

44

${styles}

45

@media print {

46

body { margin: 0; padding: 0; }

47

@page { size: A4; margin: 15mm; }

48

}

49

</style>

50

</head>

51

<body>

52

${content}

53

</body>

54

</html>

55

`);

56

iframeDoc.close();

57

58

iframe.contentWindow.focus();

59

iframe.contentWindow.print();

60

61

setTimeout(() => {

62

document.body.removeChild(iframe);

63

this.printing = false

64

}, 1000);

65

},

打印出来的结果如下:

default

使用iframe基本上可以解决大部分场景下的问题了。