<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Electron 進(jìn)程間通信(IPC)方法詳解

      Electron 是一個使用 JavaScript、HTML 和 CSS 構(gòu)建桌面應(yīng)用程序的框架,它是基于 Chromium 和 Node.js 構(gòu)建的,而 Chromium 本身是采用多進(jìn)程架構(gòu)的,所以 Electron 也是多進(jìn)程的。
      Electron 是一個多進(jìn)程框架,它的進(jìn)程主要分為兩類:主進(jìn)程(Main Process)渲染進(jìn)程(Renderer Process) ,兩者分工協(xié)作,共同完成桌面應(yīng)用的運行。

      Electron 主進(jìn)程

      每個 Electron 應(yīng)用有且僅有一個主進(jìn)程,它是應(yīng)用程序的入口點。主進(jìn)程在 Node.js 環(huán)境中運行,這意味著它具有使用 require 模塊和所有 Node.js API 的能力,擁有完整的系統(tǒng)權(quán)限。主進(jìn)程常用來負(fù)責(zé)應(yīng)用的生命周期管理(啟動、退出)、窗口創(chuàng)建、系統(tǒng)事件處理(如文件操作、菜單交互)等。主進(jìn)程通過 BrowserWindow 創(chuàng)建和管理窗口,每個窗口對應(yīng)一個獨立的渲染進(jìn)程。

      Electron 渲染進(jìn)程

      每個 Electron 應(yīng)用都會為 BrowserWindow 創(chuàng)建的窗口生成一個單獨的渲染器進(jìn)程。 渲染進(jìn)程負(fù)責(zé)渲染網(wǎng)頁內(nèi)容,處理用戶界面交互,運行于渲染進(jìn)程中的代碼要遵照網(wǎng)頁創(chuàng)建標(biāo)準(zhǔn)。渲染進(jìn)程以一個 HTML 文件作為渲染器進(jìn)程的入口點,這也意味著渲染進(jìn)程中無權(quán)直接訪問 require 或其他 Node.js API。

      進(jìn)程間通信(IPC)

      Electron 提供了一個特殊的預(yù)加載腳本,它將 Electron 的主進(jìn)程和渲染進(jìn)程橋接在一起,我們可以通過配置預(yù)加載腳本來實現(xiàn) Electron 不同進(jìn)程之間的通信。

      預(yù)加載腳本在 BrowserWindow 構(gòu)造器中使用 webPreferences.preload 引入,它在渲染器加載網(wǎng)頁之前注入,所以在預(yù)加載腳本中可以訪問 document、window、部分權(quán)限的 Node.js 和 Electron 的 API。

      // main.js 主進(jìn)程文件
      
      const { app, BrowserWindow } = require('electron/main')
      const path = require('node:path')
      
      const createWindow = () => {
        // 創(chuàng)建瀏覽器窗口
        const win = new BrowserWindow({
          width: 800, // 窗口寬度
          height: 600, // 窗口高度
          webPreferences: {
            // sandbox: false, // 是否開啟沙盒模式
            // nodeIntegration: false, // 是否開啟node集成
            // contextIsolation: true, // 是否開啟上下文隔離
            preload: path.join(__dirname, 'preload.js'), // 預(yù)加載腳本
          },
        })
        win.webContents.openDevTools() // 打開窗口的開發(fā)者工具
        // 把html文件加載到窗口中
        win.loadFile('index.html')
      }
      
      

      在預(yù)加載腳本中,我們通過 Electron 中的 contextBridge.exposeInMainWorld 方法定義一個變量暴露給渲染器,在這個變量中可以添加主進(jìn)程中的一些 API,渲染器可以在全局 window 對象中訪問它。下面是預(yù)加載腳本的部分代碼,展示的是如何把 Node 和 Electron 的版本號暴露給渲染器。

      // preload.js 預(yù)加載文件
      
      const { contextBridge } = require('electron')
      
      contextBridge.exposeInMainWorld('versions', {
        node: () => process.versions.node, // node版本號
        chrome: () => process.versions.chrome, // chrome版本號
        electron: () => process.versions.electron, // electron版本后
        // 除函數(shù)之外,我們也可以暴露變量
      })
      

      在 html 文件中我們可以直接獲取變量 versions,代碼展示如下:

      <body>
         <p id="version-info"></p>
      </body>
      <script>
      // 渲染腳本
      window.addEventListener('DOMContentLoaded', () => {
        if (versionInfo) {
          const versionInfoElement = document.getElementById('version-info')
          versionInfoElement.innerHTML = `
            <p>Node.js 版本: v${versionInfo?.node()}</p>
            <p>Chrome 版本: v${versionInfo?.chrome()}</p>
            <p>Electron 版本: v${versionInfo?.electron()}</p>
          `
        }
      })
      </script>
      

      1. 模式一:渲染器進(jìn)程 => 主進(jìn)程

      通常使用此模式從 web 頁面觸發(fā)預(yù)加載腳本中定義的事件,主進(jìn)程中監(jiān)聽此事件并處理相關(guān)內(nèi)容。下面展示的是設(shè)置窗口標(biāo)題的例子,只部分代碼,詳情請從 github 下載。

      點擊查看代碼
      // main.js 主進(jìn)程文件
      // 監(jiān)聽渲染進(jìn)程的 set-title 消息,主進(jìn)程設(shè)置窗口標(biāo)題
      ipcMain.on('set-title', (event, title) => {
        const webContents = event.sender
        const win = BrowserWindow.fromWebContents(webContents)
        win.setTitle(title)
      })
      
      // preload.js
      contextBridge.exposeInMainWorld('electronAPI', {
        setTitle: title => ipcRenderer.send('set-title', title), // set-title 是自定義的頻道名稱,主進(jìn)程監(jiān)聽 set-title 頻道并設(shè)置窗口標(biāo)題
      })
      
      // html
      <div class="demo-2 demo-box">
        <p>修改窗口標(biāo)題</p>
        <div>
          標(biāo)題: <input id="title"/>
          <button id="set-title-btn" type="button">設(shè)置標(biāo)題</button>
        </div>
      </div>
      
      // setTitle.js 渲染腳本
      window.addEventListener('DOMContentLoaded', () => {
        const setButton = document.getElementById('set-title-btn')
        const titleInput = document.getElementById('title')
        setButton.addEventListener('click', () => {
          const title = titleInput.value
          if (window?.electronAPI) {
            window.electronAPI.setTitle(title)
          }
        })
      })
      

      2. 模式二:渲染器進(jìn)程 <= 主進(jìn)程

      我們構(gòu)建一個由原生操作系統(tǒng)菜單控制的數(shù)字計數(shù)器,由主進(jìn)程控制計數(shù)器的增減,頁面負(fù)責(zé)更新數(shù)據(jù)。在主進(jìn)程中,調(diào)用窗口實例的 webContents.send 方法向渲染進(jìn)程傳遞數(shù)據(jù)。

      點擊查看代碼
      // main.js 主進(jìn)程
      const { app, BrowserWindow, Menu, ipcMain } = require('electron/main')
      const path = require('node:path')
      
      const createWindow = () => {
        const win = new BrowserWindow({
          width: 800, // 彈窗寬度
          height: 600, // 彈窗高度
          webPreferences: {
            preload: path.join(__dirname, 'preload.js'), // 預(yù)加載腳本
          },
        })
        // 打開窗口的開發(fā)者工具
        win.webContents.openDevTools()
        // 生成原生操作系統(tǒng)菜單
        const menu = Menu.buildFromTemplate([
          {
            label: '計數(shù)器',
            submenu: [
              {
                click: () => win.webContents.send('update-counter', 1), // update-counter 是自定義的頻道名稱
                label: '加1',
              },
              {
                click: () => win.webContents.send('update-counter', -1),
                label: '減1',
              },
            ],
          },
        ])
        // 設(shè)置窗口菜單
        Menu.setApplicationMenu(menu)
      
        // 把html文件加載到彈窗中
        win.loadFile('index.html')
      }
      
      // repload.js 預(yù)加載腳本
      const { contextBridge, ipcRenderer } = require('electron')
      
      contextBridge.exposeInMainWorld('electronAPI', {
        onUpdateCounter: callback => ipcRenderer.on('update-counter', (_event, value) => callback(value)), // 渲染進(jìn)程監(jiān)聽 update-counter 頻道并更新計數(shù)器
      })
      
      // html
      <div class="demo-3 demo-box">
        <p>
          計數(shù)器:
          <span id="counter">0</span>
        </p>
      </div>
      
      // counter.js 計數(shù)器渲染腳本
      window.addEventListener('DOMContentLoaded', () => {
        let counter = document.getElementById('counter').innerText
        counter = Number(counter)
        // 渲染進(jìn)程監(jiān)聽主進(jìn)程,當(dāng)主進(jìn)程發(fā)出 update-counter 消息時,更新計數(shù)器
        if (window.electronAPI?.onUpdateCounter) {
          window.electronAPI.onUpdateCounter(value => {
            counter += value
            document.getElementById('counter').innerText = counter
          })
        }
      })
      

      頁面更新數(shù)據(jù)后,也可以向主進(jìn)程發(fā)送信息,讓主進(jìn)程知道頁面已更新,具體實現(xiàn)方式請查看源碼。頁面計數(shù)器更新及主進(jìn)程獲取更新信息的截圖如下:

      計數(shù)器更新圖

      3. 模式三:渲染器進(jìn)程 <=> 主進(jìn)程

      雙向 IPC 的一個常見應(yīng)用是從渲染器進(jìn)程代碼調(diào)用主進(jìn)程模塊并等待結(jié)果。對于兩進(jìn)程間的相互通信,我們可以配合使用 ipcRenderer.invoke 和 ipcMain.handle 方法完成。現(xiàn)在我們實現(xiàn)一個例子,從渲染器進(jìn)程打開一個原生的文件對話框,并返回所選文件的路徑。

      點擊查看代碼
      // main.js 主進(jìn)程
      const { app, BrowserWindow, Menu, ipcMain, dialog } = require('electron/main')
      const path = require('node:path')
      
      // 創(chuàng)建瀏覽器窗口
      const createWindow = () => {
        const win = new BrowserWindow({
          width: 800, // 彈窗寬度
          height: 600, // 彈窗高度
          webPreferences: {
            preload: path.join(__dirname, 'preload.js'), // 預(yù)加載腳本
          },
        })
        // 打開窗口的開發(fā)者工具
        win.webContents.openDevTools()
        // 把html文件加載到彈窗中
        win.loadFile('index.html')
      }
      
      app.whenReady().then(() => {
        createWindow()
        // 監(jiān)聽渲染進(jìn)程的 open-file 頻道,顯示文件選擇框
        ipcMain.handle('open-file', async () => {
          const { canceled, filePaths } = await dialog.showOpenDialog()
          if (canceled) {
            return
          } else {
            return filePaths[0]
          }
        })
      
      // replod.js 預(yù)加載腳本
      const { contextBridge, ipcRenderer } = require('electron')
      
      contextBridge.exposeInMainWorld('electronAPI', {
        openFile: () => ipcRenderer.invoke('open-file'), // 渲染進(jìn)程觸發(fā)通信的頻道名稱open-file,主進(jìn)程監(jiān)聽open-file頻道并返回文件路徑
      
      })
      
      // html
      <div class="demo-4 demo-box">
        <p>
          <button type="button" id="open-btn">打開文件</button>
          文件路徑:
          <strong id="filePath"></strong>
        </p>
      </div>
      
      // openFile.js 渲染腳本
      window.addEventListener('DOMContentLoaded', () => {
        const electronAPI = window.electronAPI
        if (electronAPI?.openFile) {
          const openBtn = document.getElementById('open-btn')
          const pathElement = document.getElementById('filePath')
          openBtn.addEventListener('click', async () => {
            const filePath = await electronAPI.openFile()
            pathElement.innerText = filePath
          })
        }
      })
      

      主進(jìn)程與渲染進(jìn)程之間的通信大概可以通過以上幾種方式實現(xiàn),閱讀完代碼大家會發(fā)現(xiàn),進(jìn)程間通信主要使用的是 ipcRenderer.invoke/ipcMain.handle 和 ipcRenderer.send/ipcMain.on 兩種不同模式,這兩種模式的具體區(qū)別及使用場景我們后面再說。

      github倉庫地址:https://hgithub.xyz/zhench0515/electron-ipc.git 或者 https://github.com/zhench0515/electron-ipc.git

      posted @ 2025-03-13 18:07  老甄Home  閱讀(343)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产乱人伦无无码视频试看| 自偷自拍亚洲综合精品| 大地资源免费视频观看| h动态图男女啪啪27报gif| 人妻中文字幕精品系列| 久久亚洲av成人无码软件| 国产一区二区一卡二卡| 国产成人av免费网址| 久久精品国产亚洲av麻豆小说 | 少妇仑乱a毛片无码| 财经| 99在线 | 亚洲| 美女自卫慰黄网站| 亚洲日韩一区精品射精| 午夜国产小视频| 国产精品会所一区二区三区| 日韩不卡无码精品一区高清视频| 亚洲人成电影在线天堂色| 亚洲精品人妻中文字幕| 国产精品黄色大片在线看| 亚洲熟女乱色一区二区三区| 精品亚洲女同一区二区| 欧美成人精品三级网站视频| 另类 专区 欧美 制服| 少妇人妻系列无码专区视频| 性色av一区二区三区精品| 国产中文字幕一区二区| 精品乱码一区内射人妻无码| 亚洲一级片一区二区三区| 中文字幕少妇人妻精品| 久久夜色撩人精品国产小说 | 在线观看无码av五月花| 人妻少妇精品久久| 平顺县| 日本亚洲欧洲无免费码在线| 亚洲最大的熟女水蜜桃AV网站| 嘉鱼县| 一道本AV免费不卡播放| 国产成人MV视频在线观看| 中文字幕亚洲人妻系列| 国产免费视频一区二区|