vue实现打印指定组件内容的示例详解

 更新时间:2024年03月11日 09:43:19   作者:不要止步于此  
这篇文章主要和大家分享一下vue中打印指定组件内容,多页打印自动适配纸张大小打印的方案,文中的示例代码讲解详细,需要的可以参考一下

前言

大家好,最近在做vue项目时使用到了print-js打印指定组件内容,并且还得切换纸张大小时做到自动适配布局的需求,其中遇到了一些问题及我的解题思路想给大家分享一下,希望日后能帮助到大家。

背景

大致需求是在页面中提供一个多选框组,可以从中选择打印哪些内容,每个勾选项打印格式都是一样的,不同的是每个勾选项独占一页,且响应式适配纸张大小,大致效果如下图所示:

了解需求后,我们开始做开发准备工作!

引入print-js,并封装打印函数

npm install print-js@1.3.1

usePrint.js

import printJS from 'print-js'

export const usePrint = () => {
  printJS({
    // 需要打印区域设置的Id
    printable: 'print-area',
    // 打印类型
    type: 'html',
    // 默认值为800,我们把把设置为100%
    maxWidth: '100%', 
    // *代表应用所有样式,默认值为null,如果不设置,打印窗口则会忽略所有样式
    targetStyles: ['*'],
  });

上面主要注意点是注意点是修改maxWidth的默认值及设置targetStyles应用组件所写的样式。想要了解更多可参考:print-js文档

封装打印选择器及打印内容组件

引入插件后,我们先把打印的组件结构先写好,下面先把打印内容选择器结构写好

PrintSelector.vue

<template>
  <div>
    <!-- 这里是我们封装的打印组件 -->
    <PrintArea :data="printData" />
    <el-checkbox :value="checkAll" @change="onCheckAllChange">全选</el-checkbox>
    <div style="margin: 15px 0;"></div>
    <el-checkbox-group v-model="checkedItems" @change="onCheckedChange">
      <el-checkbox v-for="item in options" :label="item.id" :key="item.id">{{item.label}}</el-checkbox>
    </el-checkbox-group>
    <div style="margin: 15px 0;"></div>
    <el-button @click="onPrint">打印</el-button>
  </div>
</template>

<script>
import { usePrint } from './hooks/usePrint'
import PrintArea from './PrintArea.vue'
export default {
  components: {
    PrintArea
  },
  data() {
    return {
      checkedItems: [],
      options: [
        { id: 1, label: '项目1' },
        { id: 2, label: '项目2' },
        { id: 3, label: '项目3' },
      ]
    }
  },
  computed: {
    checkAll() {
      return this.checkedItems.length === this.options.length;
    },
    printData() {
      return this.options.filter(item => this.checkedItems.includes(item.id))
    }
  },
  methods: {
    onCheckAllChange() {
      if(this.checkAll) {
        this.checkedItems = []
      } else {
        this.checkedItems = this.options.map(item => item.id)
      }
    },
    onCheckedChange(val) {
      this.checkedItems = val
    },
    onPrint() {
      usePrint()
    }
  },
}
</script>

注意,上面我们把需要打印的组件PrintArea引入到了PrintSelector组件中,因为在调用printJS方法时需要通过id获取页面dom元素,所以需要组件的dom元素渲染到页面中来,但是我们又不希望页面中显示打印的内容,这里可以通过设置display: none把元素隐藏起来。但,隐藏后有一个需要注意的点,我们先把PrintArea组件写出来,后面再进行讲解。

PrintArea.vue

<template>
  <div id="print-area" v-show="false">
    <div class="item" v-for="item in data" :key="item.id">
      <div class="head">头部</div>
      <div class="main">
        <span class="text">{{ item.label }}</span>
      </div>
      <div class="footer">底部</div>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    data: Array
  }
}
</script>

这个组件就是我们需要打印的内容,外部勾选需要打印的内容后传入当前组件即可,每一个item代表着一页。我们回到前文提到的设置display:none时的问题,我们给idprint-area打印内容跟标签隐藏了起来,如果这时选择项目点击打印后,会发现打印预览窗口为空白!!!

其实问题就是出现给打印区域设置了display:none,所以打印预览窗口也把内容隐藏了,解决办法也简单,就是给打印区域再套一层div,把v-show="false"设置在外层div上即可。

<template>
  <div v-show="false">
    <div id="print-area">
      ...省略其中代码
    </div>
  </div>
</template>

这样子打印窗口就能正常显示内容了。

我们下面通过一个小例子模拟打印预览讲解一下这个问题出现的原因:

demo.html

<body>
  <div class="wrapper">
    <!-- 打印区域 -->
    <div id="print-area" style="display: none;">
      <div class="item">111</div>
      <div class="item">222</div>
    </div>
  </div>
  <!-- 模拟打印预览窗口 -->
  <div id="print-window"></div>
  <script>
    window.onload = function() {
      const printArea = document.getElementById('print-area')
      const printWindow = document.getElementById('print-window')
      // 把打印内容放入打印预览窗口
      printWindow.appendChild(printArea)
    }
  </script>
</body>

上面我们实现了一个简单的模拟打印流程,在打印区域的div上设置了display: none,所以调用appendChild放入模拟的打印窗口div下时,页面并没有内容显示,因为print-area样式还是设置为隐藏。所以我们通过在外面增加一层用来设置隐藏样式的div。这样,我们获取idprint-areadom元素后,当前元素上没有设置隐藏样式,所以appendChild放到打印预览窗口,就不会隐藏打印的内容了!

页面布局设计

我们在PrintArea.vue文件中先把样式补上,看下效果

<style lang="scss" scoped>
#print-area {
  background-color: deeppink;
  .item {
    display: flex;
    flex-direction: column;
    background-color: bisque;
    .head {
      text-align: center;
      line-height: 100px;
      font-weight: bold;
      font-size: 36px;
      background-color: azure;
    }
    .main {
      flex: 1;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .footer {
      text-align: center;
      line-height: 100px;
      font-weight: bold;
      font-size: 20px;
      background-color: #eee;
    }
  }
}
</style>

我们的需求是根据每个item进行分页打印,分页实现可以直接在.item下设置page-break-after: always;样式即可,但是还有一个需求是怎样能够让item响应式适应纸张大小,占满整个区域呢?第一想到的就是height: 100%,但,这样就得保证每一层父组件的高度为页面文档的高度100%。好像不太理想,那设置每一页item的高度为100vh呢?下图可看出也并没有达到想要的效果:

解决办法是让打印区域脱离文档流,设置一个绝对定位

#print-area {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  .item {
    height: 100%;
  }
}

上面我们巧用绝对定位的上下左右距离都为0,使容器能撑满整个纸张大小,最后给每一页item继承100%高度,这样子布局就能够适应各种纸张大小了,即使切换纸张也能够达到撑满整个容器的效果。

总结

以上我们主要是通过在打印内容区域外设置v-show="false"来隐藏元素,使打印内容不受隐藏影响,并通过一个小demo演示了问题出现的原因;接着我们通过在每个item下设置page-break-after: always;实现分页;最后通过绝对定位使容器撑满整个纸张,以达到切换纸张大小时也能撑满整个容器的效果。

到此这篇关于vue实现打印指定组件内容的示例详解的文章就介绍到这了,更多相关vue打印指定组件内容内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue 国际化 vue-i18n 双语言 语言包

    vue 国际化 vue-i18n 双语言 语言包

    这篇文章主要介绍了vue 国际化 vue-i18n 双语言 语言包的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • 详解Vue爬坑之vuex初识

    详解Vue爬坑之vuex初识

    本篇文章主要介绍了详解Vue爬坑之vuex初识 ,Vue 的状态管理工具 Vuex可以解决大型项目中子组件之间传递数据,有兴趣的可以了解下
    2017-06-06
  • 使用vue初用antd 用v-model来双向绑定Form表单问题

    使用vue初用antd 用v-model来双向绑定Form表单问题

    这篇文章主要介绍了使用vue初用antd 用v-model来双向绑定Form表单问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Vue filter介绍及详细使用

    Vue filter介绍及详细使用

    这篇文章主要介绍了Vue filter介绍及详细使用,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-04-04
  • vue如何在引入的el-tree前添加图标

    vue如何在引入的el-tree前添加图标

    这篇文章主要介绍了vue如何在引入的el-tree前添加图标问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • 浅谈vue中数据双向绑定的实现原理

    浅谈vue中数据双向绑定的实现原理

    本篇文章主要介绍了浅谈vue中数据双向绑定的实现原理 ,主要使用v-model这个数据双向绑定,有兴趣的可以了解一下
    2017-09-09
  • vue中beforeRouteLeave实现页面回退不刷新的示例代码

    vue中beforeRouteLeave实现页面回退不刷新的示例代码

    这篇文章主要介绍了vue中beforeRouteLeave实现页面回退不刷新的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • 解决找不到模块“xxx.vue”或其相应的类型声明问题

    解决找不到模块“xxx.vue”或其相应的类型声明问题

    这篇文章主要介绍了解决找不到模块“xxx.vue”或其相应的类型声明问题,具有很好的参考价值,希望对大家有所帮助。
    2022-10-10
  • Vue3 实现验证码倒计时功能(刷新保持状态)

    Vue3 实现验证码倒计时功能(刷新保持状态)

    倒计时的运用场景是需要经常用到的,但是根据业务的不同,好比手机验证码或者是邮箱验证码之类的,即使用户跳转到其它页面或者刷新,再次回到登录也,验证码的倒计时也得保持状态,下面通过本文给大家分享Vue3 验证码倒计时功能实现,感兴趣的朋友一起看看吧
    2022-08-08
  • 利用Nuxt.js做Vuex数据持久化

    利用Nuxt.js做Vuex数据持久化

    这篇文章主要介绍了利用Nuxt.js做Vuex数据持久化问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10

最新评论