0
点赞
收藏
分享

微信扫一扫

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe


目录

  • ​​需求描述​​
  • ​​方案1:直接打印页面​​
  • ​​方案2:使用css媒体查询控制打印内容​​
  • ​​方案3:第三方插件print-js​​
  • ​​方案4:将要打印的节点内容写入iframe​​
  • ​​方案5:将要打印的html写入iframe(推荐)​​

需求描述

最近有一个需求,是让用户通过浏览器可以打印表格内容

环境:

  • node v16.14.0
  • vue2.js
  • element-ui

表格本身是使用了的el-table实现的,浏览器显示的时候很正常,没有什么异常。

创建vue2项目

$ node -v
v16.14.0

// 2022-10-14 最新版本 5.0.0
pnpm install -g @vue/cli

选择
- vue 2.6.14
- vuex 3.6.2
- vue-router 3.5.1
- less 4.0.0

表格数据 data.js

export const tableData = [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
{
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
{
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
},
];

界面显示

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe_前端

直接​​ctrl+p​​ 打印效果不是很好。于是,开始寻找解决方案,大致有以下几种思路

方案1:直接打印页面

js打印页面

// 快捷键 ctrl + p
window.print()

vue代码

<template>
<div>
<el-table
:data="tableData"
border
style="width:"
>
<el-table-column
prop="date"
label="日期"
width="180"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180"
>
</el-table-column>
<el-table-column
prop="address"
label="地址"
>
</el-table-column>
</el-table>

<el-button
@click="handlePrint"
type="primary"
style="margin-top:"
>打印</el-button
>
</div>
</template>

<script>import { tableData } from './data.js'

export default {
data() {
return {
tableData,
}
},

methods: {
handlePrint() {
window.print()
},
},
}</script>

<style lang="less"></style>

打印预览

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe_html_02

发现,直接打印是不行的

当使用ctrl+p 拉起打印的时候,发现总有一些小问题,比如

  • 表格后面的竖线缺失
  • 表格的表头错位
  • 表格的列显示不全

方案2:使用css媒体查询控制打印内容

该方案适用于页面简单,打印效果过要求不高的场景

我们可以通过css媒体查询,将打印按钮隐藏

使用css媒体查询控制打印区域

@media {
/* 隐藏不需要打印的部分 */
.not-print{
display: none !important;
}

.print{
background-color: transparent;
}
}

html中设置不打印的内容

<div class="not-print">不打印此内容</div>

vue 完整代码

<template>
<div>
<el-table
:data="tableData"
border
style="width:"
>
<el-table-column
prop="date"
label="日期"
width="180"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180"
>
</el-table-column>
<el-table-column
prop="address"
label="地址"
>
</el-table-column>
</el-table>

<el-button
class="not-print"
@click="handlePrint"
type="primary"
style="margin-top:"
>打印</el-button
>
</div>
</template>

<script>import { tableData } from './data.js'

export default {
data() {
return {
tableData,
}
},

methods: {
handlePrint() {
window.print()
},
},
}</script>

<style lang="less">@media {
/* 隐藏不需要打印的部分 */
.not-print {
display: none !important;
}

.print {
background-color: transparent;
}
}</style>

打印预览

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe_css_03

方案3:第三方插件print-js

适用于简单输出

文档

  • ​​https://github.com/crabbly/print.js​​
  • ​​https://printjs.crabbly.com/​​
  • ​​https://www.npmjs.com/package/print-js​​

安装

npm install print-js --save

使用示例

printJS({
header: "表格标题",
type: "json",
properties: [
{ field: "date", displayName: "日期" },
{ field: "name", displayName: "姓名" },
{ field: "address", displayName: "地址" },
],
printable: this.tableData,
});

vue 完整代码

<template>
<div>
<el-table
:data="tableData"
border
style="width:"
>
<el-table-column
prop="date"
label="日期"
width="180"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180"
>
</el-table-column>
<el-table-column
prop="address"
label="地址"
>
</el-table-column>
</el-table>

<el-button
class="not-print"
@click="handlePrint"
type="primary"
style="margin-top:"
>打印</el-button
>
</div>
</template>

<script>import { tableData } from './data.js'
import printJS from 'print-js'

export default {
data() {
return {
tableData,
}
},

methods: {
handlePrint() {
printJS({
header: '表格标题',
type: 'json',
properties: [
{ field: 'date', displayName: '日期' },
{ field: 'name', displayName: '姓名' },
{ field: 'address', displayName: '地址' },
],
printable: this.tableData,
})
},
},
}</script>

<style lang="less"></style>

打印预览

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe_开发语言_04

方案4:将要打印的节点内容写入iframe

可以直接将要打印的节点内容设置给iframe标签,此方法可能会出现样式不一致的问题

关键代码 utils.js

export function printHTML(html) {
// 创建iframe元素
const iframe = document.createElement('iframe')
iframe.setAttribute('style', 'display:none')
document.body.appendChild(iframe)
let doc = iframe.contentWindow.document

// 写入html
doc.write(html)
doc.close()

// 调用打印
iframe.contentWindow.focus()
iframe.contentWindow.print()

// 打印完毕后移除
iframe.parentNode.removeChild(iframe)
}

vue 完整代码

<template>
<div>
<el-table
id="print-table"
:data="tableData"
border
style="width:"
>
<el-table-column
prop="date"
label="日期"
width="180"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180"
>
</el-table-column>
<el-table-column
prop="address"
label="地址"
>
</el-table-column>
</el-table>

<el-button
class="not-print"
@click="handlePrint"
type="primary"
style="margin-top:"
>打印</el-button
>
</div>
</template>

<script>import { tableData } from './data.js'
import { printHTML } from './utils.js'

export default {
data() {
return {
tableData,
}
},

methods: {
handlePrint() {
let printElementHtml = document.querySelector('#print-table').innerHTML
printHTML(printElementHtml)
},
},
}</script>

<style lang="less"></style>

打印结果

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe_html_05

方案5:将要打印的html写入iframe(推荐)

适用于复杂输出,需要自定义,复杂度也是最高的

我们应该换个思路:

打印的页面往往都是黑白显示,不一定要和原页面一样,很多元素可能不一样,可能还会增加额外的一些信息,索引应该​​单独构建html页面​

我们可以使用后端模板渲染的思路,通过twig 模板引擎来渲染一个html文件,通过容器隔离的iframe来进行独立完成渲染和打印工作

安装用到的依赖

pnpm i twig twig-loader -D

模板代码

<template>
<div style="text-align:">
<el-table
id="print-table"
:data="tableData"
border
style="width:"
>
<el-table-column
prop="date"
label="日期"
width="180"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180"
>
</el-table-column>
<el-table-column
prop="address"
label="地址"
>
</el-table-column>
</el-table>

<el-button
@click="handlePrint"
type="primary"
style="margin-top:"
>打印</el-button
>
</div>
</template>

<script>import { tableData } from './data.js'
import { printHTML } from './utils.js'
import printTemplate from './print-template.twig'
import dayjs from 'dayjs'

export default {
data() {
return {
tableData,
}
},

methods: {
handlePrint() {
let html = printTemplate({
title: '员工信息表',
list: this.tableData,
now_time: dayjs().format('YYYY-MM-DD'),
})
printHTML(html)
},
},
}</script>

<style lang="less"></style>

模板 print-template.twig

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
http-equiv="X-UA-Compatible"
content="IE=edge"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Document</title>
<style>* {
margin: 0;
padding: 0;
}

table,
td,
th {
border: 1px solid #000;
border-collapse: collapse;
}
th,
td {
padding: 3px 10px;
font-size: 12px;
line-height: 1.5;
}

table {
width: 100%;
margin: 0 auto;
}

.title {
font-size: 14px;
line-height: 1.5;
text-align: center;
margin-bottom: 20px;
font-weight: normal;
}

.footer-wrap {
margin-top: 20px;
display: flex;
}

.footer {
margin-left: auto;
padding-right: 100px;
font-size: 12px;
line-height: 1.5;
text-align: left;
}</style>
</head>
<body>
<h1 class="title">{{ title }}</h1>

<table>
<thead>
<tr>
<th>日期</th>
<th>姓名</th>
<th>地址</th>
</tr>
</thead>

<tbody>
{% for row in list %}
<tr>
<td>{{ row.date }}</td>
<td>{{ row.name }}</td>
<td>{{ row.address }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<div class="footer-wrap">
<div class="footer">
<div>打印日期:{{ now_time }}</div>
</div>
</div>
</body>
</html>

打印预览

Vue2.js:前端在浏览器中网页表格打印的实现方案:window.print、print-js、iframe_javascript_06


至此,完整的打印了表格内容,还附带了一些必要的信息

需要配置 vue.config.js

// vue.config.js
module.exports = {
configureWebpack: {
resolve: {
fallback: {
path: require.resolve('path-browserify'),
},
},
},

chainWebpack: (config) => {
// twig rule loader
const twigRule = config.module.rule('twig')
twigRule.exclude.add(/node_modules/)
// 添加新的loader处理
twigRule
.test(/\.twig$/)
.use('twig-loader')
.loader('twig-loader')
.end()
},
}

依赖 package.json

{
"name": "vue-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"dayjs": "^1.11.5",
"element-ui": "^2.15.10",
"path-browserify": "^1.0.1",
"vue": "^2.6.14"
},
"devDependencies": {
"@vue/cli-service": "~5.0.0",
"less": "^4.0.0",
"less-loader": "^8.0.0",
"twig": "^1.15.4",
"twig-loader": "^0.5.5",
"vue-template-compiler": "^2.6.14"
}
}

打印属性

/* 打印文档时修改某些 CSS 属性 */
@page {
/* 设置纸张及其方向 portrait:纵向; landscape: 横向 */
size: A4 landscape;
}

完整代码:​​https://github.com/mouday/vue-print/​​​ 在线体验:​​https://mouday.github.io/vue-print/​​

参考

  1. ​​前端实现在浏览器中打印网页​​
  2. ​​利用 iframe 标签打印元素​​
  3. ​​https://developer.mozilla.org/zh-CN/docs/Web/API/Window/print​​
  4. ​​https://developer.mozilla.org/zh-CN/docs/Web/CSS/@page​​


举报

相关推荐

0 条评论