Electron学习笔记(二)

文章目录

      • 相关笔记
      • 笔记说明
    • 三、引入现代前端框架
      • 1、配置 webpack
        • (1)安装 webpack 和 electron-webpack:
        • (2)自定义入口页面
      • 2、引入 Vue
        • (1)安装 Vue CLI
        • (2)调试配置 -- 调试主进程需要增加额外的配置
    • 四、窗口
      • 1、自定义窗口的标题栏
      • 2、窗口的控制按钮、记录与恢复窗口状态
      • 3、创建不规则窗口

相关笔记

  • Electron学习笔记(一)
  • Electron学习笔记(二)
  • 使用 electron-vite-vue 构建 electron + vue3 项目并打包

笔记说明

文本为学习《Electron 实战 入门、进阶与性能优化 刘晓伦 著》时所记录的笔记 主要将书本上的案例运行一遍,针对原理部分并无相关记录。笔记记录于 2023年9月。

三、引入现代前端框架

1、配置 webpack

(1)安装 webpack 和 electron-webpack:

说明: 这两个模块都是开发依赖,生产环境并不需要它们,所以在安装命令中都添加了 --dev 参数。

运行环境:(建议)
Node.js: 16.20.2
webpack: 4.46.0

yarn add webpack@4.46.0 --dev

yarn add electron-webpack --dev

项目目录结构:

项目目录结构

修改 package.json 文件内容如下:

  "scripts": {"start": "electron-webpack dev","build": "electron-webpack build"}

src/main目录: 放置主进程相关的代码,此目录下需要有主进程的入口文件,默认为 index.js。 index.js 文件内容如下:

const {app,BrowserWindow} = require('electron');
let path = require('path');
let URL = require('url');let win = null;
let url = '';app.on('ready', function() {win = new BrowserWindow({// 为页面集成Node.js环境webPreferences: {nodeIntegration: true,contextIsolation: false}});// 判断当前代码是在生产环境还是开发环境中运行if(process.env.NODE_ENV !== 'production') { // 开发环境url = 'http://localhost:' + process.env.ELECTRON_WEBPACK_WDS_PORT;}else {// 生产环境url = URL.format({pathname: path.join(__dirname,'index.html'),protocol: 'file'});}win.loadURL(url);// 程序启动后开启 开发者工具win.webContents.openDevTools();win.on('close',function() {win = null;})
});app.on('window-all-closed',function() {app.quit();
})

src/renderer目录: 复制渲染进程相关的代码,此目录下需要有渲染进程的入口文件,默认为index.js。

在该目录下新建一个 renderModule.js 文件,文件内容如下:

export default {say: function() {document.write('Hello webpack!');}
}

index.js 文件内容如下:

import renderModule from "./renderModule";
renderModule.say();

src/common目录: 放置既会被主进程代码用到,又会被渲染进程代码用到的公共代码,一般为一些工具类代码。

src/static目录: 放置不希望被webpack打包的内容,程序可以通过__static全局变量访问到这个目录的绝对路径。

启动项目:yarn start

(项目启动后,修改 renderModule.js 中的代码,无需重启应用,即可自动刷新)

运行结果:

运行结果


(2)自定义入口页面

package.json 中增加如下配置节,文件内容如下:

  "electronWebpack": {"renderer": {"template": "src/renderer/index.html"}}

src/renderer目录 下新建一个 index.html 文件:

<body><h1>你好,渲染进程主页</h1>
</body>

运行结果:

运行结果


2、引入 Vue

(1)安装 Vue CLI

yarn global add @vue/cli

使用 Vue CLI 创建一个 Vue 项目,执行以下命令:

vue create electron_basic03

根据提示选择配置项,此处选择:Vue2 + Yarn

安装 Vue 插件 electron-builder:

vue add electron-builder

启动项目:

yarn electron:serve

运行结果:

运行结果

Vite + Vue3 + TS 可参考: https://blog.csdn.net/qq_45897239/article/details/138490747?spm=1001.2014.3001.5501

(2)调试配置 – 调试主进程需要增加额外的配置

打开 .vscode 目录(没有则创建),创建 tasks.json 文件,文件内容如下:

{"version": "2.0.0","tasks": [{"label": "electron-debug","type": "process","command": "./node_modules/.bin/vue-cli-service","windows": {"command": "./node_modules/.bin/vue-cli-service.cmd"},"isBackground": true,"args": ["electron:serve","--debug"],"problemMatcher": {"owner": "custom","pattern": {"regexp": ""},"background": {"beginsPattern": "Starting development server\\.\\.\\","endsPattern": "Not launching electron as debug argument was passed\\."}}}]
}

在 .vscode 目录下创建 launch.json 文件,文件内容如下:

{"version": "0.2.0","configurations": [{"name": "Electron: Main","type": "node","request": "launch","protocol": "inspector","runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron","windows": {"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"},"preLaunchTask": "electron-debug","args": ["--remote-debugging-port=9223","./dist_electron"],"outFiles": ["${workspaceFolder}/dist_electron/**/*.js"]},{"name": "Electron: Renderer","type": "chrome","request": "attach","port": 9223,"urlFilter": "http://localhost:*","timeout": 30000,"webRoot": "${workspaceFolder}/src","sourceMapPathOverrides": {"webpack:///./src/*": "${webRoot}/*"}}],"compounds": [{"name": "Electron: All","configurations": ["Electron: Main","Electron: Renderer"]}]
}

参考链接(Electron官网):https://www.electronjs.org/zh/docs/latest/tutorial/debugging-vscode

参考链接(VSCode官网):https://code.visualstudio.com/docs/editor/debugging

四、窗口

1、自定义窗口的标题栏

使用 Vue CLI 创建完项目后:

src/background.js 文件中禁用默认边框:

  const win = new BrowserWindow({// 禁用窗口默认边框frame: false,width: 800,height: 600,webPreferences: {nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,// 使用 remote 模块enableRemoteModule: true,}})

打开 src/App.vue,修改 template 中的代码:

<template><div id="app"><div class="titleBar"><!-- logo和标题区域 --><div class="title"><div class="logo"><img src="@/assets/logo.png" /></div><div class="txt">窗口标题</div></div><!-- 窗口右上角工具栏,控制窗口的放大、缩小、关闭 --><div class="windowTool"><div @click="minisize"><i class="iconfont iconminisize"></i></div><div v-if="isMaxSize" @click="restore"><i class="iconfont iconrestore"></i></div><div v-else @click="maxsize"><i class="iconfont iconmaxsize"></i></div><div @click="close" class="close"><i class="iconfont iconclose"></i></div></div></div><div class="content"><router-view /></div></div>
</template>

src/App.vue 中,修改 style 中的代码:

第一部分:

<style>
body,
html {margin: 0px;padding: 0px;overflow: hidden;height: 100%;
}#app {text-align: center;margin: 0px;padding: 0px;height: 100%;overflow: hidden;box-sizing: border-box;border: 1px solid #f5222d;display: flex;flex-direction: column;
}
</style>

第二部分:

<style lang="scss" scoped>// 导入外部字体图标样式文件
@import url(https://at.alicdn.com/t/font_1378132_s4e44adve5.css);.titleBar {height: 38px;line-height: 36px;background: #fff1f0;display: flex;border-bottom: 1px solid #f5222d;.title {flex: 1;display: flex;-webkit-app-region: drag;.logo {padding-left: 8px;padding-right: 6px;img {width: 20px;height: 20px;margin-top: 7px;}}.txt {text-align: left;flex: 1;}}.windowTool {div {color: #888;height: 100%;width: 38px;display: inline-block;cursor: pointer;i {font-size: 12px;}&:hover {background: #ffccc7;}}.close:hover {color: #fff;background: #ff4d4f;}}
}.content {flex: 1;overflow-y: auto;overflow-x: auto;
}
</style>

使用 scss 前需要下载相应的包:

环境:
Node.js: 16.20.2
sass-loader: 10
node-sass: 6

1、使用淘宝镜像源

npm set sass_binary_site http://registry.npmmirror.com/dist/node-sass

2、先下载 sass-loader (此处指定版本为@10)

yarn add sass-loader@10 --dev

3、再下载 node-sass (此处指定版本为@6)

yarn add node-sass@6 --dev

运行结果:

运行结果


2、窗口的控制按钮、记录与恢复窗口状态

src/App.vue 中,修改 script 中的代码:

<script>
import { remote } from 'electron';export default {name: 'App',data() {return {// 记录当前窗口是否最大化isMaxSize: false}},methods: {// 关闭窗口close() {remote.getCurrentWindow().close();},// 窗口最小化minisize() {remote.getCurrentWindow().minimize();},// 窗口还原restore() {remote.getCurrentWindow().restore();},// 窗口最大化maxsize() {remote.getCurrentWindow().maximize();},// 窗口防抖函数// 作用:短期内有大量的事件触发时,只会执行最后一次事件关联的任务。debounce(fun) {let timeout = null;return function () {clearTimeout(timeout);timeout = setTimeout(() => {fun.apply(this, arguments);}, 300);}},// 记录窗口状态setState() {let win = remote.getCurrentWindow();// 返回一个 Rectangle 对象,包含窗口在屏幕上的坐标和大小消息let rect = win.getBounds();// 返回当前窗口是否最大化状态let isMaxSize = win.isMaximized();let obj = { rect, isMaxSize };// 将信息保存在 localStoragelocalStorage.setItem('winState', JSON.stringify(obj));},// 恢复窗口状态// 获取存储在 localStorage 内的窗口状态数据,用于恢复之前记录的窗口状态getState() {let win = remote.getCurrentWindow();let winState = localStorage.getItem('winState');if (winState) {winState = JSON.parse(winState);// 如果上一次关闭窗口是窗口处在最大化,则此次也最大化显示if (winState.isMaxSize) win.maximize();else win.setBounds(winState.rect);}}},// 监听窗口的最大化、还原状态mounted() {let win = remote.getCurrentWindow();// 监听 win 的 maximize 事件 -- 窗口最大化win.on('maximize', () => {this.isMaxSize = true;this.setState();console.log('---最大化---');});// 监听 win 的 unmaximize 事件 -- 退出窗口最大化win.on('unmaximize', () => {this.isMaxSize = false;this.setState();console.log('---退出最大化---');});// 监听 win 的 move 事件 -- 窗口拖动win.on('move', this.debounce(() => {console.log('--窗口被拖动--');this.setState();}));// 监听 win 的 resize 事件 -- 窗口缩放win.on('resize', this.debounce(() => {console.log('--窗口缩放--');this.setState();}));this.isMaxSize = win.isMaximized();this.getState();win.show();}
}
</script>

若想使 remote 模块可以使用,还需在 vue.config.js 文件中添加配置:

const { defineConfig } = require('@vue/cli-service');module.exports = defineConfig({transpileDependencies: true,lintOnSave: false,// 添加以下配置pluginOptions: {electronBuilder: {nodeIntegration: true,}}
})

src/background.js 中,添加以下代码:

win = new BrowserWindow({//...show: false
})

说明:之所以关闭窗口的显示,是因为src/App.vue 中的 getState() 函数更新了窗口的位置,窗口会先显示在屏幕的正中间,然后才移动到正确的位置,我们希望程序更新完窗口的位置、大小等信息后再显示。


3、创建不规则窗口

src/background.js 中,添加以下代码:

const win = new BrowserWindow({width: 800,height: 600,// 禁用窗口默认边框frame: false,// 窗口的透明属性transparent: true,// 窗口大小不可调整resizable: false,// 禁止窗口最大化maximizable: false,webPreferences: {nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,enableRemoteModule: true,}
})

src/App.vue 文件中, template 内容如下:

<template><div id="app"><HelloWorld></HelloWorld></div>
</template>

style 文件内容如下:


<style>
html,
body {margin: 0px;padding: 0px;/* 指示该元素不再是鼠标事件的目标。鼠标事件穿透该元素 */pointer-events: none;
}#app {/* 移动至屏幕正中央 */position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);box-sizing: border-box;width: 380px;height: 380px;border-radius: 190px;border: 1px solid green;background: #fff;overflow: hidden;pointer-events: auto;
}
</style>

script 内容如下:

<script>
import HelloWorld from './components/HelloWorld.vue';export default {name: 'App',components: {HelloWorld,},mounted() {const remote = require("electron").remote;let win = remote.getCurrentWindow();// 监听 mousemove 事件。// 当鼠标移入窗口圆形内容区时,不允许鼠标事件穿透;// 当鼠标移入透明区时,允许鼠标事件穿透window.addEventListener("mousemove", event => {let flag = event.target === document.documentElement;if (flag) {// setIgnoreMouseEvents:使窗口忽略窗口内的所有鼠标事件,// 并且在此窗口中发生的所有鼠标事件都将被传递到此窗口背后的内容// forward:true 只有点击事件会穿透窗口,鼠标移动事件仍会正常触发win.setIgnoreMouseEvents(true, { forward: true });}else {win.setIgnoreMouseEvents(false);}});win.setIgnoreMouseEvents(true, { forward: true });}
}
</script>

src\components\HelloWorld.vue 文件中,HelloWorld.vue 文件内容如下:

<template><div class="hello"><img src="../assets/logo.png" alt=""></div>
</template><script>
export default {name: 'HelloWorld',
}
</script><style>
.hello {position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);width: 80%;height: 80%;
}
.hello img {position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);object-fit: scale-down;
}
</style>

运行结果:

运行结果

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

陶瓷生产线智能巡检系统

一、背景 在陶瓷生产的过程中&#xff0c;有一个至关重要但又常常被忽视的环节&#xff0c;那就是陶瓷生产炉的巡检。陶瓷生产炉长度一般约为100~200米&#xff0c;中间烧制输送线有大量轴承。需要巡检的点位包括顶层冒火检测&#xff0c;中间滚轴是否内部断轴检测&#xff0c…

流畅的Python阅读笔记

五一快乐的时光总是飞快了&#xff0c;不知多久没有拿起键盘写文章了&#xff0c;最近公司有Python的需求&#xff0c;想着复习下Python吧&#xff0c;然后就买了本Python的书籍 书名&#xff1a; 《流畅的Python》 下面是整理的一个阅读笔记&#xff0c;大家自行查阅&#xf…

Docker部署Metabase

文章目录 Docker安装MetabaseCentOS7安装Docker获取最新的 Docker 镜像启动Metabase容器在Metabase初始化时查看日志访问Metabase Metabase 的 ClickHouse 驱动程序安装环境简介删除容器创建容器下载click house驱动放入驱动重启容器将元数据库连接到 ClickHouse报错解决 Docke…

JAVA链表相关习题2

1.反转一个单链表。 . - 力扣&#xff08;LeetCode&#xff09; //2在1前面 //1在3前面 //ListNode curhead.next //head.nextnull(翻转后头节点变为最后一个节点) // while(cur ! null) { //记录 当前需要翻转节点的下一个节点 ListNode curNext cu…

Python——Fastapi管理平台(打包+优化)

目录 一、配置多个表 1、后端项目改造 2、导包报错——需要修改&#xff08;2个地方&#xff09; 3、启动后端&#xff08;查看是否有问题&#xff09; 4、配置前端 二、打包——成exe文件&#xff08;不包含static文件&#xff09;简单 1、后端修改 2、前端修改 3、运行打包命…

RisingWave基本操作

什么是RisingWave RisingWave 是一款基于 Apache 2.0 协议开源的分布式流数据库。RisingWave 让用户使用操作传统数据库的方式来处理流数据。通过创建实时物化视图&#xff0c;RisingWave 可以让用户轻松编写流计算逻辑&#xff0c;并通过访问物化视图来对流计算结果进行及时、…

|Python新手小白中级教程|第二十三章:列表拓展之——元组

文章目录 前言一、列表复习1.索引、切片2.列表操作字符3.数据结构实践——字典 二、探索元组1.使用索引、切片2.使用__add__((添加元素&#xff0c;添加元素))3.输出元组4.使用转化法删除元组指定元素5.for循环遍历元组 三、元组VS列表1.区别2.元组&#xff08;tuple&#xff0…

vant中van-tabs使用中的小问题

1. 怎么去掉默认选中的效果 van-tabs默认情况下启用第一个标签&#xff0c;实际开发中不满足需求&#xff0c;想要点击后再进行选中 解决办法 首先&#xff0c;在标签组数中&#xff0c;添加一个占位标签在样式中设置首个标签不显示代码如下&#xff1a; //js 实际有意思的…

OPC :快速上手

本系列为OPC技术的快速上以及持续研究和技术实战专栏&#xff0c;将不定期更新。 本章节提供OPC系列技术博文的快速导航。 《OPC服务器简介和入门介绍》 《物联网平台如何为OPC服务器创造新生命力》 《OPC服务器开发之WtOPCSvr——开发文档&#xff08;1&#xff09;》 《OPC服…

自动控制原理学习--平衡小车的控制算法(二)

上一节 在matlab建模&#xff0c;这一节PID控制. 一、模型 直接先放一张matlab simulink的模型&#xff08;只有直线速度环和平衡环&#xff0c;串联PID&#xff09;&#xff0c;就在上一节的基础上加了两个PID。 二、PID控制 PID的好处就是可以不用动力学建模&#xff08;当…

Kubernetes学习-集群搭建篇(一) 搭建Master结点

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Kubernetes渐进式学习-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1. 前言 2. 集群搭建方式 3. 环境说明 4. 利用kubeadm初始化Ma…

【强训笔记】day14

NO.1 思路&#xff1a;用一个哈希表&#xff0c;先遍历s1&#xff0c;统计哈希表内的字符个数&#xff0c;在遍历s2&#xff0c;s2中的字符在哈希表中减去&#xff0c;如果哈希表中的字符个数小于0那么就输出No。 代码实现&#xff1a; #include <iostream> #include&…