【Electron】vue+electron白屏问题的解决方案

您所在的位置:网站首页 win10更新之后白屏 【Electron】vue+electron白屏问题的解决方案

【Electron】vue+electron白屏问题的解决方案

2024-07-17 21:57:43| 来源: 网络整理| 查看: 265

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

一、前言

在electron应用的使用过程中,经常会遇到白屏的情况。白屏出现的主要为中情况:

在应用使用过程中,程序白屏崩溃 在应用初次加载的时候,白屏时间过长

针对这两种情况,我们逐一进行解决分析。

二、方案 1.分析解决运行过程中出现的白屏问题

出现这种情况,主要的原因是代码编写不规范导致,例如内存泄漏、dom加载过多或某些地方陷入死循环等。针对这种情况,我们要做的就是软件运行监测,建立日志机制。 首先我们需要引入electron-log,这个插件对于前端来说,就类似于console.log()。我们自定义一个electron-log的实例.

安装

npm install electron-log // or yarn add electron-log

创建一个文件用于创建electron-log实例

// .ElectronLog.js import log from 'electron-log' import { app } from 'electron' import path from 'path' log.transports.file.level = 'debug' log.transports.file.maxSize = 1002430 // 10M log.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}' // ====重新定义日志输入的文件位置以及文件名====start const currentDate = new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-' + new Date().getDate() const fileName = `${currentDate}@${app.getVersion()}.log` const basePath = path.join(app.getPath('userData'), 'electron_log', fileName) log.transports.file.resolvePath = () => basePath // ====重新定义日志输入的文件位置以及文件名====end export default { info (param) { log.info(param) }, warn (param) { log.warn(param) }, error (param) { log.error(param) }, debug (param) { log.debug(param) }, verbose (param) { log.verbose(param) }, silly (param) { log.silly(param) } }

这样我们的日志记录实例就创建完成了。 根据electron官方文档中,里面有关于进程崩溃的监听render-process-gone。官网内容如下

事件: 'render-process-gone'

返回:

event Event

details Object

reason string - 渲染进程消失的原因。 可选值:

clean-exit - 以零为退出代码退出的进程 abnormal-exit - 以非零退出代码退出的进程 killed - 进程发送一个SIGTERM,否则是被外部杀死的。 crashed - 进程崩溃 oom - 进程内存不足 launch-failed - 进程从未成功启动 integrity-failure - 窗口代码完整性检查失败

exitCode Integer - 进程的退出代码,除非在 reason 是 launch-failed 的情况下, exitCode 将是一个平台特定的启动失败错误代码。

渲染器进程意外消失时触发。 这种情况通常因为进程崩溃或被杀死。

我们在监听到程序已经崩溃(白屏了),之后可以通过系统通知告知用户,让用户重载或退出,给用户可选项,而不是不处理。

// 引入日志 import logger from './electron-config/libs/ElectronLog' // 监听程序崩溃事件, win是窗口实例 win.webContents.on('render-process-gone', (e, details) => { const options = { type: 'error', title: '进程崩溃了', message: '这个进程已经崩溃.', buttons: ['重载', '退出'] } recordCrash(details).then(() => { dialog.showMessageBox(options).then(({ response }) => { console.log(response) if (response === 0) reloadWindow() else app.quit() }) }).catch((e) => { console.log('err', e) }) }) function recordCrash (arg) { return new Promise(resolve => { // 崩溃日志请求成功.... log.info(arg) resolve() }) } // 重载 function reloadWindow () { app.relaunch() app.exit(0) }

可以在控制台输入process.crash()检测是否设置成功。 那我们如何发现错误呢?可以使用process.on捕捉全局uncaughtException异常

process.on('uncaughtException', function (err) { log.error("=======捕捉异常=======start") log.error(err) log.error("=======捕捉异常=======end") })

这样我们就可以通过记录日志的方式发现导致electron应用运行中白屏的问题,以及做了白屏后的处理机制。

2.解决初次加载白屏时间过长问题

初次加载白屏的主要原因就是项目首屏加载速度过慢,可以通过优化vue项目加载效率的方式提高首屏加载速率,例如路由懒加载、打包拆分、组件按需引入。

这些方法是可以解决初次白屏时间过长的。但今天这里要讲的不是这种方式,而是一种较为偷懒的方法,即给窗口加个loading过度加载白屏这段时间。

我的思路是给需要通过加载过度的窗口添加一个子窗口,这个子窗口里面仅展示一个loading,等父级窗口加载完成后,再关掉子窗口。

首先,我们先写一个html静态的loading页面,我将静态页面public文件中

x loading... const remote = require('electron').remote const ipcRenderer = require('electron').ipcRenderer // 判断当前系统若为windows,将关闭按钮显示出来 if (process.platform !== 'darwin') { document.getElementById('closeBtn').style.display = 'block' } // windows环境下需要给子窗口添加关闭按钮,因为在loading过程中用户可能会选择关闭窗口 const controlWindow = () => { remote.getCurrentWindow().close() } // 获取当前页面url let url = window.location.href let GetQueryString = name => { var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)') var r = window.location.search.substr(1).match(reg) if (r != null) return decodeURI(r[2]) return null } // 若需要显示标题,则在地址栏中获取 windowTitle 为约定窗口名称字段(见下方) let windowTitle = GetQueryString('windowTitle') if (windowTitle) { document.getElementById('title').innerText = windowTitle } html { width: 100%; height: 100%; } body { margin: 0; margin: auto; } body, #loading-page{ width: 100%; height: 100%; } #loading-page { display: flex; align-items: center; justify-content: center; background: #fff; } #loadingImgPre{ height:40px; width:40px; position: relative; } .close-icon { display: none; width: 40px; height: 40px; text-align: center; line-height: 34px; cursor: pointer; -webkit-app-region: no-drag; position: absolute; pointer-events: auto; top: 0; right: 0; font-size: 14px; font-weight: 600; color: #1f2329; } .close-icon:hover { background: #FF6161 !important; } .close-icon:hover span { color: #fff !important; } #title{ font-size: 14px; color: #1f2329; font-weight: 500; height: 40px; width: 200px; text-align: center; position: absolute; top: 0; line-height: 40px; }

之后我们创建一个js文件,用于存放子窗口的实例

import { BrowserWindow } from 'electron' const path = require('path') const CreateProcessLoadingPage = function (win, data = {}) { const child = new BrowserWindow({ width: data.width || 1024, height: data.height || 640, parent: win, frame: false, title: 'loading...', show: false, center: true, fullscreenable: false, transparent: true, titleBarStyle: 'hidden', trafficLightPosition: { x: 12, y: 18 }, visualEffectState: 'active', webPreferences: { nodeIntegration: true, enableRemoteModule: true } }) // 加载本地html文件---loading页(静态页面放在了public文件中) // eslint-disable-next-line no-undef child.loadFile(path.join(__static, '/LoadingPage.html'), { query: data }) // 当子窗口已经准备完成,可以展示时 child.once('ready-to-show', () => { // 开发调试使用 // child.webContents.openDevTools() // ====设置子窗口的位置以及大小,与父窗口同步大小位置(完全覆盖)====start child.setPosition(win.getPosition()[0], win.getPosition()[1]) const width = win.getSize()[0] < 1024 ? 1024 : win.getSize()[0] const height = win.getSize()[1] < 640 ? 640 : win.getSize()[1] child.setSize(width, height) // ====设置子窗口的位置以及大小,与父窗口同步大小位置(完全覆盖)==== // 之后同步展示父窗口->子窗口 win.show() child.show() }) // 监听子窗口关闭,则父窗口关闭--同步操作 child.on('close', () => { win.close() }) child.on('maximize', () => { win.maximize() }) child.on('unmaximize', () => { win.unmaximize() }) child.on('minimize', () => { win.minimize() }) child.on('restore', () => { win.restore() }) // 监听父窗口已经准备完成,可以展示了 win.once('ready-to-show', () => { // 现将父窗口获取焦点 win.focus() // 此时判断子窗口有没有被销毁,没有被销毁的话 if (!child.isDestroyed()) { setTimeout(() => { // 稍作1s的延迟,之后关闭子窗口 if (!child.isDestroyed()) { child.destroy() } }, 1000) } }) } export default CreateProcessLoadingPage

子窗口loading我们也创建完成了, 下面是使用它

// 引入子窗口实例 import CreateProcessLoadingPage from './CreateProcessLoadingPage' // 在父窗口创建实例成功时,调用子窗口loading的实例方法,win为父窗口实例 CreateProcessLoadingPage(win)

最后我们就解决了electron应用首屏加载长时间的白屏问题。完结!撒花!

三、后记

如果你的loading 使用的是lottie插件,建议将lottie插件文件下载下来,作为静态文件,引入loading静态页中,但是会报错,全局变量找不到lottie。解决方法就是需要更改下lottie.js中的源代码,如下

// 引入子窗口实例 (typeof navigator !== 'undefined') && (function (root, factory) { if (typeof define === 'function' && define.amd) { define(function () { return factory(root) }) } // 在electron中本身有module的存在,所以会执行到这里,但是factory返回的lottie对象赋值到了错误的地方,导致全局lottie对象丢失 // else if (typeof module === "object" && module.exports) { // module.exports = factory(root); // } else { root.lottie = factory(root) root.bodymovin = root.lottie } }((window || {}), function (window) {

这样就解决了,无法获取lottie的问题。

感谢观看!希望能帮助到你!



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭