Several ways to realize the printing function in vue

1. Directly call the window.print() method

This method prints the entire page by default, and cannot print partial pages. without retaining the original style

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>打印测试页</title>
    <style type="text/css"
           media="screen">
        .pageheader,
        .pagefooter {
    
    
            display: none;
        }
    </style>
    <style type="text/css"
           media="print">
        /*每一页 如果没有另外自定义的话 */
        @page {
    
    
            margin-left: 50px;
            margin-top: 100px;
        }
        /*第一页*/
        @page :first {
    
    
            margin-left: 50%;
            margin-top: 50%;
        }
        /*分页标记*/
        .geovindu {
    
    
            page-break-after: always;
        }
        .pageheader {
    
    
            margin-top: 10px;
            font-size: 12pt;
        }
        .pagefooter {
    
    
            margin-top: 10px;
            font-size: 10pt;
        }
    </style>
</head>
<body>
    <script type="text/javascript">
         function main() {
    
    
            window.print();
        }
    </script>
    <div id="geovindu"
         class="geovindu">
        <div class="pageheader">页眉:打印测试</div>
        <div class="conent">
            封面内容
        </div>
        <div class="pagefooter">页脚:第1/2</div>
    </div>
    <div id="geovindu"
         class="geovindu">
        <div class="pageheader">页眉:打印测试</div>
        <div class="conent">
            第二页内容
        </div>
        <div class="pagefooter">页脚:第2/2</div>
    </div>
    <button onclick="main()">打印按钮</button>
</body>
</html>

2. Custom package printing method

This method also calls native printing. By encapsulating the method, you can specify the area to be printed, with a high degree of freedom. The disadvantage is that the string is intercepted by intercepting the html of the entire page, and the original style is not retained. You need to manually add the style .

2.1. Encapsulate the printing method and create a printHtml.js file

export default function printHtml(html) {
    
    
    let style = getStyle();
    let container = getContainer(html);

    document.body.appendChild(style);
    document.body.appendChild(container);

    getLoadPromise(container).then(() => {
    
    
        window.print();
        document.body.removeChild(style);
        document.body.removeChild(container);
    });
}

// 设置打印样式
function getStyle() {
    
    
    let styleContent = `#print-container {
      display: none;
  }
  @media print {
      body > :not(.print-container) {
          display: none;
      }
      html,
      body {
          display: block !important;
      }
      #print-container {
          display: block;
      }
  }`;
    let style = document.createElement("style");
    style.innerHTML = styleContent;
    return style;
}

// 清空打印内容
function cleanPrint() {
    
    
    let div = document.getElementById('print-container')
    if (!!div) {
    
    
        document.querySelector('body').removeChild(div)
    }
}

// 新建DOM,将需要打印的内容填充到DOM
function getContainer(html) {
    
    
    cleanPrint()
    let container = document.createElement("div");
    container.setAttribute("id", "print-container");
    container.innerHTML = html;
    return container;
}

// 图片完全加载后再调用打印方法
function getLoadPromise(dom) {
    
    
    let imgs = dom.querySelectorAll("img");
    imgs = [].slice.call(imgs);

    if (imgs.length === 0) {
    
    
        return Promise.resolve();
    }

    let finishedCount = 0;
    return new Promise(resolve => {
    
    
        function check() {
    
    
            finishedCount++;
            if (finishedCount === imgs.length) {
    
    
                resolve();
            }
        }
        imgs.forEach(img => {
    
    
            img.addEventListener("load", check);
            img.addEventListener("error", check);
        })
    });
}

2.2. How to use

<template>
  <div>
    <button @click="onPrint">打印1</button>
    // dom部分 可用if控制
    <i test='printStart'></i>
        <div v-show="oldStr">
            v-show1的
        </div>
        <div v-show="oldStr">
            v-show2的
        </div>
        测试冲冲冲
        <div class="xwtable">
            <table>
                <tr>
                    <th>序号</th>
                    <th>姓名</th>
                    <th>年龄</th>
                    <th>性别</th>
                    <th>手机</th>
                    <th>邮箱</th>
                    <th>地址</th>
                    <th>工龄</th>
                    <th>岗位</th>
                    <th>薪资</th>
                </tr>
                <tr v-for="(item, index) in list"
                    key="index">
                    <td>{
    
    {
    
     index + 1}}</td>
                    <td>{
    
    {
    
     item.name }}</td>
                    <td>{
    
    {
    
     item.age }}</td>
                    <td>{
    
    {
    
     item.sex }}</td>
                    <td>{
    
    {
    
     item.phone }}</td>
                    <td>{
    
    {
    
     item.mail }}</td>
                    <td>{
    
    {
    
     item.address }}</td>
                    <td>{
    
    {
    
     item.workAge }}</td>
                    <td>{
    
    {
    
     item.jobs }}</td>
                    <td>{
    
    {
    
     item.salary }}</td>
                </tr>
            </table>
        </div>
    <i test='printEnt'></i>
    <div>
      <div class="text_styte">我是测试样式的</div>
    </div>
  </div>
</template>
<script setup lang="ts">
// 引入封装好的打印函数
import printHtml from "./printHtml.js";
import {
    
     ref } from 'vue';
let oldStr = ref(false);
let editableIs = ref(true);
let showChang = ref(true);
let list = [{
    
    
    name: "阿哒",
    age: 26,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 2,
    jobs: "研发",
    salary: "1.8k"
},
{
    
    
    name: "阿荣",
    age: 24,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 1,
    jobs: "研发",
    salary: "1.8k"
},
{
    
    
    name: "阿豪",
    age: 26,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 5,
    jobs: "产品",
    salary: "1.8k"
},
{
    
    
    name: "阿晨",
    age: 29,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 9,
    jobs: "设计",
    salary: "1.8k"
},
{
    
    
    name: "阿震",
    age: 30,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 7,
    jobs: "销售",
    salary: "1.8k"
},
{
    
    
    name: "阿锋",
    age: 21,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 0.1,
    jobs: "售后",
    salary: "1.8k"
}
]
// 点击处理打印
const onPrint = () => {
    
    
  editableIs.value = false;
  //以上用于关闭不需要打印的部分 最简单的方法是给dom v-if,不需要赘述吧
  showChang.value = true;
  //双向绑定需要给页面渲染时间,延迟一定时间
  setTimeout(function () {
    
    
    // document.title = '标题 | 这是页眉标题哦';
    // 获取body的内容
    let oldStr = window.document.body.innerHTML;
    // 开始打印标识, 21个字符 注意""
    let start = '<i test="printStart">';
    // 结束打印标识, 23个字符
    let end = '<i test="printEnt"></i>';
    let condition = true
    let printData = ''
    while (condition) {
    
    
      if (oldStr.indexOf(start) == -1) {
    
    
        condition = false
      } else {
    
    
        // 截取开始打印标识之后的内容
        let newStr = oldStr.substr(oldStr.indexOf(start) + 21);
        // 截取开始打印标识和结束打印标识之间的内容
        printData = printData + newStr.substring(0, newStr.indexOf(end));
        // 截取结束打印标识之后的内容
        oldStr = newStr.substr(newStr.indexOf(end) + 23);
      }
    }
    let reg = new RegExp("display: none", "g"); //定义正则表达式
    printData = printData.replace(reg, '')
    // 调用打印
    printHtml(printData)
  }, 500)
}
</script>
<style scoped>
.xwtable {
    
    
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #ccc;
}

.xwtable thead td {
    
    
    font-size: 12px;
    color: #333333;
    text-align: center;
    background: url(table_top.jpg) repeat-x top center;
    border: 1px solid #ccc;
    font-weight: bold;
}

.xwtable tbody tr {
    
    
    background: #fff;
    font-size: 12px;
    color: #666666;
}

.xwtable tbody tr.alt-row {
    
    
    background: #f2f7fc;
}

.xwtable td {
    
    
    line-height: 20px;
    text-align: left;
    padding: 4px 10px 3px 10px;
    height: 18px;
    border: 1px solid #ccc;
}
</style>

3. Use vue3-print-nb dependency

This method can customize the print area and retain the original style. The disadvantage is that the style of the print area cannot be associated with the style outside the print area. Colleagues, we can also @media printset the style of the area that needs to be printed by using it. The degree of freedom is better. More specific usage methods should be explored together.

Here is the introduction and use of vue3+ts, and the introduction of vue2 can be read in other articles.

3.1. Global import method

// main.ts
import {
    
     createApp } from "vue";
import App from "./App.vue";
import Print from 'vue3-print-nb'
createApp(App).use(Print).mount("#app");

3.2. Partial import method (setup) custom command ------------ (recommended)

There are many <script lang="ts">or <script>different ways to use custom commands on the Internet, so I won't go into details here.

<script setup lang="ts">
import print from 'vue3-print-nb'

// 使用自定义指令
const vPrint = print

let prints = {
    
    
  id: 'print-iframe',
  popTitle: '配置页眉标题', // 打印配置页上方的标题
  extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
  preview: false, // 是否启动预览模式,默认是false
  previewTitle: '预览的标题', // 打印预览的标题
  previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
  zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
  previewBeforeOpenCallback() {
    
     console.log('正在加载预览窗口!'); }, // 预览窗口打开之前的callback
  previewOpenCallback() {
    
     console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
  // 开始打印之前的callback
  beforeOpenCallback() {
    
    
    console.log('开始打印之前!')
  },
  openCallback() {
    
     console.log('执行打印了!') }, // 调用打印时的callback
  closeCallback() {
    
     console.log('关闭了打印工具!'); var element = document.getElementById("print-iframe"); element?.parentNode?.removeChild(element); }, // 关闭打印的callback(无法区分确认or取消)
  clickMounted() {
    
     console.log('点击v-print绑定的按钮了!') },
  standard: '',
  extarCss: ''
}
</script>

3.3. Simple and direct usage scenarios

We add the id attribute printsdefined in the object to the html tag that needs to be printed, and print by adding custom instructions to the button.v-print="prints"

<template>
	<button v-print="prints">打印2</button>
  <div id="print-iframe">
    // dom部分 可用if控制
        <div class="xwtable">
            <table>
                <tr>
                    <th>序号</th>
                    <th>姓名</th>
                    <th>年龄</th>
                    <th>性别</th>
                    <th>手机</th>
                    <th>邮箱</th>
                    <th>地址</th>
                    <th>工龄</th>
                    <th>岗位</th>
                    <th>薪资</th>
                </tr>
                <tr v-for="(item, index) in list"
                    key="index">
                    <td>{
    
    {
    
     index + 1}}</td>
                    <td>{
    
    {
    
     item.name }}</td>
                    <td>{
    
    {
    
     item.age }}</td>
                    <td>{
    
    {
    
     item.sex }}</td>
                    <td>{
    
    {
    
     item.phone }}</td>
                    <td>{
    
    {
    
     item.mail }}</td>
                    <td>{
    
    {
    
     item.address }}</td>
                    <td>{
    
    {
    
     item.workAge }}</td>
                    <td>{
    
    {
    
     item.jobs }}</td>
                    <td>{
    
    {
    
     item.salary }}</td>
                </tr>
            </table>
        </div>
    <div>
      <div class="text_styte">我是测试样式的</div>
    </div>
  </div>
</template>
<script setup lang="ts">
// 引入封装好的打印函数
import print from 'vue3-print-nb'
import {
    
     ref } from 'vue';
const vPrint = print
let prints = {
    
    
  id: 'print-iframe',
  popTitle: '配置页眉标题', // 打印配置页上方的标题
  extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
  preview: false, // 是否启动预览模式,默认是false
  previewTitle: '预览的标题', // 打印预览的标题
  previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
  zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
  previewBeforeOpenCallback() {
    
     console.log('正在加载预览窗口!'); }, // 预览窗口打开之前的callback
  previewOpenCallback() {
    
     console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
  // 开始打印之前的callback
  beforeOpenCallback() {
    
    
    console.log('开始打印之前!')

  },
  openCallback() {
    
     console.log('执行打印了!') }, // 调用打印时的callback
  closeCallback() {
    
     console.log('关闭了打印工具!'); var element = document.getElementById("print-iframe"); element?.parentNode?.removeChild(element); }, // 关闭打印的callback(无法区分确认or取消)
  clickMounted() {
    
     console.log('点击v-print绑定的按钮了!') },
  standard: '',
  extarCss: ''
}
let list = [{
    
    
    name: "阿哒",
    age: 26,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 2,
    jobs: "研发",
    salary: "1.8k"
},
{
    
    
    name: "阿荣",
    age: 24,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 1,
    jobs: "研发",
    salary: "1.8k"
},
{
    
    
    name: "阿豪",
    age: 26,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 5,
    jobs: "产品",
    salary: "1.8k"
},
{
    
    
    name: "阿晨",
    age: 29,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 9,
    jobs: "设计",
    salary: "1.8k"
},
{
    
    
    name: "阿震",
    age: 30,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 7,
    jobs: "销售",
    salary: "1.8k"
},
{
    
    
    name: "阿锋",
    age: 21,
    sex: "男",
    phone: "12345678901",
    mail: "[email protected]",
    address: "蓝星星国马尔哈哈海岛",
    workAge: 0.1,
    jobs: "售后",
    salary: "1.8k"
}
]
// 点击处理打印

</script>
<style scoped>
.xwtable {
    
    
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #ccc;
}
.xwtable thead td {
    
    
    font-size: 12px;
    color: #333333;
    text-align: center;
    background: url(table_top.jpg) repeat-x top center;
    border: 1px solid #ccc;
    font-weight: bold;
}
.xwtable tbody tr {
    
    
    background: #fff;
    font-size: 12px;
    color: #666666;
}
.xwtable tbody tr.alt-row {
    
    
    background: #f2f7fc;
}
.xwtable td {
    
    
    line-height: 20px;
    text-align: left;
    padding: 4px 10px 3px 10px;
    height: 18px;
    border: 1px solid #ccc;
}
</style>

3.4. Process the content area that needs to be printed before printing

  1. We need to do some things before triggering the printing. We can create two button tags to trigger the processing event and then execute the printing function.
  2. And we can also create a new dom node to store the content to be printed, re-render it to the page and then perform printing.
<template>
  <div>
    <button ref="printRef" v-print="prints">打印2</button>
    <button @click="onClick">打印3</button>
    <div id="printArea">
      <div class="text_styte">我是测试样式的</div>
      <Auto></Auto>
    </div>
  </div>
</template>
<script setup lang="ts">
import Auto from "./Auto.vue";
import print from 'vue3-print-nb'
import {
    
     ref } from 'vue';

const vPrint = print
let printRef = ref();
let prints = {
    
    
  id: 'print-iframe',
  popTitle: '配置页眉标题', // 打印配置页上方的标题
  extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
  preview: false, // 是否启动预览模式,默认是false
  previewTitle: '预览的标题', // 打印预览的标题
  previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
  zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
  previewBeforeOpenCallback() {
    
     console.log('正在加载预览窗口!'); }, // 预览窗口打开之前的callback
  previewOpenCallback() {
    
     console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
  // 开始打印之前的callback
  beforeOpenCallback() {
    
    
    console.log('开始打印之前!')

  },
  openCallback() {
    
     console.log('执行打印了!') }, // 调用打印时的callback
  closeCallback() {
    
     console.log('关闭了打印工具!'); var element = document.getElementById("print-iframe"); element?.parentNode?.removeChild(element); }, // 关闭打印的callback(无法区分确认or取消)
  clickMounted() {
    
     console.log('点击v-print绑定的按钮了!') },
  standard: '',
  extarCss: ''
}
const onClick = () => {
    
    
  test()
  printRef.value.click()
}
const test = () => {
    
    
  let iframe = document.createElement("div");
  iframe.setAttribute("id", "print-iframe");
  iframe.setAttribute(
    "style",
    "width: 100%; height: 100%;  z-index: -9999; border: 0; margin: 0; padding: 0; "
  );
  // 创建节点
  document.body.appendChild(iframe);
  //获取目标节点
  let targetDom = document.getElementById("printArea");
  console.log(targetDom);

  let temp = `<div class="text_styte">我是测试样式的22222222222</div> <div id="pageFooter">Page </div>`;
  temp += targetDom?.innerHTML
  temp += targetDom?.innerHTML
  temp += targetDom?.innerHTML
  temp += targetDom?.innerHTML
  temp += targetDom?.innerHTML
  temp += targetDom?.innerHTML
  temp += targetDom?.innerHTML
  iframe.innerHTML = temp
}
</script>

This article mainly introduces how to use it. Sorry for the bad description. . .

Guess you like

Origin blog.csdn.net/weixin_44982333/article/details/127609629