添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
vue 浏览器 打印 vue-print-nb.js

vue 浏览器 打印 vue-print-nb.js

备注: 由于本人是个后端,第一次搞前端打印功能,网上很多打印都是一些简单调用vue-print-nb的复制粘贴,没有太多详细的教程,经过摸索,结合多方查找知识点,终于依靠自己的“土方法”完成了需求,特此记录一下,希望对刚做打印功能的朋友们有帮助

npm install vue-print-nb --save

在main.js文件中注册:

import Print from 'vue-print-nb'
Vue.use(Print) // 浏览器打印插件

需求:点击打印按钮,预览打印的订单信息,打印一张A4纸,要求每页有26行表格,底部附带该订单的固定信息。同时支持多页打印。

初始效果:

先调试一页纸,调节好表行和底部固定信息的高度,使之刚好填充满一整页。对于超过26行的数据做代码逻辑分页。使用CSS(style="page-break-after: always;")可以进行强制html分页。对于未满26行的数据,通过计算26-真实数据个数得到空白行数;使用 占位填充。使用CSS(style="width: 0; height: 0; overflow: hidden")来不占空间的先隐藏要打印的信息,这样通过打印按钮点击就可以打印了,浏览器会自动提供预览功能。

这里我根据自己的需求写成了一个vue打印组件print-order-info.vue,然后使用组件实现需求;我采用了vue-print-nb的js配置方式来实现打印,过程遇到一个问题,每次点击绑定了v-print指令的按钮时,该按钮的点击事件还没来得及请求数据表格就已经被打印出来了。因此我的思路是 v-print打印指令 和 @click请求数据事件 不能放在同一个button按钮上,要用 一个显示“打印”的@click请求数据按钮 和 一个隐藏的v-print打印功能按钮;每次点击显示按钮时,先发起数据请求,数据请求返回成功后再使用document.getElementById('printButtonRef').click()模拟按钮点击事件,进而触发被隐藏的v-print按钮的预览打印功能。

单元格内容过多导致单元格变形甚至整个页面的排版,超出部分使用省略号...

组件引入与使用:

print-order-info.vue

<template>
<!--    <el-dialog-->
<!--      title="打印票单"-->
<!--      :visible.sync="dialogVisible"-->
<!--      width="60%"-->
<!--      :before-close="handleClose">-->
      <!-- 这里在调试的时候可以使用el-dialog包裹,使对话框一直可见;待调试完成后,将el-dialog去掉,改用下面的隐藏css样式标签包裹 -->
      <!-- 这里是隐藏的html,用于打印票单时的界面效果 -->
<!--      style="width: 0; height: 0; overflow: hidden" 这里跟对话框二选一,上面的对话框是调试用的-->
      <div style="width: 0; height: 0; overflow: hidden">
        <div id="printMe">
          <!-- 换页CSS,逻辑分页 -->
          <div class="page" v-for="(page, pageIndex) in printData.pageArray" :key="'page' + pageIndex">
            <table class="content-table">
                <th class="base-cell">序号</th>
                <th class="base-cell skuCode">商品编码</th>
                <th class="base-cell skuName">商品名称</th>
                <th class="base-cell weight">重量/斤</th>
                <th class="base-cell binQty">料箱数</th>
              <tr v-for="(row, dataIndex) in page" :key="row.skuCode">
                <td class="center-cell">{{ pageIndex * pageSize + dataIndex + 1 }}</td>
                <td class="center-cell skuCode text-ellipsis">{{ row.skuCode }}</td>
                <td class="base-cell skuName text-ellipsis">{{ row.skuName }}</td>
                <td class="center-cell weight text-ellipsis">{{ row.weight | weightFilter }}</td>
                <td class="center-cell binQty text-ellipsis">{{ row.binQty || 0 }}</td>
              <template v-if="pageIndex === printData.pageArray.length - 1">
                <tr v-for="(blankRow, blankIndex) in blankRowNum" :key="'blank' + blankIndex">
                  <td class="center-cell" style="width: 50px;">&nbsp;</td>
                  <td class="center-cell skuCode" style="width: 160px;">&nbsp;</td>
                  <td class="base-cell skuName">&nbsp;</td>
                  <td class="center-cell weight" style="width: 80px;">&nbsp;</td>
                  <td class="center-cell binQty" style="width: 80px;">&nbsp;</td>
              </template>
            </table>
            <div style="margin: 5px 0"></div>
            <table class="table-header">
                <th class="base-cell">工单号</th>
                <td class="center-cell text-ellipsis" style="width: 230px;">
                  <span v-if="printData.workOrderNO">{{ printData.workOrderNO }}</span>
                  <span v-else>&nbsp;</span>
                <th class="base-cell" style="width: 155px;">生产用料清单号</th>
                <td class="center-cell text-ellipsis" style="width: 260px;" colspan="2">
                  <span v-if="printData.voucherCode">{{ printData.voucherCode }}</span>
                  <span v-else>&nbsp;</span>
              <tr class="multi-row">
                <th class="base-cell">车间</th>
                <td style="width: 645px;" class="center-cell" colspan="4">
                  <span v-if="printData.workShopName" class="moddle-text">{{ printData.workShopName }}</span>
                  <span v-else>&nbsp;</span>
              <tr class="multi-row">
                <th class="base-cell">楼层<br />备注</th>
                <td style="width: 645px;" class="center-cell" colspan="4">
                  <span v-if="printData.floorRemark" class="moddle-text">{{ printData.floorRemark }}</span>
                  <span v-else>&nbsp;</span>
              <tr class="multi-row">
                <th class="base-cell">货号</th>
                <td style="width: 385px;" class="center-cell" colspan="2">
                  <span v-if="printData.productName" class="big-text">{{ printData.productName }}</span>
                  <span v-else>&nbsp;</span>
                <th class="base-cell" style="width: 130px">
                  料箱<br />总数
                <td class="center-cell" style="width: 130px;">
                  <span v-if="printData.totalBinQty" class="small-text">{{ printData.totalBinQty }}</span>
                  <span v-else>&nbsp;</span>
            </table>
          </div>
        </div>
        <button
          id="printButtonRef"
          v-print="printObj">
        </button>
      </div>
<!--    </el-dialog>-->
  </div>
</template>
<script>
import { keepTwoDecimal } from '@/utils/unit'
export default {
  name: 'PrintOrderInfo',
  data() {
    return {
      pageSize: 26, // 每页总行数
      // 控制对话框显示与隐藏
      dialogVisible: false,
      printObj: { // 打印配置对象
        id: 'printMe',
        popTitle: '&nbsp;',
        extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>'
      // 打印表单数据对象
      printData: {
        pageArray: [], // 分页数据(二维数组)
        workShopName: '', // 车间
        voucherCode: '', // 生产用料清单号
        workOrderNO: '', // 工单号
        floorRemark: '', // 楼层备注
        productName: '', // 货号
        totalBinQty: '' // 料箱总数
  filters: {
    weightFilter(weight) {
      return weight ? keepTwoDecimal(weight) : 0
  computed: {
    // 打印票单的空白行数
    blankRowNum() {
      const { pageArray } = this.printData
      if (pageArray && pageArray.length) {
        const pageTotal = pageArray.length
        const lastPage = pageArray[pageTotal - 1]
        return this.pageSize - lastPage.length
      return 0
  methods: {
    // 显示上架绑定dialog
    open(printData) {
      this.dialogVisible = true
      // 本地mock测试数据(仅用于样式的调试和自测)
      // printData = {
      //   workShopName: 'aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbccccccccccccccccddddddddddddddddddeeeeeeeeeeeeeeeeeeffffffffffffffffffffffgggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhh',
      //   voucherCode: 'jii234-ffhrhfttjefeggegejgegggegegrtuuiiewrtcbnkl',
      //   workOrderNO: 'adsdafejfiejgoejiogijegijekgjekjgegegegeegeoijngefef',
      //   floorRemark: '天空那么高!一片片薄纱似的白云在慢慢地浮动着,对我说:你看天空那么高!一片片薄纱似的白云在慢慢地浮动着,对我说:你看天空那么高!一片片薄纱似的白云在慢慢地浮动着,对我说:你看天空那么高!一片片薄纱似的白云在慢慢地浮动着,对我说:你看',
      //   productName: 'crd000311crd000311crd000311crd000311crd000311crd000311crd000311',
      //   totalBinQty: '123456789787984884552259658542665895422658855',
      //   orderDetails: [{
      //     skuCode: '04.070.25.011',
      //     skuName: '中蓝机甲身(牙白身中蓝臂)',
      //     weight: '2.1740000',
      //     binQty: 1
      //   }]
      this.initData(printData)
      // 触发隐藏的打印按钮点击事件,开始打印票单
      document.getElementById('printButtonRef').click()
    // 关闭对话框事件
    handleClose() {
      this.dialogVisible = false
    // 初始化数据
    initData(printData) {
      const {
        orderDetails, // 表格数据
        workShopName, // 车间
        voucherCode, // 生产用料清单号
        workOrderNO, // 工单号
        floorRemark, // 楼层备注
        productName, // 货号
        totalBinQty // 料箱总数
      } = printData
      // 一维数组拆分成二维数组(代码逻辑数据分页)
      const pageArray = []
      const total = orderDetails.length
      const pageNum = Math.ceil(total / this.pageSize)
      for (let i = 0; i < pageNum; i++) {
        const pageArr = []
        if (i === pageNum - 1) {
          pageArray.push(orderDetails)
        } else {
          for (let j = 0; j < this.pageSize; j++) {
            pageArr.push(orderDetails.shift())
          pageArray.push(pageArr)
      this.printData = {
        pageArray, // 分页数据
        workShopName, // 车间
        voucherCode, // 生产用料清单号
        workOrderNO, // 工单号
        floorRemark, // 楼层备注
        productName, // 货号
        totalBinQty // 料箱总数
</script>
<style lang="scss" scoped>
.page {
  page-break-after: always;
  table {
    table-layout: fixed;
    border: 1px solid black;
    width: 100%;
    margin: 0 auto;
    border-spacing: 0;
    border-collapse: collapse;
    font-size: 20px;
  .content-table {
    .skuCode {
      width: 160px;
    .skuName {
      width: 350px;
    .weight {
      width: 80px;
    .binQty {
      width: 80px;
  .base-cell {
    border: 1px solid black;
  .center-cell {
    border: 1px solid black;
    text-align: center;
  .table-header {
    font-size: 20px;
    line-height: 25px;
  .big-text {
    font-size: 40px;
    font-weight: 700;
    line-height: 45px;
    overflow: hidden; // 超出隐藏
    text-overflow: ellipsis;  //溢出显示省略号
    white-space: normal; //常规默认,会折行
    display: -webkit-box;
    -webkit-box-orient: vertical;  //子元素排列 vertical(竖排)orhorizontal(横排)
    -webkit-line-clamp: 2;/*内容限制的行数 需要几行写几就行*/
    border: none; // 隐藏自身边框
    word-break: break-all; // 对字母也换行
  .moddle-text {
    font-size: 27px;
    line-height: 33px;
    overflow: hidden; // 超出隐藏
    text-overflow: ellipsis;  //溢出显示省略号
    white-space: normal; //常规默认,会折行
    display: -webkit-box;
    -webkit-box-orient: vertical;  //子元素排列 vertical(竖排)orhorizontal(横排)
    -webkit-line-clamp: 3;/*内容限制的行数 需要几行写几就行*/
    border: none; // 隐藏自身边框
    word-break: break-all; // 对字母也换行
  .small-text {
    overflow: hidden; // 超出隐藏
    text-overflow: ellipsis;  //溢出显示省略号
    white-space: normal; //常规默认,会折行
    display: -webkit-box;
    -webkit-box-orient: vertical;  //子元素排列 vertical(竖排)orhorizontal(横排)
    -webkit-line-clamp: 4;/*内容限制的行数 需要几行写几就行*/
    border: none; // 隐藏自身边框
    word-break: break-all; // 对字母也换行
  .multi-row {
    height: 100px;
  .text-ellipsis{
    overflow:hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    -o-text-overflow:ellipsis;
</style>

代码优化后预览效果

实际打印效果:(一页调试时的效果)

完结番!

分类:
前端
  •