electron实现静默打印(各种踩坑解决)

前车之鉴

也是阅读了很多资料和前人踩的坑,直接使用webContent.print方法进行打印。其他方式要不就是Bug多,官方修复也有问题;要不就是官方升级版本后不再支持等
不赘述

需求思路

  • main里面实现printerHandle,暴露给渲染线程去调用打印等功能
  • 点击打印后,调出打印页面(新建窗口再隐藏)
  • 通过路径指向打印页面的路由地址,在此页面进行html和css编码,实现打印内容编辑
  • onMounted事件上直接执行打印操作,实现静默
  • 打印完成后,销毁窗口(此过程用户无感)

具体实现

main
  • getPrinter

获取打印机列表,有array.length再继续

  private async getPrinters(event: IpcMainInvokeEvent) {
    const printers = await event.sender.getPrintersAsync()
    return printers
  }
  • print

打印功能,使用官方提供API

  private print(event: IpcMainInvokeEvent, options: WebContentsPrintOptions) {
    return new Promise(resolve => {
      event.sender.print(options, (success: boolean, failureReason: string) => {
        resolve({ success, failureReason })
      })
    })
  }
  • createPrint

创建打印窗口(显示可预览,隐藏可静默)
这里有一个print页面要写,路径指向此页面路由
区分开发环境和生产环境
数据我是通过query传参方式通信,也可以用其他方式(store,cookie等)

  private createPrint(_, data: string) {
    if (win) {
      win.destroy()
      win = null
    }
    win = new BrowserWindow({
      titleBarStyle: 'hidden',
      width: 1240,
      height: 768,
      useContentSize: true,
      frame: false,
      show: false,
      webPreferences: {
        preload: join(__dirname, '../preload/index.js'),
        sandbox: false
      }
    })

    const url = is.dev ? new URL(process.env.ELECTRON_RENDERER_URL!) : new URL('file://')
    url.pathname = is.dev ? '' : join(__dirname, '../renderer/index.html')
    url.hash = `#/print?data=${data}`

    win.loadURL(url.href)
    // win.webContents.openDevTools()

    win.setMenu(null)
    win.on('ready-to-show', () => {
      // win?.show()
      win?.hide()
    })
    win.on('closed', () => {
      win = null
    })
  }
  • destroyPrint
  private destroyPrint() {
    if (win) {
      win.destroy()
      win = null
    }
  }
  • 其他代码
// 在class外部定义win
  let win = null as BrowserWindow | null


// 提供register
  register() {
    ipcMain.handle('get-printers', this.getPrinters)
    ipcMain.handle('print', this.print)
    ipcMain.handle('create-print-window', this.createPrint)
    ipcMain.handle('destroy-print-window', this.destroyPrint)
  }
preload
const api = {
  printer: {
    getPrinter: () => ipcRenderer.invoke('get-printers'),
    print: (options: WebContentsPrintOptions) => ipcRenderer.invoke('print', options),
    createPrintWindow: (data: string) => ipcRenderer.invoke('create-print-window', data),
    destroyPrintWindow: () => ipcRenderer.invoke('destroy-print-window')
  }
}

contextBridge.exposeInMainWorld('api', api)
renderer
  • 触发打印功能
const printClick = ref(false)
const handlePrint = async (data: Order) => {
  if (printClick.value) {
    return
  }
  printClick.value = true
  const list = await window.api.printer.getPrinter()
  console.log(list)

  if (!list.length) {
    toast('没有检测到打印设备!', 'error')
    return
  }
  toast('正在打印出货单...', 'info')
  await window.api.printer.createPrintWindow(
    JSON.stringify({ ...data, createTime: formatDate(data.createTime) })
  )

  printClick.value = false
}
  • 打印窗口页面
<template>
........
<!-- 打印内容和样式 -->
<!-- handle里面 win.show()和控制台功能可临时调试放开注释 -->
</template>


<script setup name="Print" lang="ts">
import { WebContentsPrintOptions } from 'electron'
import { onMounted } from 'vue'
import { useRoute } from 'vue-router'

// 从query获取内容
const query = useRoute().query
const { data } = query
const order: Order = JSON.parse(data as string)

// 这里加了延时,后面解释...
onMounted(() => {
  setTimeout(print, 100)
})

// 这里解释
// el-table看到的样式和打印出来的样式区别更大,在于style内联样式的问题
// 渲染后会在.el-table__header,.el-table__body等DOM上计算出宽度来优化样式
// 如果是用户自己点击打印按钮,再去做样式处理setTableFrame是没有问题的,因为样式是后来我们自己加上的100%
// 而为了实现静默下载,需要在页面渲染完成就立即打印,此时elementui也刚刚计算好宽度赋值,而覆盖掉我们的逻辑
// 所以延时了一波,样式没变化,但打印出来的样式就和我们看到的页面样式一样了
const setTableFrame = () => {
  //el-table设置宽度100%
  const tableNodes = document.querySelectorAll(
    '.el-table__header,.el-table__body'
  ) as NodeListOf<HTMLElement>
  tableNodes.forEach(table => {
    table.style.width = '100%'
    const children = table.children
    for (let i = 0; i < children.length; i++) {
      const child = children[i]
      if (child.localName === 'colgroup') {
        child.innerHTML = ''
      }
    }
  })

  //el-table cell设置每个宽度100%
  const cells = document.querySelectorAll('.cell') as NodeListOf<HTMLElement>
  cells.forEach(cell => {
    cell.style.width = '100%'
    cell.removeAttribute('style')
  })
}

// 打印,先重置el-table样式
const print = async () => {
  setTableFrame()
  try {
  // 设置打印参数,具体看文档
    const options: WebContentsPrintOptions = {
      silent: true,
      margins: { marginType: 'none' },
      pageSize: 'A4'
    }
    await window.api.printer.print(options)
  } catch (error) {
    console.log(error)
  } finally {
  // 打印完成,调用destory
    await window.api.printer.destroyPrintWindow()
  }
}
</script>

踩坑

如果是普通下载(非静默),到此就没有问题了
我的版本是electron@27,设置silent: true后,有问题,会缩放很小,而且居中展示
那么有问题,就肯定不止我一个人遇到,就肯定有解决方法
不过@24官方已经不支持更新维护了,但是基本没啥问题(打印功能很迷,据说时不时一个版本好,一个版本又坏,然后又好)
后期项目还要支持win7,还得降级到@21,没bug不出问题就完事~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/574246.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端CSS基础10(浮动)

前端CSS基础10&#xff08;浮动&#xff09; 浮动元素浮动后的特点浮动后的特点浮动后的影响及解决 浮动布局小练习 浮动 CSS中的浮动是一种布局技术&#xff0c;常用于实现元素的排列和定位。通过使用float属性&#xff0c;可以让元素在页面中左浮动或右浮动&#xff0c;使得…

ubuntu18.04系统编译openwrt21.02.3

搭建ubuntu18.04环境 使用虚拟机安装ubuntu环境网上教程很多&#xff0c;这里不做赘述&#xff0c;主要是安装一些我们在编译openwrt时可能会用到的一些工具环境 sudo apt-get update sudo apt instll libncurses-dev gawk sudo apt-get install build-essential libncurses5…

pytest数据驱动DDT(数据库/execl/yaml)

常见的DDT技术 数据结构&#xff1a; 列表、字典、json串 文件&#xff1a; txt、csv、excel 数据库&#xff1a; 数据库链接 数据库提取 参数化&#xff1a; pytest.mark.parametrize() pytest.fixture() …

2023年图灵奖揭晓,Avi Wigderson成为双冠王

文章目录 Avi Wigderson双冠王个人简介约翰纳什致敬 Avi Wigderson 2024年4月10日&#xff0c;ACM宣布Avi Wigderson为2023年ACM A.M.图灵奖获得者&#xff0c;以表彰他对计算理论的基础性贡献&#xff0c;包括帮助我们重新理解随机性在计算中的作用&#xff0c;以及他在理论计…

第一届长城杯半决赛wp和AWD笔记

目录 AWD 渗透 cfs 单节点1 AWD笔记 AWD工具 文件比较工具 Web漏洞扫描工具 waf工具 代码审计工具 批量网站备份文件泄露扫描工具 cms通杀漏洞的利用 通杀脚本和批量提交flag脚本 防御流程 攻击流程 注意 AWD 解题思路] 首先就是fscan快速扫描对应C段&#xf…

【Qt 学习笔记】Qt常用控件 | 显示类控件 | LCD Number的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 显示类控件 | LCD Number的使用及说明 文章编号&#xf…

贪吃蛇的C语言实现

目录 一、游戏流程设计 二、游戏实现原理 2.1如何创建并管理数据 2.2如何实现蛇身移动 2.3如何实现食物随机放置 2.4如何检测按键与调整光标位置 三、源代码 3.1 test.c 3.2 snake.h 3.3 snake.c 一、游戏流程设计 GameStart WelcomeToGame&#xff1a;打印欢迎界面…

架构师系列-消息中间件(九)- RocketMQ 进阶(三)-消费端消息保障

5.2 消费端保障 5.2.1 注意幂等性 应用程序在使用RocketMQ进行消息消费时必须支持幂等消费&#xff0c;即同一个消息被消费多次和消费一次的结果一样&#xff0c;这一点在使用RoketMQ或者分析RocketMQ源代码之前再怎么强调也不为过。 “至少一次送达”的消息交付策略&#xff…

开启医疗数据新纪元:山海鲸可视化智慧医疗解决方案

在数字化浪潮席卷而来的今天&#xff0c;智慧医疗作为医疗行业的创新力量&#xff0c;正以其独特的技术优势&#xff0c;推动着医疗服务的升级和变革。而在这场变革中&#xff0c;山海鲸可视化以其出色的数据可视化能力&#xff0c;为智慧医疗提供了强大的技术支持&#xff0c;…

用Python和Pygame实现简单贪吃蛇游戏

1.pip安装pygame pygam插件安装 pip install 插件名字 # 安装 pip uninstall 插件名字 # 卸载 pip install 插件名字 -i 指定下载的镜像网址 pip show 插件名字 # 查看插件名字 pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple pip show p…

【网络编程】网络编程概念 | TCP和UDP的区别 | UDP数据报套接字编程 | Socket

文章目录 网络编程一、什么是网络编程1.TCP和UDP的区别 二、UDP数据报套接字编程DatagramSocketDatagramPacket回显服务器&#xff08;echo server&#xff09; 网络编程 一、什么是网络编程 通过网络&#xff0c;让两个主机之间能够进行通信。基于通信来完成一定的功能。 ​…

MacOS 下gif 文件的几种压缩方法

categories: Tips tags: Tips GIF 写在前面 最近想转换几个 tg 的 tgs 文件到 gif, 然后上传到微信, 所以又涉及到了 gif 的操作了. 工具介绍 安装 brew install imagemagick gifsicleimagemagick 是专业的图像处理工具, gifsicle 是专门处理 gif 的小工具 ,都是开源的. …

C++之AVL树的使用以及原理详解

1.AVL树 1.1AVL树的概念 1.2AVL树的定义 1.3AVL树的插入 1.4AVL树的旋转 1. 右单旋 2. 左单旋 3. 左右双旋 4. 右左双旋 1.5AVL树的验证 1.6AVL的实现 在之前对map/multimap/set/multiset进行了简单的介绍&#xff08;C之map_set的使用-CSDN博客&#xff09;&#xff0c;…

说说2024年暑期三下乡社会实践工作新闻投稿经验

作为一名在校大学生,我有幸自去年起参与学院组织的暑期大学生三下乡社会实践团活动。这项活动不仅是我们深入基层、服务社会的重要平台,也是展现当代大学生风采、传递青春正能量的有效途径。然而,如何将这些生动鲜活的实践故事、感人至深的瞬间传播出去,让更多人了解并受到启发…

火绒安全的应用介绍

火绒安全软件是一款集成了杀毒、防御和管控功能的安全软件&#xff0c;旨在为用户提供全面的计算机安全保障。以下是火绒安全软件的一些详细介绍&#xff1a; 系统兼容性强&#xff1a;该软件支持多种操作系统&#xff0c;包括Windows 11、Windows 10、Windows 8、Windows 7、…

xgp加速器免费 微软商店xgp用什么加速器

2001年11月14日深夜&#xff0c;比尔盖茨亲自来到时代广场&#xff0c;在午夜时分将第一台Xbox交给了来自新泽西的20岁年轻人爱德华格拉克曼&#xff0c;后者在回忆中说&#xff1a;“比尔盖茨就是上帝。”性能超越顶级PC的Xbox让他们趋之若鹜。2000年3月10日&#xff0c;微软宣…

25-代码随想录第454题.四数相加II

25-代码随想录第454题.四数相加II 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) &#xff0c;使得 A[i] B[j] C[k] D[l] 0。 为了使问题简单化&#xff0c;所有的 A, B, C, D 具有相同的长度 N&#xff0c;且 0 ≤ N ≤ 500 。所有整数的范…

python 笔记ast.literal_eval

1 介绍 ast.literal_eval 是 Python 标准库 ast 模块中的一个函数&#xff0c;用于安全地评估表示 Python 字面量或容器&#xff08;如列表、字典、元组、集合&#xff09;的字符串 import ast # 解析并执行一个数字表达式 num ast.literal_eval("3.14") prin…

OpenFeign微服务调用组件!!!

1.Feign是什么 GitHub - OpenFeign/feign: Feign makes writing java http clients easierFeign makes writing java http clients easier. Contribute to OpenFeign/feign development by creating an account on GitHub.https://github.com/OpenFeign/feignFeign是Netflix开…

项目十一:爬取热搜榜(小白实战级)

首先&#xff0c;恭喜各位也恭喜自已学习爬虫基础到达圆满级&#xff0c;今后的自已python爬虫之旅会随着网络发展而不断进步。回想起来&#xff0c;我学过请求库requests模块、解析库re模块、lmxl模块到数据保存的基本应用方法&#xff0c;这一次的学习python爬虫之旅收获很多…
最新文章