vue内嵌网页可以使用iframe实现内嵌网页,但是只能通过postMessage间接通信,在electron环境下,vue可以直接使用webview来内嵌网页,支持 executeJavaScript、postMessage、send 等丰富的通信机制。
使用 webview的优势
性能更佳:独立进程,适合加载复杂网页或 Web App。
更强的 API 控制:支持 executeJavaScript、postMessage、send 等丰富的通信机制。
更强的安全性:启用 contextIsolation、sandbox 等参数可大幅降低攻击面。
使用 iframe的优势
轻量快捷:无需额外配置,简单加载外部网页或静态内容。
兼容性更好:更接近标准 Web 技术,适用于更广泛的项目场景。
注:官方更推荐WebContentsView,webview已经不推荐,但还是能够使用
前端代码 (Vue 3 组件)
<template>
<div class="content-layout" >
<webview ref="webviewRef" :src="url" style="width: 100%; height: 100%;"
@dom-ready="onDomReady"></webview>
</div>
</template>
<script lang="ts" setup >
import { ref, onMounted } from 'vue';
const url = ref('https://www.baidu.com');
const webviewRef = ref<Electron.WebviewTag | null>(null);
onMounted(() => {
if (webviewRef.value) {
webviewRef.value.addEventListener('dom-ready', () => {
webviewRef.value!.executeJavaScript(`
console.log("Injected JavaScript: Hello from Electron!");
document.body.style.backgroundColor = 'lightblue';
`);
});
}
});
function onDomReady () {
console.log('Webview DOM Ready!');
};
</script>
<style scoped>
.content-layout {
width: 100%;
background-color: var(--color-background-content);
}
</style>
主进程 (main.js)
在 Electron 主进程中,需要配置 webview 的权限。
const { app, BrowserWindow } = require('electron');
let mainWindow;
app.whenReady().then(() => {
mainWindow = new BrowserWindow({
width: 1000,
height: 800,
webPreferences: {
preload: `${__dirname}/preload.js`, // 为 webview 提供安全预加载脚本
webviewTag: true, // 启用 webview 标签
contextIsolation: true, // 提高安全性
enableRemoteModule: false // 禁止远程模块,减少安全风险
}
});
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
}
});
预加载脚本 (preload.js)
预加载脚本用于在 webview 和 主进程 之间安全地通信
const { contextBridge, ipcRenderer } = require('electron');
// 暴露安全 API 给 Webview
contextBridge.exposeInMainWorld('electronAPI', {
sendMessage: (message) => ipcRenderer.send('message', message)
});
// 监听来自主进程的消息
ipcRenderer.on('reply', (event, response) => {
console.log('Received from main process:', response);
});