当前位置: 首页 > wzjs >正文

盐城网站建设中国女排联赛排名

盐城网站建设,中国女排联赛排名,h5网站开发软件,衢州网站建设公司渲染进程与渲染进程之间的通信有两种: 通过主进程进行消息转发(通过组合主进程与渲染进程之间的单向、双向通信可以实现,可以自己动手尝试,该篇不讲解)通过消息端口进行直接通信 该篇主要用示例讲解下单项目内多个窗口…

渲染进程与渲染进程之间的通信有两种:

  • 通过主进程进行消息转发(通过组合主进程与渲染进程之间的单向、双向通信可以实现,可以自己动手尝试,该篇不讲解)
  • 通过消息端口进行直接通信

该篇主要用示例讲解下单项目内多个窗口的渲染进程之间相互通信的流程(也就是通过消息端口进行通知)
初始版本项目结构可参考项目:https://github.com/ylpxzx/electron-forge-project/tree/init_project

请添加图片描述

渲染进程与渲染进程之间的消息端口通信

实现整项目示例:https://github.com/ylpxzx/electron-forge-project/tree/message_port

MessageChannelMain方法

示例:

const { port1, port2 } = new MessageChannelMain()

MessageChannelMain方法用于创建一个消息通道,该通道包含两个端口 port1 和 port2。这两个端口可以用于在不同的上下文(如主进程和渲染进程)之间传递消息

通信逻辑

通过模拟主窗口(Main)与配置窗口(Settings)之间的通信,来了解下如何通过消息端口实现渲染进程之间的通信

新增Settings窗口预加载文件
  • 创建src/settingPreload.js文件

    该预加载文件用于暴露可用的Electron API给Settings窗口页面调用

    该文件创建完成后,需要在forge.config.js文件的plugins字段进行配置

    {name: '@electron-forge/plugin-vite',config: {build: [{entry: 'src/main.js',config: 'vite.main.config.mjs',target: 'main',},{entry: 'src/preload.js',config: 'vite.preload.config.mjs',target: 'preload',},{ // 加入该配置entry: 'src/settingPreload.js',config: 'vite.preload.config.mjs',target: 'preload',},],renderer: [{name: 'main_window',config: 'vite.renderer.config.mjs',},],},},
    
主进程下发消息端口给窗口
  • src/main.js文件
    请添加图片描述
    端口下发逻辑:

    • 在主进程main.js文件中,调用消息体MessageChannelMain方法,得到两个可互相通信的端口port1、port2

    • 将消息体端口port1、port2分别下发给准备就绪后的main窗口和settings窗口(即下发给两个渲染进程)

      // 将port1端口下发给main窗口
      mainWindow.once('ready-to-show', () => {mainWindow.webContents.postMessage('main-port', null, [port1])
      })// 将port2端口下发给settings窗口
      settingsWindow.once('ready-to-show', () => {settingsWindow.webContents.postMessage('settings-port', null, [port2])
      })
      

    完整代码如下:

    import { app, BrowserWindow, MessageChannelMain } from 'electron';
    import path from 'node:path';
    import started from 'electron-squirrel-startup';// Avoid Warning:Electron Security Warning (Insecure Content-Security-Policy) This renderer process has either no Content Security
    process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";if (started) {app.quit();
    }// crerate message channel
    const { port1, port2 } = new MessageChannelMain()// 创建Main窗口
    const createWindow = () => {const mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js'),},});if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);} else {mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`));}// webContents准备就绪后,使用postMessage向webContents发送端口main-portmainWindow.once('ready-to-show', () => {mainWindow.webContents.postMessage('main-port', null, [port1])})mainWindow.webContents.openDevTools();
    };// 创建Settings窗口
    const createSettingsWindow = () => {const settingsWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {nodeintegration: true,preload: path.join(__dirname, 'settingPreload.js'),},});if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {const settingUrl = `${MAIN_WINDOW_VITE_DEV_SERVER_URL}/#/settings`;settingsWindow.loadURL(settingUrl);} else {mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`));}// webContents准备就绪后,使用postMessage向webContents发送端口settings-portsettingsWindow.once('ready-to-show', () => {settingsWindow.webContents.postMessage('settings-port', null, [port2])})settingsWindow.webContents.openDevTools();
    };app.whenReady().then(() => {// app准备好后,创建两个窗口createWindow();createSettingsWindow();app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) {createWindow();}});
    });app.on('window-all-closed', () => {if (process.platform !== 'darwin') {app.quit();}
    });
    
在预加载文件暴露可调用的Electron API给两个窗口页面
  • src/preload.js

    const { contextBridge, ipcRenderer } = require('electron/renderer')let electronMessage = nullipcRenderer.on('main-port', e => {electronMessage = e.ports[0]
    })contextBridge.exposeInMainWorld('electronAPI', {// 向端口发送消息pushMessageEvent: (message) => electronMessage.postMessage(message),// 监听端口消息onMessagePort: (callback) => {const listener = (e) => {e.ports[0].onmessage = messageEvent => {callback(messageEvent.data)}}ipcRenderer.on('main-port', listener)return () => ipcRenderer.removeListener('main-port', listener)},
    })
    

    暴露给页面调用的API有两个:发送消息API、监听消息API; 都是通过ipcRenderer.on实现。

    • 发送消息API:需在上下文隔离外(contextBridge)先实例化消息示例(electronMessage), 然后通过postMessage方法推送消息给端口。

      如果在contextBridge内直接调用e.ports[0].postMessage(message), 会发送不成功。如下错误示例(没有任何报错):

      pushMessageEvent: (message) => {ipcRenderer.on('main-port', e => {e.ports[0].postMessage(message)})
      },
      

      具体为啥会失败,目前没找到原因。如果有人能答下疑惑,可以在评论区解答下

    • 监听消息API:通过e.ports[0].onmessage方法监听端口,接收到消息时触发对应的回调函数callback

  • src/settingPreload.js 同上

    const { contextBridge, ipcRenderer } = require('electron/renderer')
    let electronMessageTest = nullipcRenderer.on('settings-port', e => {electronMessageTest = e.ports[0]
    })contextBridge.exposeInMainWorld('electronSettingAPI', {pushMessageEvent: (message) => electronMessageTest.postMessage(message),onMessagePort: (callback) => {const listener = (e) => {e.ports[0].onmessage = messageEvent => {callback(messageEvent.data)}}ipcRenderer.on('settings-port', listener)return () => ipcRenderer.removeListener('settings-port', listener)},
    })
    

页面示例

通信逻辑实现后,接下来就用两个窗口页面来验证结果

  • src/vue-project/pages/home/index.vue

    <template><h1>😁 Main Render Process</h1><div style="padding-bottom: 10px;">Receive messages from the Settings window process:<span style="color: #71C25C;">{{messageVal }}</span></div><div style="display: flex; gap: 10px;"><input id="inputID" ref="inputRef" v-model="inputVal" /><button @click="onClick">Send to Settings window</button></div>
    </template><script setup>
    import { ref, onUnmounted, onMounted } from 'vue'
    const inputRef = ref(null)
    const inputVal = ref('')
    const messageVal = ref(null)
    const onClick = () => {// 点击发送消息electronAPI.pushMessageEvent(inputVal.value)
    }
    let removeLister = nullonMounted(() => {// 监听接收settins窗口回传的消息removeLister = electronAPI.onMessagePort(async (value) => {messageVal.value = value})
    })onUnmounted(() => {// 页面移除时,移除监听removeLister()
    })
    </script>
    
  • src/vue-project/pages/settings/index.vue

    <template><h1>😊 Settings Render Process</h1><div style="padding-bottom: 10px;">Received message from the main window process:<span style="color: #71C25C;">{{message}}</span></div><div style="display: flex; gap: 10px;"><input v-model="inputVal" /><button @click="onClick">Send to Main window</button></div>
    </template><script setup>
    import { ref, onUnmounted, onMounted } from 'vue'
    const message = ref('')
    const inputVal = ref('')const onClick = () => {// 点击发送消息electronSettingAPI.pushMessageEvent(inputVal.value)
    }let removeLister = nullonMounted(() => {// 监听端口消息,当接收到消息时,再回传一段话给main窗口removeLister = electronSettingAPI.onMessagePort((value) => {message.value = valueelectronSettingAPI.pushMessageEvent(`👋 Hello main window, I have received your message, message is ${message.value}`)})
    })onUnmounted(() => {// 页面移除时,移除监听removeLister()
    })
    </script>
    
  • src/vue-project/router/index.js

    import { createWebHashHistory, createRouter } from 'vue-router'import HomeView from '@/vue-project/pages/home/index.vue'
    import SettingsView from '@/vue-project/pages/settings/index.vue'const routes = [{ path: '/', component: HomeView },{ path: '/settings', component: SettingsView },
    ]
    const router = createRouter({history: createWebHashHistory(),routes,
    })export default router;
    
  • src/vue-project/App.vue

    <template><h1>🖥️ Hello World!</h1><p>Welcome to your Electron application.</p><p>🎉 Welcome to your Electron <span style="font-weight: 600;">{{ isMain ? 'Main' : 'Settings' }} Window </span>. 🎊</p><divstyle="margin-top: 20px; border: 1px solid grey; padding: 20px; border-radius: 6px; background-color: #23272E; color: #fff"><router-view></router-view></div>
    </template><script setup>
    import { ref } from 'vue'
    const isMain = ref(true)
    if (window.electronAPI) {isMain.value = true
    } else {isMain.value = false
    }
    </script>
    

示例演示:

在这里插入图片描述

解决潜在问题:

问题1:从其他页面切换回来时,消息端口监听失效

  • src/vue-project/pages/empty/index.vue

    新增一个空页面,用于复现从其他页面切换回来后,消息端口监听失效问题

    <template><h1>😁Test whether the message communication is still valid after the page is switched back.</h1>
    </template><script setup>
    </script>
    
  • src/vue-project/router/index.js

    注册empty页面路由

    import { createWebHashHistory, createRouter } from 'vue-router'import HomeView from '@/vue-project/pages/home/index.vue'
    import SettingsView from '@/vue-project/pages/settings/index.vue'
    import EmptyView from '@/vue-project/pages/empty/index.vue'const routes = [{ path: '/', component: HomeView },{ path: '/settings', component: SettingsView },{ path: '/empty', component: EmptyView },
    ]
    const router = createRouter({history: createWebHashHistory(),routes,
    })export default router;
    
  • src/vue-project/App.vue

    <template><h1>🖥️ Hello World!</h1><p>Welcome to your Electron application.</p><p>🎉 Welcome to your Electron <span style="font-weight: 600;">{{ isMain ? 'Main' : 'Settings' }} Window </span>. 🎊</p><nav><div v-if="isMain"><RouterLink to="/">Go to Home</RouterLink></div><div v-if="isMain"><div><RouterLink to="/empty">Go to empty page<span style="font-size: 12px; color: #999; padding-left: 10px;"></span></RouterLink></div></div></nav><divstyle="margin-top: 20px; border: 1px solid grey; padding: 20px; border-radius: 6px; background-color: #23272E; color: #fff"><router-view></router-view></div>
    </template><script setup>
    import { ref } from 'vue'
    const isMain = ref(true)
    if (window.electronAPI) {isMain.value = true
    } else {isMain.value = false
    }
    </script>
    
  • 问题复现

    在这里插入图片描述

  • 解决方法

    vue页面没缓存的情况下,页面会直接被移除,导致之前的监听也丢失。需要给页面路由加上<keep-alive>

    src/vue-project/App.vue

    <!-- 该处得加入keep-alive,否则切换路由时会重新渲染组件,导致消息端口监听器失效 -->
    <router-view v-slot="{ Component }"><keep-alive><component :is="Component" /></keep-alive>
    </router-view>
    

问题2:项目打包构建npm run make后运行,settings窗口显示报错

请添加图片描述

  • 解决方法:

    报错的原因是在生产环境下,找不到settings窗口的路由导致的,更改下生产环境的页面路由路径就可以了

    src/main.js

    // 其他代码...
    const createSettingsWindow = () => {const settingsWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {nodeintegration: true,preload: path.join(__dirname, 'settingPreload.js'),},});if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {const settingUrl = `${MAIN_WINDOW_VITE_DEV_SERVER_URL}/#/settings`;settingsWindow.loadURL(settingUrl);} else {// 增加此行代码:hash: 'settings', 保证打包好的生产环境下正常跳转settingsWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`), { hash: 'settings' });}settingsWindow.once('ready-to-show', () => {settingsWindow.webContents.postMessage('settings-port', null, [port2])})settingsWindow.webContents.openDevTools();
    };
    // 其他代码...
    

项目结构

请添加图片描述

http://www.dtcms.com/wzjs/165183.html

相关文章:

  • 分形科技做网站怎么样站长工具推荐网站
  • 那里有制作网站企业seo课
  • 物流企业网站如何在外贸平台推广
  • 优质的南昌网站建设外贸如何推广
  • 政府门户网站建设目的百家号自媒体平台注册
  • 长沙定制网站建设百度上首页
  • 中国网页设计师联盟seo计费系统登录
  • 主机托管是什么意思关键词排名优化营销推广
  • 网站做系统叫什么软件有哪些seo外包资讯
  • 云服务器做淘客网站可以看任何网站的浏览器
  • 高要网站制作青岛seo关键词优化公司
  • 陕西网站建设培训品牌宣传策划公司
  • 图片上传网站变形的处理湖北百度关键词排名软件
  • 装潢设计费用怎么算关键词优化难度分析
  • 爱网站查询关键词优化排名详细步骤
  • 合肥网页设计培训学校seo是指什么意思
  • 佛山cms建站系统百度服务中心电话
  • 做吉祥物设计看什么网站百度官方免费下载安装
  • 如何做网站banner搜索引擎seo如何优化
  • 设计师参考效果图网站橙子建站官网
  • 河北省建设环境备案网站谷歌官网首页
  • 景观做文本常用的网站2023新闻热点摘抄
  • 合肥哪家做网站不错昆明seo网站建设
  • 做网上卖酒的网站有几家百度广告竞价排名
  • 做购物网站安全吗aso100官网
  • 宁波做网站gs百度知道小程序
  • 电商网站如何做引流加盟网络营销推广公司
  • 做静态网站选用什么服务器深圳百度推广联系方式
  • 保定手机网站制作全网霸屏推广系统
  • 网站建设服务协议模板软文发布公司