英文:
How to load external website into Electron and manipulate/persist its CSS correctly?
问题
我的目标摘要
我想将第三方网站加载到 Electron 中并操作其 CSS。我希望我所做的 CSS 更改能够持续存在。我想将代码打包成一个应用程序,当用户运行应用程序时,CSS 更改将保持不变。我想嵌入的网站使用 Google 进行身份验证。
- 第一种方法
我尝试的第一种方法是通过 Google Chrome 的“Overrides”功能在浏览器中更改 CSS。这并不起作用,因为当用户在其计算机上打开应用程序时,更改不会保持不变。
第二种方法在我发布的这个问题中有记录:
https://stackoverflow.com/questions/75045482/in-electron-forge-when-nodeintegrationinworker-true-embedding-gmail-shows-a
- 第二种方法
注意 - 在下面的代码中,我以 gmail.com 作为示例网站进行了演示。它产生了相同的问题。
index.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
const createWindow = () => {
// 创建浏览器窗口。
const mainWindow = new BrowserWindow({
// width: 1000,
// height: 800,
// resizable: false,
// frame:false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegrationInWorker: true,
contextIsolation: true
},
});
mainWindow.loadURL("https://gmail.com");
mainWindow.webContents.openDevTools();
};
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
preload.js
function changeCSSonLoad(){
let ele1 = document.querySelector('123-some large class list > div > div.flex.h-full.flex-1.flex-col.md\\:pl-\\)');
let ele2 = document.querySelector('456-some large class list > div > div.flex.h-full.flex-1.flex-col.md\\:pl-\\)');
let ele3 = document.querySelector('789-some large class list > div > div.flex.h-full.flex-1.flex-col.md\\:pl-\\)');
ele2.style.display = "none";
ele3.style.display = "none";
ele4.style.display = "none";
console.log("IT WERRRRKS")
}
setTimeout(function(){ changeCSSonLoad(); }, 1000);
上面的代码在用户登录后运行良好。如果用户未登录,并且他们通过 Google 提示登录,屏幕会变成空白白色(连接被切断)。
这与此 Github 帖子中发生的情况完全相同:
https://github.com/electron/electron/issues/8950
前面链接中的解决方案是从我的代码中删除 nodeIntegrationInWorker: true
。如果我这样做,CSS 更改将不再起作用。
我在线上阅读了关于 preload.js 的文章,看起来我可能没有正确使用它。这篇帖子讨论了正确使用 preload.js 的方式:
https://stackoverflow.com/questions/57807459/how-to-use-preload-js-properly-in-electron#:~:text=The%20proper%20way%20to%20use,here%20for%20more%20explanation%20why)。
总之,
- 我想将第三方网站加载到 Electron 中并操作其 CSS。我想要加载的网站使用 Google 进行身份验证。我已经创建了一个在用户被提示进行身份验证时不起作用的版本。
- 我不确定是否正确使用 preload.js,因此也不确定在 Electron 中解决这个问题的整个方式是否正确。
英文:
Summary of my Goal
I want to load a third party website into Electron and manipulate its CSS. I want the CSS changes I made to persist. I want to bundle the code as an app and the CSS changes to persist when the user runs the app. The website I want to embed uses google for authentication.
- The First Approach
The first approach I tried was to change the CSS in the browser via the Google Chrome "Overrides" feature. This did not work as the changes do not persist to users when they open the app on their machines.
The second approach is documented in this question I posted:
https://stackoverflow.com/questions/75045482/in-electron-forge-when-nodeintegrationinworker-true-embedding-gmail-shows-a
- The Second Approach
Note - In my code below I've used gmail.com as the example website to load. It creates the same problem.
index.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
// width: 1000,
// height: 800,
// resizable: false,
// frame:false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegrationInWorker: true,
contextIsolation: true
},
});
;
mainWindow.loadURL("https://gmail.com")
mainWindow.webContents.openDevTools();
};
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
preload.js
function changeCSSonLoad(){
let ele1 = document.querySelector('123-some large class list > div > div.flex.h-full.flex-1.flex-col.md\\:pl-\\)');
let ele2 = document.querySelector('456-some large class list > div > div.flex.h-full.flex-1.flex-col.md\\:pl-\\)');
let ele3 = document.querySelector('789-some large class list > div > div.flex.h-full.flex-1.flex-col.md\\:pl-\\)');
ele2.style.display = "none";
ele3.style.display = "none";
ele4.style.display = "none";
console.log("IT WERRRRKS")
}
setTimeout(function(){ changeCSSonLoad(); }, 1000);
The code above works fine after the user is logged in. If the user is not logged in and they are prompted to do so via Google, the screen turns blank white (the connection is severed).
It is exactly what happens in this Github post:
https://github.com/electron/electron/issues/8950
The solution in the previous link is to remove nodeIntegrationInWorker: true
from my code. If I do that the CSS changes no longer work.
I've been online reading about preload.js and from the looks of it I am not using it correctly. This post talks about the "Proper" way to use preload.js
In summary,
- I want to load a third party website into Electron and manipulate its CSS. The website I want to load uses Google for authentication. I have created a version that works except when users are prompted to authenticate.
- I am not sure if I am using preload.js the right way and by proxy I am not sure if I am going about solving this entire problem the right way in Electron.
答案1
得分: 1
以下是已翻译的部分:
有几种方法可以将外部网站加载到Electron应用程序中并操作其CSS。一种方法是使用webview标签,它允许您将网页嵌入到Electron应用程序中。您可以使用src属性指定要加载的外部网站的URL,然后使用JavaScript来操作webview的DOM和样式。
另一种方法是使用BrowserWindow模块创建一个新窗口,并将外部网站加载到其中。您可以使用BrowserWindow的webContents属性在页面上执行JavaScript并更改其CSS。
要持久保存对网页CSS的更改,您可以使用localStorage或indexedDB将更改保存在浏览器中。
以下是如何将外部网站加载到Electron应用程序中、操作其CSS并保存更改的示例代码:
// 在主进程中
const { BrowserWindow } = require('electron')
// 创建一个新窗口
let win = new BrowserWindow({ width: 800, height: 600 })
// 加载外部网站
win.loadURL('https://example.com')
// 获取窗口的Web内容
let contents = win.webContents
// 注入一些CSS到页面中
contents.insertCSS(`
body {
background-color: red;
}
`)
// 将CSS更改保存到localStorage
contents.executeJavaScript(`
localStorage.setItem('css', 'body {background-color: red;}');
`)
在渲染进程中,您可以从localStorage中检索CSS并将其重新插入到webview中:
// 在渲染进程中
let css = localStorage.getItem('css')
// 注入保存的CSS
let webview = document.getElementById('webview')
webview.addEventListener('dom-ready', () => {
webview.insertCSS(css)
})
请注意,上述示例只是实现此目标的一种方法,可能需要进行一些调整以适应您的要求。此外,如果要在Electron应用程序内加载外部网站,您可能需要处理一些安全问题,如跨站脚本(XSS)和跨站请求伪造(CSRF)。
英文:
There are a few ways to load an external website into an Electron app and manipulate its CSS. One way is to use the webview tag, which allows you to embed a web page within your Electron app. You can use the src attribute to specify the URL of the external website you want to load, and then use JavaScript to manipulate the webview's DOM and styles.
Another way is to use the BrowserWindow module to create a new window and load the external website into it. You can use the webContents property of the BrowserWindow to execute JavaScript on the page and change its CSS.
To persist the changes you made to the web page's CSS, you can either use the localStorage or indexedDB to save the changes in the browser.
Here is an example of how to load an external website into an Electron app, manipulate its CSS and persist the changes:
// In the main process
const { BrowserWindow } = require('electron')
// Create a new window
let win = new BrowserWindow({ width: 800, height: 600 })
// Load the external website
win.loadURL('https://example.com')
// Get the web contents of the window
let contents = win.webContents
// Inject some CSS into the page
contents.insertCSS(`
body {
background-color: red;
}
`)
// Save the CSS changes to localstorage
contents.executeJavaScript(`
localStorage.setItem('css', 'body {background-color: red;}');
`)
In the render process you can retrieve the css from localStorage and insert it into the webview again
// In the renderer process
let css = localStorage.getItem('css')
// Inject the saved CSS
let webview = document.getElementById('webview')
webview.addEventListener('dom-ready', () => {
webview.insertCSS(css)
})
Please note that the above example is just one way to achieve this and it might need some adjustments to fit your requirements. Additionally, you might need to take care of some security issues like cross-site scripting (XSS) and cross-site request forgery (CSRF) if you want to load external website inside your electron app.
答案2
得分: 0
希望这有所帮助,但我进行了一些实验并进行了以下操作...
请注意以下代码位于自调用的异步函数中
使用 node-fetch 获取 Gmail 的 HTML。
const html = await fetch('https://gmail.com').then(resp => resp.text())
使用 JSDOM 在内存中创建虚拟 DOM。
const dom = new JSDOM(html);
const document = dom.window.document;
可以按照需要扩展这个虚拟 DOM。
const ele = document.querySelector('.BDEI9.LZgQXe');
const ele2 = document.createElement('div');
ele2.innerHTML = 'Aweh!!!!';
ele.appendChild(ele2)
将更新后的 HTML 导出为 base64。
let buffer = Buffer.from(dom.serialize());
const base64 = "data:" + 'text/html' + ';base64,' + buffer.toString('base64');
现在加载页面。
mainWindow.loadURL(base64)
mainWindow.webContents.openDevTools();
最终的代码如下所示。
const { app, BrowserWindow } = require('electron')
const fetch = async (...args) => await import('node-fetch').then(({ default: fetch }) => fetch(...args));
const path = require('path')
const jsdom = require("jsdom");
const { Buffer } = require('buffer');
const { JSDOM } = jsdom;
function createWindow() {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
;(async () => {
// 使用 node-fetch 获取 Gmail 的 HTML
const html = await fetch('https://gmail.com').then(resp => resp.text())
// 在内存中创建 DOM
const dom = new JSDOM(html);
const document = dom.window.document;
// 扩展 DOM
const ele = document.querySelector('.BDEI9.LZgQXe');
const ele2 = document.createElement('div');
ele2.innerHTML = 'Aweh!!!!';
ele.appendChild(ele2)
// 导出更新后的 HTML 内容为 base64
let buffer = Buffer.from(dom.serialize());
const base64 = "data:" + 'text/html' + ';base64,' + buffer.toString('base64');
// 加载页面
mainWindow.loadURL(base64)
mainWindow.webContents.openDevTools();
})()
}
希望这有所帮助。
英文:
I hope this helps, but I experimented a bit and did the following...
Please note that the following code is in a self-invoked async function
Get the HTML for gmail using node-fetch.
const html = await fetch('https://gmail.com').then(resp => resp.text())
Create the dom in memory using JSDOM
const dom = new JSDOM(html);
const document = dom.window.document;
Augment this virtual dom however you like
const ele = document.querySelector('.BDEI9.LZgQXe');
const ele2 = document.createElement('div');
ele2.innerHTML = 'Aweh!!!!';
ele.appendChild(ele2)
Export updated HTML as base64
let buffer = Buffer.from(dom.serialize());
const base64 = "data:" + 'text/html' + ';base64,' + buffer.toString('base64');
Now load the page
mainWindow.loadURL(base64)
mainWindow.webContents.openDevTools();
The final code looks like this
const { app, BrowserWindow } = require('electron')
const fetch = async (...args) => await import('node-fetch').then(({ default: fetch }) => fetch(...args));
const path = require('path')
const jsdom = require("jsdom");
const { Buffer } = require('buffer');
const { JSDOM } = jsdom;
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
;(async () => {
// Get the html for gmail using node-fetch
const html = await fetch('https://gmail.com').then(resp => resp.text())
// Create the dom in memory
const dom = new JSDOM(html);
const document = dom.window.document;
// Augment the dom
const ele = document.querySelector('.BDEI9.LZgQXe');
const ele2 = document.createElement('div');
ele2.innerHTML = 'Aweh!!!!';
ele.appendChild(ele2)
// Export updated html content as base64
let buffer = Buffer.from(dom.serialize());
const base64 = "data:" + 'text/html' + ';base64,' + buffer.toString('base64');
// Load page
mainWindow.loadURL(base64)
mainWindow.webContents.openDevTools();
})()
}
Hopefully, this helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论