2024年Electron笔记_browserwindow 初始状态,HarmonyOS鸿蒙经典面试题

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

})
}

// 窗口加载和关闭
app.on(‘ready’, createWindow)
app.on(“window-all-closed”, () => {
console.log(“window-all-closed”)
app.quit()
})


## 窗口标题及环境(创建窗口)



> 
> 这里要说明一下,低版本直接可以使用一个remote,主进程稍微配置一下就能创建窗口了,高版本就不行了,高版本需要安装一个@electron/remote模块,通过对这个模块稍微配置一下也能创建窗口了,本人之前版本是`"electron": "^26.0.0","@electron/remote": "^2.0.11"`,[具体配置可以可以看看这个小哥的博客](https://bbs.csdn.net/topics/618636735),我下面的代码和这两个不一样我是在主进程创建窗口,渲染进程向主进程发请求才能创建窗体(下面代码示例就是这个方法),因为方式和另两种不一样,因此记录一下
> 
> 
> 


**ctrl+r 可以刷新当前窗口的index.html样式,ctrl+shift+i可以打开调试窗口**


**这里强调一下main.js为主进程,创建的js里面重新创建的窗口为渲染进程**


**主进程main.js代码如下**



const { app, BrowserWindow, ipcMain } = require(“electron”) // ipcMain用于渲染进程创建窗体使用
const createWindow = () => {
// 创建窗口
let win = new BrowserWindow({
x: 100,
y: 50, //窗体坐标
webPreferences: {
nodeIntegration: true,
contextIsolation: false, //加入这两行代码就可以正常使用require了,不会报错了
}
})
//当前窗口显示的页面
win.loadFile(“index.html”)
// 窗口关闭
win.on(‘close’, () => {
console.log(‘close’)
win = null
})
}
// 窗口加载和关闭
app.on(‘ready’, createWindow)
app.on(“window-all-closed”, () => {
console.log(“window-all-closed”)
app.quit()
})

// 下面代码就是创建渲染进程窗体代码
// 在主进程中监听渲染进程的请求
// open-window后面的回调函数,参数一默认是事件对象,参数二为渲染进程传递来的数据
// pageFileName为ipcRenderer.send()的第二个参数,ipcRenderer.send()由渲染进程发起,参数一为事件名,参数二为页面配置(大小,位置等等)
ipcMain.on(‘open-window’, (event, winconfig) => {
console.log(‘winconfig’, winconfig)
// 创建新窗口并设置相应的配置(配置由渲染进程提供)
let newWindow = new BrowserWindow(winconfig)
// 这里设置的是winconfig.pageFileName,所以渲染进程的请求的配置中必须pageFileName代表页面
newWindow.loadFile(winconfig.pageFileName)
// 监听创建的窗体关闭事件
newWindow.on(‘close’, () => {
console.log(‘close’)
newWindow = null
})
})


**主进程页面index.html代码**



萧寂

窗口标题

打开第一个新窗口 打开第二个新窗口

**渲染进程index.js代码**



// 这里强调一下main.js为主进程,窗口里面页面点击创建的js里面重新创建的窗口为渲染进程
// require直接使用会报错,因为electron是不被允许直接require的,不给这个权限,需要我们自行放开
// 权限需要在窗口的配置定义webPreferences对象,值为 {nodeIntegration: true,contextIsolation: false},这样就可以正常使用require了

// 创建窗口这里使用的是electron自带的ipcRenderer属性,它是向主进程发送创建窗体请求,参数一为事件名,参数二为窗体配置
const { ipcRenderer } = require(“electron”)
const path = require(“path”)
window.addEventListener(“DOMContentLoaded”, () => {
// 点击按钮打开新窗口
// 获取btn
const btn = document.getElementById(“btn”)
// 按钮点击打开新窗口
btn.addEventListener(“click”, () => {
// 创建新窗口(向主进程发起请求,创建窗体,并显示pageFileName指定的页面)
ipcRenderer.send(‘open-window’, {
width: 600,
height: 400,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
},
pageFileName: path.join(__dirname, “list.html”) // 确保传递了正确的页面文件名,list.html需要显示的页面
})
})

// 打开第二个窗口
// 获取btn
const btn2 = document.getElementById(“btn2”)
// 按钮点击打开新窗口
btn2.addEventListener(“click”, () => {
// 创建新窗口(向主进程发起请求,创建窗体,并显示pageFileName指定的页面)
ipcRenderer.send(‘open-window’, {
width: 200,
height: 200,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
},
pageFileName: path.join(__dirname, “list2.html”) // 确保传递了正确的页面文件名,list2.html需要显示的页面
})
})
})


**项目结构**


![在这里插入图片描述](https://img-blog.csdnimg.cn/e8f596561f5a439186dc0a7a9dcd48ed.png)


**效果图**


![在这里插入图片描述](https://img-blog.csdnimg.cn/5f5458d325ef401183fb72a73a892beb.png)


### 自定义窗口的实现(以及阻止窗口关闭)


**项目结构**


![在这里插入图片描述](https://img-blog.csdnimg.cn/88214c2574a2405b850a97dea70384b1.png)


**安装**



npm install --save @electron/remote


**main.js代码如下**



const { app, BrowserWindow } = require(“electron”)
const createWindow = () => {
// 创建窗口
let win = new BrowserWindow({
x: 100,
y: 50, //窗体坐标
frame: false, // 只保留主体部分,然后后面的样式全部都是由html去模拟
webPreferences: {
nodeIntegration: true,
contextIsolation: false, //加入这两行代码就可以正常使用require了,不会报错了
enableRemoteModule: true
}
})
require(‘@electron/remote/main’).initialize()
require(“@electron/remote/main”).enable(win.webContents)

//当前窗口显示的页面
win.loadFile(“index.html”)
// 窗口关闭
win.on(‘close’, () => {
console.log(‘close’)
win = null
})
}

// 窗口加载和关闭
app.on(‘ready’, createWindow)
app.on(“window-all-closed”, () => {
console.log(“window-all-closed”)
app.quit()
})


**index.html**



萧寂

主题内容

一 口 X

上面的三个模拟最小化,最大化和关闭

是否关闭当前应用

系统可能不会保存您的所有更改


**index.css**



main {
display: flex;
justify-content: space-evenly;
align-items: center;
}
.box {
color: red;
}
span {
padding: 10px 5px;
cursor: pointer;
}
/* 将提示语隐藏 */
.isShow {
display: none;
}
.s1 {
cursor: pointer;
}


**index.js**



const remote = require(“@electron/remote”)

window.addEventListener(‘DOMContentLoaded’, () => {
//利用remote获取当前窗口对象
let mainwin = remote.getCurrentWindow()

// 这里代码是当窗口关闭,去进行一下阻止,并弹出提示框,用户确定关闭再进行关闭
// 监听close事件,close事件触发会执行这个事件onbeforeunload
window.onbeforeunload = function () {
// 获取到弹框dom元素,并设置样式
document.querySelector(‘.isShow’).style.display = ‘block’
// 将主题内容隐藏
document.querySelector(‘h2’).style.display = ‘none’

// 获取弹窗的按钮(确认和取消)
let btn = document.querySelectorAll('.s1')

// 点击确认关闭按钮
btn[0].addEventListener('click', () => {
  // 这里不再使用close事件,不然会一直触发window.onbeforeunload事件,进入死循环了
  mainwin.destroy() //窗口销毁
})

// 点击取消按钮
btn[1].addEventListener('click', () => {
  // 将窗口隐藏就好了
  // 获取到弹框dom元素,并设置样式
  document.querySelector('.isShow').style.display = 'none'
  // 将主题内容显示
  document.querySelector('h2').style.display = 'block'
})
return false

}

const spans = document.querySelectorAll(‘span’)

// 最小化
spans[0].addEventListener(“click”, () => {
mainwin.minimize() //窗口最小化
})
// 放大
spans[1].addEventListener(“click”, () => {
// 最大化操作
console.log(‘mainwin.isMaximized()’, mainwin.isMaximized()) //false,返回布尔值,代表当前界面是否是最大化了
if (!mainwin.isMaximized()) {
mainwin.maximize() //如果没有最大化的话,给个最大化
} else {
mainwin.restore() //如果是最大化了,给它恢复到初始状态
}
})
// 关闭窗口
spans[2].addEventListener(“click”, () => {
mainwin.close() //关闭窗口
})
})


**效果图**


![在这里插入图片描述](https://img-blog.csdnimg.cn/a034ed1bd3f8413395ae1cf0cbb39ad5.png)


**当点击关闭按钮,会弹出提示框,点击是就关闭,点击否会将提示框进行隐藏**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/56ef210c19d146b28db888514c9bf727.png)


### 父子及模态窗口


**模态窗口定义**:定义完以后不能对主窗口或者别的窗口进行操作,除非模态窗口  
 **其余代码和上面一样,只修改了index.js代码,代码如下**



const remote = require(‘@electron/remote’)

window.addEventListener(‘DOMContentLoaded’, () => {
let btn = document.querySelector(‘#btn’)
btn.addEventListener(‘click’, () => {
let subWin = new remote.BrowserWindow({
width: 200,
height: 200,
parent: remote.getCurrentWindow(), //这个属性指向父级,实现了父子关联
modal: true, //定义模态窗口(默认为false,定义完以后不能对主窗口或者别的窗口进行操作,除非关闭模态窗口)
})
subWin.loadFile(‘sub.html’)
subWin.on(‘close’, () => {
subWin = null
})
})
})


## 自定义菜单


**main.js代码如下**



const { app, BrowserWindow, Menu } = require(“electron”) //Menu是菜单模块

console.log(process.platform)

const createWindow = () => {
// 创建窗口
let win = new BrowserWindow({
x: 100,
y: 50,
title: ‘自定义菜单’,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
}
})

// 1.这里定义菜单(定义自己需要的菜单项)
let menuTemp = [
{
label: ‘文件’,
submenu: [ //定义二级菜单
{
label: ‘打开文件’,
click () {
// 这里就可以使用每个选项的点击事件
console.log(‘当前需要的就是打开某一具体的文件’)
}
},
{
type: ‘separator’ // 添加分割线,就这一个属性将上下分隔开
},
{
label: ‘关闭文件夹’
},
{
label: ‘关于’,
role: ‘about’ //弹出关于项
}
]
},
{
label: ‘编辑’
}
]
// 2.利用上面菜单项生成一个菜单
let menu = Menu.buildFromTemplate(menuTemp)
// 3.将上述的自定义菜单添加到应用里面
Menu.setApplicationMenu(menu)

require(‘@electron/remote/main’).initialize()
require(“@electron/remote/main”).enable(win.webContents)
win.loadFile(“index.html”)
win.on(‘close’, () => {
console.log(‘close’)
win = null
})
}

// 窗口加载和关闭
app.on(‘ready’, createWindow)
app.on(“window-all-closed”, () => {
console.log(“window-all-closed”)
app.quit()
})


**这里打印有点中文乱码问题,解决方法就是在终端输入`chcp 65001`回车,重新执行即可解决中文乱码问题**


### 菜单角色及类型


**main.js代码**



const { app, BrowserWindow, Menu } = require(“electron”)
const createWindow = () => {
// 创建窗口
let win = new BrowserWindow({
x: 100,
y: 50, //窗体坐标
webPreferences: {
nodeIntegration: true,
contextIsolation: false, //加入这两行代码就可以正常使用require了,不会报错了
enableRemoteModule: true
}
})
require(‘@electron/remote/main’).initialize()
require(“@electron/remote/main”).enable(win.webContents)

// 1.自定义菜单项
let menutap = [
{
label: ‘角色’,
submenu: [
{ label: ‘复制’, role: ‘copy’ },
{ label: ‘剪切’, role: ‘cut’ },
{ label: ‘粘贴’, role: ‘paste’ },
{ label: ‘最小化’, role: ‘minimize’ },
]
},
{
label: ‘类型’,
submenu: [
{ label: ‘多选一’, type: ‘checkbox’ },
{ label: ‘多选二’, type: ‘checkbox’ },
{ label: ‘多选三’, type: ‘checkbox’ },
{ type: ‘separator’ },
{ label: ‘单选1’, type: ‘radio’ },
{ label: ‘单选2’, type: ‘radio’ },
{ label: ‘单选3’, type: ‘radio’ },
{ type: ‘separator’ },
{ label: ‘windows’, type: ‘submenu’, role: ‘windowMenu’ } //这里两个属性必须同时给出
]
},
{
label: ‘其他’,
submenu: [
{
label: ‘打开’,
icon: ‘’,
accelerator: ‘ctrl + o’, //定义快捷键
click () {
console.log(‘打开操作执行了’)
}
}
]
}
]
// 2.依据上述的数据创建一个menu
let menu = Menu.buildFromTemplate(menutap)
// 3.将上述菜单添加至app身上
Menu.setApplicationMenu(menu)

//当前窗口显示的页面
win.loadFile(“index.html”)
// 窗口关闭
win.on(‘close’, () => {
console.log(‘close’)
win = null
})
}

// 窗口加载和关闭
app.on(‘ready’, createWindow)
app.on(“window-all-closed”, () => {
console.log(“window-all-closed”)
app.quit()
})


![在这里插入图片描述](https://img-blog.csdnimg.cn/3751e1dd146847fabdc5e47f509ae866.png)


### 动态创建菜单


**index.html代码如下**



萧寂

动态创建菜单

创建自定义菜单
添加菜单项

**index.js代码如下**



const remote = require(‘@electron/remote’)
// 找到菜单和菜单项
const Menu = remote.Menu
const MenuItem = remote.MenuItem
window.addEventListener(‘DOMContentLoaded’, () => {
// 获取按钮
let btn = document.querySelectorAll(‘button’)
// 获取输入框
let input = document.querySelector(‘input’)

// 自定义全局变量存放菜单项
let menuItem = new Menu()
// 点击生成自定义菜单
btn[0].addEventListener(‘click’, () => {
// 创建菜单
let menuFile = new MenuItem({ label: ‘文件’, type: ‘normal’ })
let menuEdit = new MenuItem({ label: ‘编辑’, type: ‘normal’ })
let customMenu = new MenuItem({ label: ‘自定义菜单项’, submenu: menuItem })
// 将创建好的菜单添加到menu
let menu = new Menu()
menu.append(menuFile)
menu.append(menuEdit)
menu.append(customMenu)
// 将ment放置于app中显示
Menu.setApplicationMenu(menu)
})

// 点击动态添加菜单项
btn[1].addEventListener(‘click’, () => {
// 获取当前input输入框当中输入的内容
let con = input.value.trim()
if (con) {
menuItem.append(new MenuItem({ label: con, type: ‘normal’ }))
input.value = ‘’
}
})
})


**效果图**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/d123960a5e76401ba3fee23fe0ea1de5.png)  
 **点击自定义创建菜单会替换原来的菜单项,在输入框输入菜单名,点击添加菜单项会在菜单栏的自定义菜单里面追加自己添加的菜单项**


### 自定义右键菜单


**所有代码都是在index.js里面写的,index.html无代码只引用了index.js**  
 **index.js代码如下**



const remote = require(‘@electron/remote’)
const Menu = remote.Menu

// 01 创建一个自定义菜单的内容
let contextTemp = [
{ label: ‘RunCode’ },
{ label: ‘转到定义’ },
{ type: ‘separator’ },
{
label: ‘其他功能’,
click () {
console.log(“其他功能选项被点击了”) //这个打印不会在主进程显示,而是在桌面版使用ctrl+shifl+i去控制台看
}
}
]

// 02 依据上述内容来创建menu
let menu = Menu.buildFromTemplate(contextTemp)

window.addEventListener(‘DOMContentLoaded’, () => {
// 03 在鼠标右击行为发生后显示出来
window.addEventListener(‘contextmenu’, (e) => {
e.preventDefault() //阻止有些元素点击的默认行为
menu.popup({ window: remote.getCurrentWindow() }) //将当前窗口对象作为popup参数,代表在当前窗口弹出
}, false)
})


## 主进程和渲染进程进行通信


### 同步和异步进行通信


**index.html**



萧寂

渲染进程与主进程进行通信


渲染主异步操作
渲染主同步操作

**index.js**



const { ipcRenderer } = require(‘electron’)

window.onload = () => {
// 获取元素
let abtn = document.querySelectorAll(‘button’)

// 01 采用异步的API在渲染进程中给主进程发送消息
abtn[0].addEventListener(‘click’, () => {
ipcRenderer.send(‘msg1’, ‘dataMag’)
})

// 当前接收主进程的消息
ipcRenderer.on(‘msgRe’, (ev, data) => {
console.log(‘data’, data) //主进程回复的异步消息
})

// 02 采用同步的方式完成数据的通信
abtn[1].addEventListener(‘click’, () => {
let val = ipcRenderer.sendSync(‘msg2’, ‘SyncMsg’)
console.log(‘val’, val) // 主进程回复的同步消息
})
}


**主进程main.js**



const { app, BrowserWindow, ipcMain } = require(“electron”)
const createWindow = () => {
// 创建窗口
let win = new BrowserWindow({
x: 100,
y: 50, //窗体坐标
webPreferences: {
nodeIntegration: true,
contextIsolation: false, //加入这两行代码就可以正常使用require了,不会报错了
enableRemoteModule: true
}
})
require(‘@electron/remote/main’).initialize()
require(“@electron/remote/main”).enable(win.webContents)
//当前窗口显示的页面
win.loadFile(“index.html”)
// 窗口关闭
win.on(‘close’, () => {
console.log(‘close’)
win = null
})
}
// 窗口加载和关闭
app.on(‘ready’, createWindow)
app.on(“window-all-closed”, () => {
console.log(“window-all-closed”)
app.quit()
})

// 监听渲染进程发送的消息
ipcMain.on(‘msg1’, (e, data) => {
console.log(‘data’, data)

// 主进程给渲染进程发消息
e.sender.send(‘msgRe’, “主进程回复的异步消息”)
})

// 监听渲染进程发送的消息
ipcMain.on(‘msg2’, (e, data) => {
console.log(‘data’, data)

// // 主进程给渲染进程发消息
e.returnValue = ‘主进程回复的同步消息’
})


### 通过主进程主动发送消息控制渲染进程作出行为


**以下代码没有使用index.html,index.html只是引用了一下index.js**  
 **index.js**



const { ipcRenderer } = require(‘electron’)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

{
console.log(“window-all-closed”)
app.quit()
})

// 监听渲染进程发送的消息
ipcMain.on(‘msg1’, (e, data) => {
console.log(‘data’, data)

// 主进程给渲染进程发消息
e.sender.send(‘msgRe’, “主进程回复的异步消息”)
})

// 监听渲染进程发送的消息
ipcMain.on(‘msg2’, (e, data) => {
console.log(‘data’, data)

// // 主进程给渲染进程发消息
e.returnValue = ‘主进程回复的同步消息’
})


### 通过主进程主动发送消息控制渲染进程作出行为


**以下代码没有使用index.html,index.html只是引用了一下index.js**  
 **index.js**



const { ipcRenderer } = require(‘electron’)

[外链图片转存中…(img-LeJartWV-1715608408428)]
[外链图片转存中…(img-U24kBqoq-1715608408429)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值