Electron中如何创建模态窗口?

news2024/11/28 22:55:59

目录

  • 前言
  • 一、模态窗口
    • 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/550610.html

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

相关文章

【TES714】JFM7K325T(复旦微FPGA)+HI3531DV200(华为海思)的综合视频处理平台设计原理图及调试经验

板卡概述 TES714是自主研制的一款5路HD-SDI视频采集图像处理平台,该平台采用上海复旦微的高性能Kintex系列FPGA加上华为海思的高性能视频处理器HI3531DV200来实现。 华为海思的HI3531DV200是一款集成了ARM A53四核处理器性能强大的神经网络引擎,支持多种…

【运维知识进阶篇】集群架构-Nginx动静分离详解

我们先前将静态资源放到NFS,动态资源放到MySQL,一是为了提高我们Web服务器性能,减轻它的压力,另一面如果Web宕机了,我们的静态和动态资源还可以访问到。但是之前方式不管是静态还是动态文件,都是走的代码文…

ssl vpn 与 ipsec vpn 区别

VPN 安全协议有两种主要类型,IPsec 和 SSL,了解它们之间的区别对于确保客户的安全至关重要。在本文中,我们将解释IPsec 和 SSL VPN 协议之间的区别,以及如何选择合适的协议来满足客户的需求。了解更多SSL技术最新信息,…

Linux_证书_Openssl实现对称加密、非对称加密、CA颁布证书

文章目录 OpenSSLopenssl实现对称加密openssl实现非对称加密生成密钥对非对称加密数字签名小结 根据CA颁布证书生成ca私钥和ca证书根据ca生成证书 尾声 OpenSSL 常用证书生成工具包括三个:ssh-keygen、cfssl、openssl。这里介绍 OpenSSL , OpenSSL 是一个开源项目&…

【Python从入门到进阶】20、HTML页面结构的介绍

接上篇《19、Python异常处理》 上一篇我们学习了Python中有关异常(捕获异常、处理异常等)的知识。从本篇开始,我们进入Python的实战教程,学习爬虫的相关技术,本篇主要讲解要爬取的HTML页面的结构。 一、一个场景 假设…

Godot引擎 4.0 文档 - 入门介绍 - Godot 编辑器

本文为Google Translate英译中结果,DrGraph在此基础上加了一些校正。英文原版页面: First look at Godots editor — Godot Engine (stable) documentation in English Godot的编辑器 本页将为您简要介绍 Godot 的界面。我们将查看不同的主屏幕和停靠栏…

C语言:字符函数和字符串函数详解及部分函数的模拟实现(前篇)

文章目录 求字符串长度strlenstrlen函数的模拟实现: 长度不受限制的字符串函数strcpystrcatstrcmp总结 长度受限制的字符串函数介绍strncpystrncatstrncmp 前言: C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串…

【LeetCode】382. 链表随机节点

382. 链表随机节点(中等) 方法一 思路 定义两个链表,一个origin,用于每次调用 getRandom() 时进行初始化,一个 l 用于每次调用 getRandom() 时进行遍历,找到随机选定的元素。首先在 Solution() 的时候&am…

SpringBoot原理——起步依赖与自动装配

文章目录 SpringBoot原理一、起步依赖二、自动配置2.1 概述2.2 工具类准备工作2.2.2 HeaderConfig2.2.3 HeaderGenerator2.2.4 HeaderParser2.2.5 MyImportSelector2.2.6 TokenParser2.2.7 pom.xml文件 2.3 自动配置原理2.3.1 引入工具类2.3.2 案例 : 访问第三方Bea…

GPT专业应用:撰写工作简报

●图片由Lexica 生成,输入:Workers working overtime 工作简报,作为一种了解情况、沟通信息的有效手段,能使上级机关和领导及时了解、掌握所属部门的政治学习、军事训练、行政管理等方面的最新情况;同时,能…

BERT输入以及权重矩阵形状解析

以下用形状来描述矩阵。对于向量,为了方便理解,也写成了类似(1,64)这种形状的表示形式,这个你理解为64维的向量即可。下面讲的矩阵相乘都是默认的叉乘。 词嵌入矩阵形状:以BERT_BASE为例,我们知道其有12层Encoder&…

记录--Vue中如何导出excel表格

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 一、导出静态数据 1、安装 vue-json-excel npm i vue-json-excel注意,此插件对node有版本要求,安装失败检查一下报错是否由于node版本造成! 2、引入并注册组件(以全…

【CSS语法应用在Qt中的QSS和文本】第一天

CSS语法应用在Qt中的QSS和文本 【1】CSS语法【1】QSS使用以上CSS语法【1.1】QTextBrowser设置样式表【1.2】QTextBrowser使用CSS语法设置文本样式 【1】CSS语法 💛💛💛💛💛💛💛💛&am…

Redis的五大类型

一、String数据类型 概述:String是redis最基本的类型,最大能存储512MB的数据,String类型是二进制安全的,即可以存储任何数据、比如数字、图片、序列化对象等 1. SET/GET/APPEND/STRLEN: append命令:append key valu…

【mysql】explain执行计划之id列

目录 一、说明二、示例2.1 id相同,执行顺序从上到下2.2 id不相同,id值越大越先执行2.3 既有id相同也有id不同的情况,先执行序号大的,再同级从上往下执行2.4 id列显示为null的最后执行。表示结果集,不需要使用它来进行查…

记录一次windows mysql5.7安装失败的过程

首先下载mysql安装包 windows版本 https://dev.mysql.com/downloads/installer/ 接着 在执行安装mysql msi安装包最后一步的时候,显示 Failed to start service MySQL57. 只有在任务处于完成状态(RanToCompletion、Fau 这时候 检查要么windows下面mysql的卸载残留没…

AUTOSAR-文档命名说明

文章目录 AUTOSAR_TR_PredefinedNamesAutosar验收测试基本说明 AUTOSAR_TR_PredefinedNames AUTOSAR_TR_PredefinedNames(Predefined Names in AUTOSAR).pdf对基础软件标准规范文档的分类信息做出了介绍,其中常用的文档包括EXP、PRS、RS、SR…

【C++】类和对象(中)---取地址及const取地址操作符重载、const成员函数的使用

个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C之路】💌 本专栏旨在记录C的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长&…

缓存穿透的解决办法有哪些?

一、概述 缓存穿透是指查询一个不存在的数据,由于缓存和数据库都没有命中,导致每次请求都需要从数据库中读取数据,增加了数据库的负担。解决缓存穿透的方法有以下几种: 布隆过滤器(Bloom Filter):使用位数组来表示一个集合&#…

iptables防火墙概念

iptables防火墙 一、iptables概述1.netfilter 与 iptables 的关系1)netfilter2)iptables 2.四表五链1)四表2)五链3)表的匹配优先级4)规则链之间的匹配顺序5)规则链内的匹配顺序 二、iptables防火…