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 };
            // 将信息保存在 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.mfbz.cn/a/606168.html

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

相关文章

【Micropython Pitaya Lite教程】烧录固件

文章目录 前言一、编译固件源码二、烧录固件总结 前言 MicroPython是一种精简的Python 3解释器&#xff0c;可以在微控制器和嵌入式系统上运行。Pitaya Lite是一款基于ESP32的微控制器开发板&#xff0c;它结合了低功耗、Wi-Fi和蓝牙功能。结合MicroPython和Pitaya Lite&#…

Python AI库pandas读写数据库的应用操作——以sqlite3为例

Python AI库pandas读写数据库的应用操作——以sqlite3为例 本文默认读者具备以下技能&#xff1a; 熟悉python基础知识&#xff0c;vscode或其它编辑工具 已阅读Pandas基础操作文章,了解pandas常见操作 具备自主扩展学习能力 在数据分析和人工智能领域&#xff0c;pandas库和s…

Ruby中的字符串转换方法

在Ruby中&#xff0c;你可以使用各种方法来转换字符串。下面是一些常用的方法&#xff0c;当然选择哪种适用的方法还得更具具体项目来做调整。日常使用中下面的错误也是比较常见的&#xff0c;看看我们怎么处理哈。 1、问题背景 在Python中&#xff0c;内置的数据结构都有一个…

VMware 虚拟机打开一段时间后卡死,VNX进程CPU占比高

一、问题描述 打开虚拟机后可以正常运行 运行几分钟后突然卡死 然后通过任务管理器可以观察到VMware Workstation VMX应用进程的CPU占比高&#xff0c;CPU也出现异常 关闭虚拟机重新开启&#xff0c;还是一样卡死 二、系统环境 系统: Windows10 VMware: Workstation 17 Pro …

visa/masterCard虚拟信用卡可以用于欧洲亚马逊店Amazon铺吗?欧洲亚马逊Amazon店铺扣租金

亚马逊是网络上最早开始经营电子商务的公司之一&#xff0c;亚马逊成立于1995年&#xff0c;一开始只经营网络的书籍销售业务&#xff0c;现在则扩及了范围相当广的其他产品&#xff0c;已成为全球商品品种最多的网上零售商和全球互联网企业。 很多小伙伴需要开多个站点店铺&a…

软胶囊硬度计:QC部门保障药品质量的精准工具

软胶囊硬度计&#xff1a;QC部门保障药品质量的精准工具 一、引言 随着医药行业的快速发展和药品监管力度的加强&#xff0c;制药企业对于药品质量的要求越来越高。在药品的生产过程中&#xff0c;软胶囊作为一种常见的剂型&#xff0c;其硬度的控制对于药品质量至关重要。软胶…

数组进了多个obj,但是 在修改某个num值时,导致别的num值也发生了变化如何解决?

问题如下&#xff1a; 遇到的问题&#xff0c;数组monthArr1 push进了多个obj,但是 在修改某个num值时&#xff0c;导致别的num值也发生了变化。 而这就是深拷贝浅拷贝的问题。 解决浅拷贝使用深拷贝最简单方法 &#xff1a;JSON.parse(JSON.stringify(obj)) 或者: 使用深拷…

学习Java的日子 Day44 HTML基础

Day44 HTML 学习路线&#xff1a; 前端&#xff1a;展示页面、与用户交互 — HTML 后端&#xff1a;数据的交互和传递 — JavaEE/JavaWeb 1.网页的组成部分(HTMLCSSJavaScript) 前端开发的工作模式&#xff1a;开发输出htmlcssjs HTML&#xff1a;页面结构 CSS&#xff1a;页面…

【linux】——日志分析

1. 日志文件 1.1 日志文件的分类 日志文件&#xff1a; 是用于记录Linux系统中各种运行消息的文件&#xff0c;相当于Linux主机的“日记". 日志文件对于诊断和解决系统中的问题很有帮助&#xff0c;系统一旦出现问题时及时分析日志就会“有据可查”。此外。当主机遭受攻…

JVM的垃圾回收

JVM简介 JVM 是 Java Virtual Machine 的简称&#xff0c;意为 Java虚拟机。 虚拟机:是指通过软件模拟的具有完整硬件功能、运行在一个完全隔离的环境中完整计算机系统 1.JVM的内存区域划分 jvm是一个java进程 每一个java进程就是一个jvm实例 一个进程运行过程中 就要从操作系…

uniapp0基础编写安卓原生插件之编写安卓页面在uniapp上显示(摄像头调用)

前言 如果你对安卓插件开发部分不熟悉你可以先看uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件 效果 开始 dcloud_uniplugins.json {"nativePlugins": [{"hooksClass": "","plugins": [{&…

软件试运行方案,试运行报告(word原件获取)

一、 试运行目的 &#xff08;一&#xff09; 系统功能、性能与稳定性考核 &#xff08;二&#xff09; 系统在各种环境和工况条件下的工作稳定性和可靠性 &#xff08;三&#xff09; 检验系统实际应用效果和应用功能的完善 &#xff08;四&#xff09; 健全系统运行管理体制&…

Pspice for TI学习

Pspice for TI中PSpice Part Search空白解决方法 配置环境变量 Cad_PSpice_TI_Regr_Srvr https://software-dl.ti.com/pspice/S009 重新安装2023版的Pspice Pspice安装链接 打开新安装的软件即可发现PSpice Part Search可以正常使用了 VSIN各参赛的含义 VOFF直流偏置VAMPL…

JavaEE企业级开发中常用的Stream流

介绍 在Java编程中&#xff0c;Stream流是Java 8引入的一个重要概念&#xff0c;它提供了一种新的处理集合的方式&#xff0c;可以更加简洁、高效地进行数据操作。Stream流支持各种常见的操作&#xff0c;比如过滤、映射、排序、聚合等&#xff0c;同时也支持并行处理&#xf…

Vue 项目 尚品汇(二)(暂停进行)

一、Home 模块组件拆分 基本流程 先写静态页面 拆分静态组件 获取服务器的数据进行展示 动态业务 &#xff08;一&#xff09;三级联动组件 如果一个组件在很多模块之间都在使用&#xff0c;我们就拆分成成一个全局组件 只需注册一次 在全局的项目都能使用 三级联动在 …

Java:就业市场上的常青树-永远的宠儿

除了兴趣&#xff0c;我们学习编程最主要的目标是找一份好工作&#xff0c;选择合适的编程语言就非常重要了&#xff0c;毕竟选择大于努力&#xff0c;男怕选错行&#xff0c;学编程最怕选错语言。比如&#xff0c;如果你选Perl&#xff0c;那就糟糕了&#xff0c;基本上可以断…

高效备战!2024年陕西省绿色工厂申报条件好处和各地区奖补

什么是绿色工厂&#xff1f; 绿色工厂是制造业的生产单元&#xff0c;是绿色制造的实施主体&#xff0c;属于绿色制造体系的核心支撑单元&#xff0c;侧重于生产过程的绿色化。 通过采用绿色建筑技术建设、改造厂房&#xff0c;预留可再生能源应用场所和设计负荷&#xff0c;…

PyQt5中的事件与信号处理

文章目录 1. 简介1.1事件(Event)1.2 信号(Signal)与槽(Slot)1.3 自定义信号 2. 一个信号与槽的简单示例13. 一个信号与槽的简单示例24. 事件发送者5. 创建自定义信号6. 一个简单计算器 1. 简介 在PyQt5中&#xff0c;事件和信号处理是GUI编程的核心概念。事件是指用户操作或系…

吴恩达机器学习笔记:第 9 周-16推荐系统(Recommender Systems) 16.3-16.4

目录 第 9 周 16、 推荐系统(Recommender Systems)16.3 协同过滤16.4 协同过滤算法 第 9 周 16、 推荐系统(Recommender Systems) 16.3 协同过滤 在之前的基于内容的推荐系统中&#xff0c;对于每一部电影&#xff0c;我们都掌握了可用的特征&#xff0c;使用这些特征训练出了…

codeforce#937 (div4)题解

E. Nearly Shortest Repeating Substring 给出字符串s&#xff0c;是否存在长度为k的字符串多次拼接后得到的字符串与s最多有一位不同 由题意得&#xff0c;k一定是n的因数&#xff0c;所以暴力枚举就好&#xff0c;求出满足 s [ i ] s [ i m o d k ] s[i] s[i \mod k] s[…
最新文章