Electron 如何创建模态窗口?

news2024/12/23 18:10:32

目录

  • 前言
  • 一、模态窗口
    • 1.Web页面模态框
    • 2.Electron中的模态窗口
    • 3.区分父子窗口与模态窗口
  • 二、实际案例使用
  • 总结


前言

模态框是一种常用的交互元素,无论是在 Web 网站、桌面应用还是移动 APP 中,都有其应用场景。模态框指的是一种弹出窗口,它显示在原有主界面的上方,通常使用于展示一些重要的信息或提供一些交互能力,增强用户体验。
那么在 Electron 中如何实现模态框呢?在 Electron 中是叫模态窗口,在 BrowserWindow 模块中。


一、模态窗口

1.Web页面模态框

模态框指的是一种弹出窗口,它显示在原有主界面的上方,通常使用于展示一些重要的信息或提供一些交互能力。

模态框的外部区域会被半透明遮罩覆盖,用户必须优先完成模态框的操作或关闭模态框,才可以返回到主界面进行其他操作。这种机制可以有效地防止用户在没有进行必要操作的情况下误操作或忽视重要信息,从而提升用户体验和效率。

模态框通常包含一个标题栏、一个内容区域以及一组操作按钮。标题栏用于显示模态框的名称或信息,内容区域用于展示相关信息或操作选项,操作按钮则用于响应用户的操作或关闭模态框等。

其实很多前端UI框架都提供了模块框,比如 Bootstrap 中的模态框:
Bootstrap模态框
是不是突然觉得很常见呀,原来就是它呀。

2.Electron中的模态窗口

我们先来看实际效果,以下是使用官方入门案例的主界面:
官方入门案例主界面
之后我们来看模态窗口效果,如下动图:
模态窗口
如何实现呢?其实官网说的很清楚。

首先在 Main Process 模块中,找到 BrowserWindow,它在主进程中负责创建和控制浏览器窗口。

我们在官方文档可以找到父子窗口和模态窗口API,如下:

父子窗口
通过使用 parent 选项,你可以创建子窗口。

官方示例代码如下:

const { BrowserWindow } = require('electron')

const top = new BrowserWindow() // 创建一个普通窗口
const child = new BrowserWindow({ parent: top })// 创建一个子窗口,并将top窗口设置为child窗口的父窗口
child.show() // 显示子窗口
top.show() // 显示父窗口

相信代码中的注释已经很明了了,这里最重要的是在创建窗口时配置是parent 选项,用于指定父窗口。要注意,child 窗口将总是显示在 top 窗口的顶部。

模态窗口
模态窗口是禁用父窗口的子窗口,创建模态窗口必须设置 parentmodal 选项。

const { BrowserWindow } = require('electron')

 // 创建child窗口,并将top窗口设置为父窗口。通过modal选项将该子窗口设置为模态窗口,预先将窗口隐藏起来
const child = new BrowserWindow({ parent: top, modal: true, show: false })
// 子窗口加载github网页
child.loadURL('https://github.com')
// 当子窗口渲染完毕后再显示
child.once('ready-to-show', () => {
  child.show()
})

其实就是在创建父子窗口的基础上,设置 modal 选项。将父子窗口变为模态窗口,并通过 show:false 提前将其隐藏起来,再通过一些事件等触发显示。

该窗口也是一个普通浏览器窗口,new BrowserWindow() 时的一些属性、方法等皆可以设置、调用。

现在贴出上面模态窗口的完整示例代码:

const { app, BrowserWindow } = require('electron')

const createWindow = () => {
    const win = new BrowserWindow({
      width: 800,
      height: 600
    })
    win.loadFile('index.html')
    // 这里将创建的win窗口进行返回
    return win;
}

app.whenReady().then(() => {
    const win = createWindow()// 这里要拿到父窗口
    const child = new BrowserWindow({ width: 600, height: 400, parent: win, modal: true, show: false })
        child.loadURL('https://github.com')
        child.once('ready-to-show', () => {
            child.show()
        })
})

该示例代码直接放在官网入门示例中 main.js 中运行即可,运行后会直接在窗口中显示模态窗口。

3.区分父子窗口与模态窗口

Electron 中,父子窗口和模态窗口是两种不同的窗口类型,它们具有不同的特点和用途。

  • 父子窗口:在一个父窗口中打开一个子窗口,子窗口具有和父窗口相同的特性,可以共享父窗口的一些信息和资源。父子窗口之间可以相互通信和交互,父窗口还可以控制子窗口的动态行为,比如打开、关闭等。
  • 模态窗口:指打开一个额外的窗口来进行一些必要的交互,但你不能在模态窗口外面进行任何操作。模态窗口打开后,你必须要完成其中需要的操作才能关闭它,否则无法操作其他窗口。模态窗口通常用于进行重要的提示、询问或操作确认等场景,以确保用户了解并明确自己的操作,避免一些不必要的错误发生。

需要注意的是,虽然父子窗口和模态窗口都可以用于打开新的窗口,并在其中进行一些操作,但它们有着不同的交互模式和使用场景。在使用时需要根据实际需求选择合适的窗口类型。

二、实际案例使用

我们先来看效果:
在这里插入图片描述
这里直接使用了 @中二少年学编程 导师的 electron+vue3 项目结构和基础代码,应用主窗口创建封装在 windows.js 中,部分代码如下:

const windowStateKeeper = require('electron-window-state');

const { BrowserWindow, app, Menu, Tray} = require('electron');
const path = require('path');
const {join} = require('path');

process.env.DIST = join(__dirname, '../../')
const indexHtml = join(process.env.DIST, 'dist/index.html')

/**
 * 创建窗口类
 */
class Window {

    win = null;

    getWindowState() {
        // 配置 electron-window-state 插件,获取窗口 option
        let win;
        const mainWindowState = windowStateKeeper({
            defaultWidth: 1000,
            defaultHeight: 800
        });
        let{width,height}=mainWindowState
        const options = {
            width,
            height,
            devTools: true,
            show: false,
            icon: path.resolve(__dirname, '../log.ico'),
            webPreferences: {
                // nodeIntegration:true,  //集成node api
                // contextIsolation:false  //关闭上下文隔离,配合nodeIntegration,可以赋予在render进程中写node代码的能力
                preload: path.resolve(__dirname, '../preload/preload.js')  //预加载的js文件
            }
        }

        win = new BrowserWindow(options)
        mainWindowState.manage(win);
        return win
    }

    // 创建窗口
    createWindow () {
        this.win = this.getWindowState()

        // 应用被打包了,返回true
        if(app.isPackaged){
            this.win.loadFile(indexHtml)
        }else{
            this.win.loadURL('http://localhost:5173')
        }

        // 等待dom渲染后打开窗口
        this.win.on('ready-to-show', () => {
            this.win.show()
        })
        this.win.on('closed', () => {
            this.win = null;
        })

        // webContents是一个EventEmitter. 负责渲染和控制网页, 是 BrowserWindow 对象的一个属性。(主进程)
        let contents = this.win.webContents;
        contents.openDevTools()

        this.win.loadURL('http://localhost:5173/')
        // this.win.loadFile('../../dist/index.html')

        return this.win
    }
}

module.exports = Window

我们可以看到在 Window 类中的 createWindow() 方法可以创建窗口,并返回该窗口实例。

我们在入口 main.js 中执行,完成窗口创建工作,部分代码如下:

const { app, BrowserWindow, ipcMain, dialog, globalShortcut } = require('electron')
const getWindow = require('./windows')

// 当Electron初始化完成
app.whenReady().then(() => {
    let win = null
    win = new getWindow().createWindow() // 创建窗口
});

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) win.createWindow()
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit()
});

在这段代码中,主进程(main.js)在应用启动时会创建一个浏览器窗口。但是对于需要显示模态窗口的场景,我们需要将该场景的实现放到业务代码中。在渲染器进程与主进程之间的通信过程中,渲染器进程负责渲染页面和执行预加载的js文件,而主进程负责实现模态窗口的功能。

我们可以直接在业务代码中调用创建模态窗口的函数,但是需要注意的是,创建窗口的代码可能会被封装在 windows.js 等独立的模块中,在这种情况下,如何获取到父窗口是一个需要考虑的问题。我们再次调用创建窗口代码吗?不!

win = new getWindow().createWindow() // 创建窗口

如何解决这个问题呢?BrowserWindow 类中提供了一个名为getFocusedWindow() 的方法,该方法可用于获取当前应用程序中获得焦点的窗口。如果当前存在焦点窗口,则该方法将返回一个 BrowserWindow 对象,否则将返回 null

使用getFocusedWindow()方法,我们可以方便地获取父窗口对象,所以在业务js中的实现代码是这样的:

const { ipcMain, BrowserWindow, dialog } = require('electron')
const path = require('path');

ipcMain.handle('go-add-url', (event, msg) => {
    // 获取焦点窗口
    const top = BrowserWindow.getFocusedWindow()
    // 创建模态窗口
    const child = new BrowserWindow({
        parent: top,
        modal: true,
        autoHideMenuBar: true,
        show: false,
        webPreferences: {
            preload: path.resolve(__dirname, '../../preload/preload.js')  //预加载的js文件
        }
    })
    // 模态窗口加载页面
    child.loadURL('http://localhost:5173#addUrl')
    child.once('ready-to-show', () => {
        child.show()
    })

})

总结

Electron 主进程中可以通过实例化 BrowserWindow 类来创建浏览器窗口。可以向构造函数中传入一些选项,如窗口大小、位置、URL等。如果传入 parent 选项,便可以将该窗口设置为子窗口,子窗口可以访问父窗口的一些属性和方法。在此基础上,还可以设置 modal 选项来创建模态窗口,模态窗口会锁定父窗口,防止用户在未完成当前窗口操作前操作其他窗口。

在某些情况下,我们需要使用主窗口对象作为参数传递给其他方法或模块中,可以使用 BrowserWindow.getFocusedWindow() 方法来获取当前焦点窗口的对象。这个方法非常有用,可以使我们很方便地获取到主窗口对象,进行各种操作。

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

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

相关文章

leetcode 1383. Maximum Performance of a Team(团队的最大performance)

n个工程师,长度为n的speed数组和efficiency数组。 每次最多选k个工程师,取出k个对应的speed和efficiency数字。 performancesum(k个speed) ✖ min(k个efficiency) 可以理解为k个人一起干,效率按最慢的人算(一个环节干不完其他人都…

Linux——IO之系统接口+文件描述符详解

IO 文件再次理解系统接口文件操作理解文件描述符 fd 文件再次理解 文件 文件内容 文件属性 其中文件属性也是数据–>即便你创建一个空文件,其也是要占据磁盘攻坚的。 文件操作 文件内容的操作 文件属性的操作 有可能在操作文件的过程中即改变文件的内容&…

Linux---echo命令、反引号`、tail命令、重定向符

1. echo命令 可以使用echo命令在命令行内输出指定内容 语法:echo 输出的内容 无需选项,只有一个参数,表示要输出的内容,复杂内容可以用 ”” 包围 带有空格或 \ 等特殊符号,建议使用双引号包围。 如果不使用双引号…

华为OD机试真题 Java 实现【统计匹配的二元组个数】【2023Q2 200分】

一、题目描述 给定两个数组A和B,若数组A的某个元素A[i]与数组B中的某个元素B[j]满足 A[i] B[j],则寻找到一个值匹配的二元组(i, j)。 请统计在这两个数组A和B中,一共存在多少个这样的二元组。 二、输入描述 第一行输入数组A的长度M&…

复习之[ 查询帮助 ] 和 [ 输入输出管理 ]

1.查询命令用途--whatis # whatis 命令 : 查询命令的用法 -如果结果出现nothing , 有两种情况: (1)查询数据库没有更新,此时输入命令 mandb更新数据库即可。 (2)查询的命令不存在。 2.获得命令的简要帮…

想学渗透,如何入门?

首先 渗透是计算机技术应用的一种,脱离不了基础,您需要学会一门编程语言,任何与计算机相关的都是从学习编程语言开始的,让你对计算机有个初步的认识,将您认识的数字转化为用0和1表示的编码。这个阶段推荐学习Python&a…

​LeetCode解法汇总LCP 33. 蓄水

目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给定 N 个无限容量且初始均空的水缸,每个水缸配有一个水桶用来打水&…

华芯微特SWM34-IO速度优化

对比测试了一下IO翻转速度在各种函数调用的情况下的差异 CPU运行速度150Mhz,SDRAM开 直接调用翻转函数 while(1) {GPIO_InvBit(GPIOA, PIN0); }速度大约5Mhz,主要是因为函数调用开销和函数内部的移位和异或操作,增加了指令的运行数量。 vo…

这是JWT 简单使用

JWT 是 Json Web Token的缩写 JSON Web Tokens - jwt.ioJSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Sig…

6-索引

目录 1.什么是索引? PS:数据库引擎简介(InnoDB VS MyISAM) 2.为什么需要索引? PS:存储数据模组 PS:查询数据存储的目录: 3.索引的作用 PS:索引 VS 书的目录 4.索…

PostgreSQL 源码部署

文章目录 说明1. 准备工作1.1 源码包下载1.2 解压安装目录1.3 安装依赖包1.4 添加用户1.5 创建数据目录 2. 编译安装2.1 源码编译2.2 配置环境变量2.3 初始化数据库2.4 启动数据库2.5 连接数据库 3. 参数调整3.1 配置 pg_hba3.2 监听相关2.4 日志文件2.5 内存参数 说明 本篇文…

db2常用命令/db2常见报错

文章目录 一、前言二、db2服务端常用命令2.1 启动/停止数据库2.2 连接数据库2.3 查看schema下所有表名2.4 查看表结构2.5 删除表数据2.6 导入导出del/ixf文件2.6.1 del与ixf区别 三、db2客户端常用命令3.1 查看schema下所有表及每个表的记录数3.2 修改表字段,对表字…

WPF中集合ObservableCollection<T>的使用

C#集合类ObservableCollection<T> 类似于泛型列表类List<T>&#xff0c;表示一个动态数据收集&#xff0c;该集合在添加或删除项或刷新整个列表时提供通知。 所在命名空间&#xff1a;System.Collections.ObjectModel 继承关系&#xff1a; public class Obser…

APP软件开发详细流程如何?

在互联网技术发达的今天&#xff0c;APP已经深入到我们生活的方方面面了&#xff0c;从购物、家政、洗车、教育到美容、旅游、餐饮等等&#xff0c;都可以通过各种各样的APP软件来实现&#xff0c;使我们的生活更加便捷化、智能化。不过&#xff0c;很多感兴趣的朋友对于APP软件…

亚马逊云科技宣布全面推出Amazon Aurora I/O-Optimized集群配置

自亚马逊云科技Amazon Aurora于2014年推出以来&#xff0c;成千上万的客户选择Aurora来运行其要求最严苛的应用程序。Aurora在全球范围内提供无与伦比的高性能和可用性&#xff0c;完全兼容MySQL和PostgreSQL&#xff0c;成本仅为商用数据库的十分之一。 许多亚马逊云科技客户受…

电竞小程序系统开发功能有哪些?

电竞小程序系统开发功能有哪些&#xff1f; 1、电竞资讯。对于电竞爱好者来说&#xff0c;每一场电竞比赛的相关信息都是不容错过的&#xff0c;因此用户可以通过小程序直接了解近期电竞相关资讯&#xff0c;例如&#xff1a;赛程安排、直播平台、参赛团队、比赛规则等&…

【CocosCreator问题总结】MotionStreak效果显示异常

&#x1f4e2;博客主页&#xff1a;肩匣与橘&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由肩匣与橘编写&#xff0c;首发于CSDN&#x1f649;&#x1f4e2;生活依旧是美好而又温柔的&#xff0c;你也是✨ …

公司新招了一个00后软件测试工程师,上来一顿操作给我看呆了...

前段时间公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司干了三年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍!给…

基于微信小程序的医院挂号预约系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

react学习2

props基本用法&#xff0c;把属性自动保存到props里 简写&#xff1a;三点展开&#xff0c;展开运算符无法展开对象&#xff0c;但是三点外侧包裹花括号可以复制对象{...P} 对props的属性进行限制 首先需要引入prop-types.js包 之后再去进行限制 props是只读的&#xff0c;只…