Electron学习笔记(二)

news2024/11/29 5:31:26

文章目录

      • 相关笔记
      • 笔记说明
    • 三、引入现代前端框架
      • 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 };
            // 将信息保存在 localStorage
            localStorage.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.coloradmin.cn/o/1658981.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【解决】Android APK文件安装时 已包含数字签名相同APP问题

引言 在开发Android程序过程中&#xff0c;编译好的APK文件&#xff0c;安装至Android手机时&#xff0c;有时会报 包含数字签名相同的APP 然后无法安装的问题&#xff0c;这可能是之前安装过同签名的APP&#xff0c;但是如果不知道哪个是&#xff0c;无法有效卸载&#xff0c;…

KaiwuDB 参编的《分析型数据库技术要求》标准正式发布

近期&#xff0c;中国电子工业标准化技术协会正式发布团体标准《分析型数据库技术要求》&#xff08;项目号&#xff1a;T-CESA 2023-006&#xff09;。该标准由中国电子技术标准化研究院、KaiwuDB&#xff08;上海沄熹科技有限公司&#xff09; 等国内 16 家企业联合起草&…

婚恋程序_婚恋系统_交友程序_ 婚恋相亲交友系统-一站式搭建婚恋平台-社交婚恋系统-相亲交友APP小程序H5系统婚恋交友社交软件开发语音视频聊天平台定制开发

快速搭建线上平台 赋予十大线上盈利 快速精准牵线匹配 会员资料管理跟进 精美多样海报系统 红娘独立办公系统 丰富拓客引流工具 合伙红娘拓展客源 可多区域连锁运营 外呼电销到店邀约 线下约见服务管理 1对1技术服务支持 无感自动更新升级 行业领先的研发技术与服…

武汉凯迪正大—钢管焊缝裂纹探伤仪

产品概述 武汉凯迪正大无损探伤仪是一种便携式工业无损探伤仪器&#xff0c; 能够快速便捷、无损伤、精确地进行工件内部多种缺陷&#xff08;裂纹、夹杂、气孔等&#xff09;的检测、定位、评估和诊断。既可以用于实验室&#xff0c;也可以用于工程现场。 设置简单&#xff0c…

Swift 集合类型

集合类型 一、集合的可变性二、数组&#xff08;Arrays&#xff09;1、数组的简单语法2、创建一个空数组3、创建一个带有默认值的数组4、通过两个数组相加创建一个数组5、用数组字面量构造数组6、访问和修改数组7、数组的遍历 三、集合&#xff08;Sets&#xff09;1、集合类型…

IDEA 使用maven编译,控制台出现乱码问题的解决方式

前言 使用idea进行maven项目的编译时&#xff0c;控制台输出中文的时候出现乱码的情况。 通常出现这样的问题&#xff0c;都是因为编码格式不一样导致的。既然是maven出的问题&#xff0c;我们在idea中查找下看可以如何设置文件编码。 第一种方式 在pom.xml文件中&#xff…

LeetCode-2079. 给植物浇水【数组 模拟】

LeetCode-2079. 给植物浇水【数组 模拟】 题目描述&#xff1a;解题思路一&#xff1a;简单的模拟题&#xff0c;初始化为0&#xff0c;考虑先不浇灌每一个植物解题思路二&#xff1a;初始化为n&#xff0c;考虑每一个植物需要浇灌解题思路三&#xff1a;0 题目描述&#xff1a…

2024车载测试还有发展吗?

2024年已过接近1/4了,你是不是还在围观车载测试行业的发展? 现在入车载测试还来得及吗? 如何高效学习车载测试呢? 首先我们看一下车载测试行情发展,通过某大平台,我们后去数据如下: 这样的数据可以预估一下未来车载测试还是会持续发展. 随着科技的发展和汽车行业的不断创新,…

Python import 必看技巧:打造干净利落的代码结构

大家好,学习Python你肯定绕不过一个概念import,它是连接不同模块的桥梁,是实现代码复用和模块化的关键。本文将带你深入探索Python中import的原理,并分享一些实用的导入技巧。 1. import 原理 导入机制概述 在Python中,模块(module)是一种封装Python代码的方式,它允许…

华为eNSP学习—IP编址

IP编址 IP编址子网划分例题展示第一步:机房1的子网划分第二步:机房2的子网划分第三步:机房3的子网划分IP编址 明确:IPv4地址长度32bit,点分十进制的形式 ip地址构成=网络位+主机位 子网掩码区分网络位和主机位 学此篇基础: ①学会十进制与二进制转换 ②学会区分网络位和…

宋仕强论道之新质生产力

宋仕强论道之新质生产力&#xff0c;宋仕强说当前5G通信、人工智能、万物互联、工业互联网、数字经济、新能源技术和产业等领域正蓬勃发展&#xff0c;成为未来经济增长的重要推动力&#xff0c;也是目前提倡的新质生产力的重要组成部分。而这些领域的发展都离不开数据的采集、…

每日一题7:Pandas-重命名列

一、每日一题 编写一个解决方案&#xff0c;按以下方式重命名列&#xff1a; id 重命名为 student_idfirst 重命名为 first_namelast 重命名为 last_nameage 重命名为 age_in_years 返回结果格式如下示例所示。 解答&#xff1a; import pandas as pddef renameColumns(studen…

计算机系列之面向对象、设计模式

24、面向对象技术&#xff08;重要&#xff0c;10分左右&#xff09; 1、面向对象开发 (1)对象:由数据及其操作所构成的封装体&#xff0c;是系统中用来描述客观事务的个实体&#xff0c;是构成系统的一个基本单位。一个对象通常可以由对象名、属性和方法3个部分组成。 (2)类…

C++容器——stack

stack容器 C的std::stack容器是一个基于适配器模板类实现的容器适配器&#xff0c;它提供了一种后进先出的数据结构&#xff0c;即栈。 特点&#xff1a; 1.后进先出&#xff1a;元素在栈容器中按照后进先出的顺序管理&#xff0c;最后放入的元素将会最先被取出。 2.只能从栈…

《Decoupled Optimisation for Long-Tailed Visual Recognition》阅读笔记

论文标题 《Decoupled Optimisation for Long-Tailed Visual Recognition》 长尾视觉识别的解耦优化 作者 Cong Cong、Shiyu Xuan、Sidong Liu、Shiliang Zhang、Maurice Pagnucco 和 Yang Song、 来自新南威尔士大学计算机科学与工程学院、北京大学计算机学院多媒体信息处…

在Flask中使用Celery完成异步和定时任务(Flask、Celery、Redis)

编程目标 通过使用Flask和Celery&#xff0c;实现一个简单的Web应用程序&#xff0c;能够接收HTTP POST请求&#xff0c;并异步发送电子邮件。 说明 使用Flask创建一个简单的Web应用程序&#xff0c;包含一个HTTP POST路由&#xff0c;用于接收发送电子邮件的请求。使用Cele…

特征提取与深度神经网络(角点检测)

图像特征概述 图像特征表示是该图像唯一的表述&#xff0c;是图像的DNA HOG HOG &#xff08;Histogram of Oriented Gradients&#xff09;是一种用于目标检测的特征描述子。在行人检测中用的最多。HOG特征描述了图像中局部区域的梯度方向信息&#xff0c;通过计算图像中各个…

HTML5 Canvas发光Loading动画特效源码

源码介绍 之前我们分享过很多基于CSS3的Loading动画效果&#xff0c;相信大家都很喜欢。今天我们要来分享一款基于HTML5 Canvas的发光Loading加载动画特效。Loading旋转图标是在canvas画布上绘制的&#xff0c;整个loading动画是发光3D的视觉效果&#xff0c;HTML5非常强大。 …

【Linux】传输文件,补充:VMware中Linux系统无法连接网络的解决方法

Linux系统可以和其他系统之间进行传输文件&#xff0c;只要通过ssh连接成功以后&#xff0c;就能进行文件传输。 Linux系统也可以通过URL规则和网页之间进行传输文件&#xff08;即上传/下载&#xff09;。 1、Linux系统之间传输文件&#xff1a;scp centos7自带ssh服务&…

Nvidia发布Llama3-ChatQA-1.5: 提升对话问答和表格推理能力,平均性能超越GPT-4

前言 近日&#xff0c;Nvidia推出了一款名为Llama3-ChatQA-1.5的对话问答模型。该模型在对话式问答和检索增强型生成等能力方面表现出色&#xff0c;在综合评测指标上甚至超越了当前业界顶尖的GPT-4模型。 技术特点 Llama3-ChatQA-1.5是基于Llama-3基础模型训练而成的。相比之…