如何通过electron js访问htmlDOM元素
How to access html DOM element through electron js
我正在用 electron js 制作一个文本编辑器,一旦用户按下 ctrl + s,我希望将文件保存为 txt 文件。问题是,我似乎无法找到直接访问包含文本的 div 的方法。我试过使用预加载,但只有在程序为 运行 时才有效。如何将元素保存为变量?
这是主要的 javascript 代码:
const { app, BrowserWindow, globalShortcut } = require('electron');
const path = require('path');
// Create the main window
const createWindow = () => {
// Adjust a few settings
const win = new BrowserWindow({
// What the height and width that you open up to
width: 500,
height: 600,
// Minimun width and height
minWidth: 400,
minHeight: 400,
icon: __dirname + '/icon.png',
// Change the window title
title: "text editor",
webPreferences: {
// Preload so that the javascript can access the text you write
preload: path.join(__dirname, 'preload.js'),
}
});
win.loadFile('index.html');
// Remove that ugly title bar and remove unnecessary keyboard shortcuts
win.removeMenu();
}
// Create window on ready so that no nasty errors happen
app.whenReady().then(() => {
createWindow();
});
app.whenReady().then(() => {
// Global shortcut so the user has the ablitiy to exit
globalShortcut.register('ctrl+e', () => {
console.log("exiting...");
app.exit();
});
globalShortcut.register('ctrl+s', () => {
console.log("saving...");
});
})
// when all windows close this app actually closes
app.on('window-all-closed', () => {
if (process !== 'darwin') app.quit();
})
要获取 index.html
window 中 div
元素的 innerText
(或等同物),您需要向渲染线程发送消息请求这条信息。在此之后,您将需要渲染线程将 innerText
发送回主线程进行处理(保存)。
Electron 的 Inter-Process Communication 有时会令人困惑,但如果正确实施,它会简单而安全。
要了解有关所涉及过程的更多信息,您需要阅读并尝试理解以下链接:
让我们首先构建您的 html 文档。它至少必须包含一个可编辑的 <div>
标签和一个 'save' 按钮。
index.html
(渲染线程)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Test Editor</title>
<style>
#editor {
width: 50vw;
height: 50vh;
}
<style>
</head>
<body>
<div id="content" contenteditable="true"></div>
<input type="button" id="save" value="Save">
</body>
<script src="script.js"></script>
</html>
See Example: A simple but complete rich text editor for some cool ideas.
现在让我们添加 'save' 按钮和 IPC 消息功能。
script.js
(渲染线程)
// IIFE (Immediately Invoked Function Expression)
(function() => {
let content = document.getElemetById('content').innerText;
document.getElementById('save').addEventListener('click', saveContent(content));
window.ipcRender.receive('editor:getContent', () => { saveContent(content); });
});
function saveContent(content) {
window.ipcRender.send('editor:saveContent', content);
}
这是您的 main.js
文件,其中包含以下更新。
- 添加 Electron 的
ipcMain
模块。
- 将
win
对象添加到顶级范围,这样它就不会被垃圾回收。
- 侦听来自呈现线程的消息(使用 IFFE)。
- 添加
saveContent()
功能(待您充实)。
- 从
new BrowserWindow
行删除 const
。
- Return
win
来自 createWindow()
函数,以便稍后参考。
- 更新 globalShortcut
ctrl+s
函数。
main.js
(主线程)
const { app, BrowserWindow, globalShortcut, ipcMain } = require('electron');
const path = require('path');
let win = null;
// IIFE (Immediately Invoked Function Expression)
(function() => {
ipcMain.on('editor:saveContent', (event, content) => { saveContent(content); });
})();
function saveContent(content) {
console.log("saving...");
// Save content...
console.log("saved...");
}
// Create the main window
function createWindow() {
// Adjust a few settings
win = new BrowserWindow({
// What the height and width that you open up to
width: 500,
height: 600,
// Minimun width and height
minWidth: 400,
minHeight: 400,
icon: __dirname + '/icon.png',
// Change the window title
title: "text editor",
webPreferences: {
// Preload so that the javascript can access the text you write
preload: path.join(__dirname, 'preload.js'),
}
});
win.loadFile('index.html');
// Remove that ugly title bar and remove unnecessary keyboard shortcuts
win.removeMenu();
return win;
}
// Create window on ready so that no nasty errors happen
app.on('ready', () => {
// Create the window.
win = createWindow();
// Global shortcut so the user has the ability to exit
globalShortcut.register('ctrl+e', () => {
console.log("exiting...");
app.exit();
});
// Global shortcut to save editable content.
globalShortcut.register('ctrl+s', () => {
console.log('ctrl+s pressed.');
win.webContents.send('editor:getContent');
});
})
// when all windows close this app actually closes
app.on('window-all-closed', () => {
if (process !== 'darwin') app.quit();
})
Note that I have left the actual saving to the filesystem functionality to you. See Node.js: fs.writeFile() for more information.
好的,拼图的最后一块是一个有效的 preload.js
脚本。这是授予在主线程和渲染线程之间使用白名单通道列表的脚本。
在这里我们添加 editor:saveContent
和 editor:getContent
频道名称。
preload.js
(主线程)
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'editor:saveContent'
],
// From main to render.
'receive': [
'editor:getContent'
],
// From render to main and back again.
'sendReceive': []
}
};
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Note that I do not perform any functions so-to-speak in the preload
script. I only manage a list
of channel names and the transfer of any data associated with those channel names.
我正在用 electron js 制作一个文本编辑器,一旦用户按下 ctrl + s,我希望将文件保存为 txt 文件。问题是,我似乎无法找到直接访问包含文本的 div 的方法。我试过使用预加载,但只有在程序为 运行 时才有效。如何将元素保存为变量?
这是主要的 javascript 代码:
const { app, BrowserWindow, globalShortcut } = require('electron');
const path = require('path');
// Create the main window
const createWindow = () => {
// Adjust a few settings
const win = new BrowserWindow({
// What the height and width that you open up to
width: 500,
height: 600,
// Minimun width and height
minWidth: 400,
minHeight: 400,
icon: __dirname + '/icon.png',
// Change the window title
title: "text editor",
webPreferences: {
// Preload so that the javascript can access the text you write
preload: path.join(__dirname, 'preload.js'),
}
});
win.loadFile('index.html');
// Remove that ugly title bar and remove unnecessary keyboard shortcuts
win.removeMenu();
}
// Create window on ready so that no nasty errors happen
app.whenReady().then(() => {
createWindow();
});
app.whenReady().then(() => {
// Global shortcut so the user has the ablitiy to exit
globalShortcut.register('ctrl+e', () => {
console.log("exiting...");
app.exit();
});
globalShortcut.register('ctrl+s', () => {
console.log("saving...");
});
})
// when all windows close this app actually closes
app.on('window-all-closed', () => {
if (process !== 'darwin') app.quit();
})
要获取 index.html
window 中 div
元素的 innerText
(或等同物),您需要向渲染线程发送消息请求这条信息。在此之后,您将需要渲染线程将 innerText
发送回主线程进行处理(保存)。
Electron 的 Inter-Process Communication 有时会令人困惑,但如果正确实施,它会简单而安全。
要了解有关所涉及过程的更多信息,您需要阅读并尝试理解以下链接:
让我们首先构建您的 html 文档。它至少必须包含一个可编辑的 <div>
标签和一个 'save' 按钮。
index.html
(渲染线程)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Test Editor</title>
<style>
#editor {
width: 50vw;
height: 50vh;
}
<style>
</head>
<body>
<div id="content" contenteditable="true"></div>
<input type="button" id="save" value="Save">
</body>
<script src="script.js"></script>
</html>
See Example: A simple but complete rich text editor for some cool ideas.
现在让我们添加 'save' 按钮和 IPC 消息功能。
script.js
(渲染线程)
// IIFE (Immediately Invoked Function Expression)
(function() => {
let content = document.getElemetById('content').innerText;
document.getElementById('save').addEventListener('click', saveContent(content));
window.ipcRender.receive('editor:getContent', () => { saveContent(content); });
});
function saveContent(content) {
window.ipcRender.send('editor:saveContent', content);
}
这是您的 main.js
文件,其中包含以下更新。
- 添加 Electron 的
ipcMain
模块。 - 将
win
对象添加到顶级范围,这样它就不会被垃圾回收。 - 侦听来自呈现线程的消息(使用 IFFE)。
- 添加
saveContent()
功能(待您充实)。 - 从
new BrowserWindow
行删除const
。 - Return
win
来自createWindow()
函数,以便稍后参考。 - 更新 globalShortcut
ctrl+s
函数。
main.js
(主线程)
const { app, BrowserWindow, globalShortcut, ipcMain } = require('electron');
const path = require('path');
let win = null;
// IIFE (Immediately Invoked Function Expression)
(function() => {
ipcMain.on('editor:saveContent', (event, content) => { saveContent(content); });
})();
function saveContent(content) {
console.log("saving...");
// Save content...
console.log("saved...");
}
// Create the main window
function createWindow() {
// Adjust a few settings
win = new BrowserWindow({
// What the height and width that you open up to
width: 500,
height: 600,
// Minimun width and height
minWidth: 400,
minHeight: 400,
icon: __dirname + '/icon.png',
// Change the window title
title: "text editor",
webPreferences: {
// Preload so that the javascript can access the text you write
preload: path.join(__dirname, 'preload.js'),
}
});
win.loadFile('index.html');
// Remove that ugly title bar and remove unnecessary keyboard shortcuts
win.removeMenu();
return win;
}
// Create window on ready so that no nasty errors happen
app.on('ready', () => {
// Create the window.
win = createWindow();
// Global shortcut so the user has the ability to exit
globalShortcut.register('ctrl+e', () => {
console.log("exiting...");
app.exit();
});
// Global shortcut to save editable content.
globalShortcut.register('ctrl+s', () => {
console.log('ctrl+s pressed.');
win.webContents.send('editor:getContent');
});
})
// when all windows close this app actually closes
app.on('window-all-closed', () => {
if (process !== 'darwin') app.quit();
})
Note that I have left the actual saving to the filesystem functionality to you. See Node.js: fs.writeFile() for more information.
好的,拼图的最后一块是一个有效的 preload.js
脚本。这是授予在主线程和渲染线程之间使用白名单通道列表的脚本。
在这里我们添加 editor:saveContent
和 editor:getContent
频道名称。
preload.js
(主线程)
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'editor:saveContent'
],
// From main to render.
'receive': [
'editor:getContent'
],
// From render to main and back again.
'sendReceive': []
}
};
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Note that I do not perform any functions so-to-speak in the
preload
script. I only manage a list of channel names and the transfer of any data associated with those channel names.