electron开发采坑小记

2019-07-13 admin

前言

原文地址:electron开发采坑小记-SegmentFault 思否

前前前前段时间做了个桌面端的项目(这篇文章拖了挺久了),功能大概是这样的:

  • 项目左右两栏结构
  • 左侧feed流信息展示
  • 右侧webview打开一个网站
  • 将左侧信息注入右侧网站中

需求很简单,提高运营效率的辅助工具,但是因为一些原因需要做成一个桌面端。 从前端一下子跨到PC桌面端开发,听起来跨度有点大,但在实际的开发中因为有了electron的加持,这一切都变的非常便利,丝毫没有跨度的痕迹,完全变成了web开发那一套,让人不禁感叹js生态的完善,就像有句话说的:

能用JavaScript书写的终将会用JavaScript书写。

实际上我并非直接采用electron,而是使用了更加懒人的electron-vue。通过这一工具将web开发那一套又转移到vue开发上,再辅以iview做UI,开发起来一下子高效了不少。

我们知道electron,但是electron-vue是个什么东西呢,我们还需要了解一下。这东西的官方介绍是这样的。

An Electron & Vue.js quick start boilerplate with vue-cli scaffolding, common Vue plugins, electron-packager/electron-builder, unit/e2e testing, vue-devtools, and webpack.

从这个介绍大致可以看出来这是个基于vue-cli的使用vue开发electron应用的脚手架。可以帮助我们做不少的vueelectron之间结合的基础工作,让我们的开发更加便捷。那么我们就来看看使用electron-vue怎么做开发。我们先从基础的安装开始。

安装

我觉得这个步骤叫安装并不是很严谨,因为electron-vue并不是一个单独的npm包,而是vue-cli的一个模板配置。所以使用起来没有难度,可以按照官方文档的说明即可完成,只有两行命令。

# 安装 vue-cli 和 脚手架样板代码
npm install -g vue-cli
vue init simulatedgreg/electron-vue my-project

如此,我们便得到了一个初始化的electron项目,安装完依赖包就能开发了。初始化过程很简单,但是需要提示一些vue cli使用过程中需要注意的问题:

  • Vue CLI的包名称由vue-cli改成了@vue/cli,导致最新版的vue cli使用vue init命令会报错,而electron-vue的安装文档比较老旧,需要用vue init这个命令,我们可以用一个命令来做桥接

    npm install -g @vue/cli-init 
    
  • windowsGit bash上初始化选择插件时候无法用上下键交互的问题可以换用powershell

开发

项目初始化、安装依赖后我们就可以开发了。这时候可以跑一下项目,他会有个默认的界面。

npm run dev

clipboard.png

对应的目录是这样的(目录会根据安装插件的不同而存在差异)。

├── appveyor.yml
├── build
│   └── icons
│       ├── 256x256.png
│       ├── icon.icns
│       └── icon.ico
├── dist
│   ├── electron
│   └── web
├── package.json
├── README.md
├── src
│   ├── index.ejs
│   ├── main
│   │   ├── index.dev.js
│   │   └── index.js
│   └── renderer
│       ├── App.vue
│       ├── assets
│       ├── components
│       ├── main.js
│       ├── router
│       └── store
└── static

大致的套路跟vue开发一样,不同的是src下有个两个目录:mainrenderer。我们大致可以理解为:

  • main目录存放与electron相关的内容,是主进程
  • renderer目录存放与我们页面相关的内容,是渲染进程

这个通过这个demo页面可以验证。搞清楚这个后开发就很简单了,不需要解释太多。更多的介绍可以看文档

调试

开发过程中调试是不可避免的,根据我的经验这里主要介绍两种调试:

普通页面调试

这种调试就像我们平时在vue开发web应用中使用devtool一样。这个在初始化的代码中已经写好了,在dev模式下默认是开启的。 在/src/main/index.dev.js可以找到这段代码,我们不用太关心。

require('electron-debug')({ showDevTools: true })

内嵌webview页面调试

这个是因为我这个项目需要才涉及到的,需要自己代码实现。 在我的逻辑中大致这样处理的:

<webview ref="webview" src="xxx" ></webview>
this.$refs.webview.addEventListener('dom-ready', res => {
    if (process.env.NODE_ENV === 'development') {
      this.$refs.webview.openDevTools();
    }
});

一些需要关注的核心点

因为这次项目功能很简单,涉及到的点很少,所以这里只介绍项目用到的一些核心点,没用过的没有发言权,就不提了。

webview代码注入

electron提供了webview标签可让我们嵌入自己的网页。想要往里面注入代码可以使用webview上提供的executeJavaScript方法。具体的参数和使用方法这些都是文档层面的内容,不用多提,需要注意的是这个方法的第三个参数是个callback,文档上是这样描述的

callback Function (可选) - 在脚本被执行后被调用。

文档只是描述了这个回调被触发的时机,而没有描述回调触发时候传的参数。 关于触发时机和参数,更具体的描述是这样的。

  • 如果你注入的是同步代码,像querySelector这样的,callback会在注入代码执行完之后触发,并且把你最后querySelector获得的值传入callback
  • 如果你注入的是异步代码,像ajax请求这样的,callback是不会等这个请求有了响应才执行的,而是执行完ajax请求就执行,当然,这种情况下callback是没有传参的。我们后面会介绍怎么拿到注入ajax的返回值

主进程和渲染进程通信

主进程和渲染进程通信是electron中很重要的概念,介绍这块内容的文章也有很多,所以这里就不过多赘述,简单介绍一下大概情况。 通信主要靠两个工具完成:ipcRendereripcMain

在主进程里这样使用ipcMain

const { ipcMain } = require('electron');

ipcMain.on('exit_app', res => {
  app.exit();
})

在渲染进程中这样使用ipcRenderer

const { ipcRenderer } = require('electron');

ipcRenderer.send('exit_app', true);

需要注意的是:消息只能是由渲染进程主动发起,主进程被动监听,然后主进程作响应,不存在由主进程主动向渲染进程通信的方式。代码实现如下:

// 在主进程中
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.reply('asynchronous-reply', 'pong')
})

ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.returnValue = 'pong'
})
//在渲染器进程 (网页) 中
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

ipcRenderer.on('asynchronous-reply', (event, arg) => {
  console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')

electron窗体关闭事件拦截

窗体关闭事件拦截利用的是BrowserWindowclose事件来做处理的。需要注意的是BrowserWindow实例还有个closed事件,区别在于:

  • close在窗口要关闭的时候触发
  • closed窗口已经关闭时触发

这个两个事件一个字母的差距,但是触发时机却大有差距,千万分清楚,当时我就是没看清,浪费了不少时间。

窗体关闭事件拦截的代码实现大致如下:

  mainWindow = new BrowserWindow({
    height: 563,
    useContentSize: true,
    width: 1000
  })

  mainWindow.on('close', event => {
      return event.preventDefault();
  })

遇到的一些问题

webviewbeforeunload弹窗问题

如果内嵌的webview中对beforeunload事件有监听,并有弹窗操作,那么这个事件触发的时候,electron是没有弹窗提示的。用户是没有感知的,这个问题还没有解决办法,是个坑。

clipboard.png clipboard.png (electronwebview是不会显示这些弹窗)

监听webview中注入请求的响应

我的项目里有一个需求是要向webview中注入ajax请求,并且要拿到请求的响应结果。但是electron中比较早的版本中只有对发起的请求有监听,并不支持监听请求的响应,所以要拿到请求的响应结果就是个问题。 但是也不是没办法解决。我这里是借助webviewconsole-message事件来处理。监听webviewconsole-message事件,当拿到请求的响应的时候把响应的内容按照约定的格式打出来,这样就间接的实现了对注入请求的监听。

electron低版本webview中不能跳转

这是一个在electron低版本中存在的问题,在一些新的版本中已经解决了。 这个问题的具体表现就是: 内嵌webview的页面中如果发生302301跳转的话页面会卡在发生跳转的请求那里不再向下进行,查看webviewnetwork可以看到这个问题。 这个问题的解决很简单,升级到最新的electron就能解决这个问题。我这里升级到4.1.4解决了这个问题。 因为electron-vue长时间没更新,里面使用的electron版本还是2.0.4,比较老旧,所以你要是遇到一些奇奇怪怪的问题不妨升级electron来尝试解决。

ctrl+c之后仍有electron进程驻守

调试时候发现的这个问题,虽然是在electron中开发,但是因为还是vue那一套,所以我们改完代码就不用重启就能在electron中看到效果,就是热更新嘛,但是有时候我还是会手动的ctrl + c,这么手动的次数多了之后我发现我的电脑会变的非常卡。排查后我发现ctrl + c并不能完全关闭整个electron应用,每次这么做都会遗留2个electron进程保持活跃,多次之后会遗留很多electron进程,电脑就会变的非常卡,每次都需要手动杀一下进程。这个问题在把模板中自带的

app.on('window-all-closed', event => {
  app.quit();
});

替换为

app.on('window-all-closed', event => {
  app.exit();
});

之后解决(在写文章的时候发现这个问题并没得到复现,不知道是不是新的版本修复了这个问题),其中差异感兴趣的可以深入研究一下

无法捕获信号量的问题

解决上面问题的时候发现electron无法捕获来自命令行的信号量。如果有这个需求的话还是要留意的。

一些不错的博客

在开发过程中也是一边学一边做,发现了一些不错的文章和博客,从里面也获得了不少的帮助,贴出来分享一下。

[转载]原文链接:https://segmentfault.com/a/1190000019747553

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-69594.html

文章标题:electron开发采坑小记

相关文章
哪些互联网产品适合用HTML5开发?
J.P. Morgan(摩根大通集团)不久前发布了有关2013年互联网公司股票的研究报告,其中在预测2013年趋势时,提及移动互联网有关web和app之间的辩论将在3到5年内继续,而摩根认为这对于搜索产品和谷歌是利好消息,因为用户需要处理复...
2015-11-12
Node.js v0.11.16 开发版发布
Node.js v0.11.16 开发版发布了,改进记录包括: openssl: Upgrade to 1.0.1l npm: Upgrade to 2.3.0 url: revert support of path for url.fo...
2015-11-12
Webpack(含 4)配置详解——从 0 配置一套开发模板
前言 源代码 熟悉 webpack 与 webpack4 配置。 webpack4 相对于 3 的最主要的区别是所谓的零配置,但是为了满足我们的项目需求还是要自己进行配置,不过我们可以使用一些 webpack 的预设值。同时 webpack...
2018-05-02
VSCode配置react开发环境的步骤
vscode 默认配置对于 react 的 JSX 语法不友好,体现在使用自动格式化或者粘贴后默认缩进错误,尽管可以通过改变 language mode 缓解错误,但更改 language mode 后的格式化依然不够理想。 通过搭配使用 ...
2017-12-28
JavaScript开发工具
常用的有sublime,webstorm,notepad++等 ...
2015-11-12
VuePress 快速踩坑
最近有个开源项目非常火,那就是尤小右开发的 VuePress,VuePress 可以让您非常方便的在 Markdown 文档中编写 Vue 代码,并且 VuePress 对编译后的 HTML 文件做了一些针对搜索引擎的优化。另外 VuePr...
2018-04-27
Ant design pro 开发笔记 - 表单和数据绑定
antd支持表单双向绑定,开发过程中无需通过onChange()回调函数去获取组件的值,通过 getFieldDecorator() 可以自动完成数据绑定的功能。 { getFieldDecorator(&#x27;email&#x...
2018-05-25
Vue 短信验证码组件开发详解
Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此...
2017-03-17
前端开发领域推荐关注的微信公众号
这篇文章分享了前端领域的多个值得关注的技术、设计、极客、创业相关微信公众号。其中有最受欢迎的热门公众号、也有专注某个技术或设计的公众号,涵盖:算法、JavaScript、Nodejs、程序员、Web前端、Linux、数据库、创业、UI设计和...
2017-03-23
JavaScript库开发者们的规则
保持无侵入性 我的HTML标记不想知道你的JavaScript代码。 严禁修改和扩展Object.prototype! 这条很重要,因此需要一条完全针对它的规则。对象是JavaScript功能的基本构建模块,不要搞乱它们。 不要...
2015-11-11
回到顶部