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

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

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

      基于Electron27+Vite4+React18搭建桌面端項目|electron多開窗口實踐

      前段時間有分享一篇electron25+vite4搭建跨桌面端vue3應用實踐。今天帶來最新搗鼓的electron27+react18創建跨端程序、electron多開窗體(模擬QQ登錄窗口切換主窗口)、自定義無邊框窗口拖拽導航欄的一些知識分享。

      electron團隊更新迭代比較快,目前穩定版本已經升級到了electron27。而且運行及構建速度有了大幅度的提升!

      • 版本信息

      "vite": "^4.4.5"
      "react": "^18.2.0"
      "electron": "^27.0.1"
      "electron-builder": "^24.6.4"
      "vite-plugin-electron": "^0.14.1"
      • 搭建react18項目

      使用vite4構建工具創建react項目模板。

      yarn create vite electron-vite4-react18
      # 選擇創建react模板 cd electron
      -vite4-react18 yarn install yarn dev

      至此,一個基礎的react模板項目就創建好了。接下來就是安裝electron相關的依賴配置。

      • 安裝electron關聯依賴包

       注意:如果安裝出現卡頓情況,建議設置淘寶鏡像源。

      // 安裝electron
      yarn add -D electron
      // 安裝electron-builder 用于構建打包可安裝exe程序
      yarn add -D electron-builder
      // 安裝electron-devtools-installer 用于開發調試electron項目
      yarn add -D electron-devtools-installer

      另外還需要安裝一個electron和vite的橋接插件vite-plugin-electron

      yarn add -D vite-plugin-electron

      vite-plugin-electron:一款快速集成整合Vite和Electron,方便在渲染進程中使用Node API或Electron API功能。

      到這里,所依賴的electron插件已經安裝完畢。接下來就是創建主進程,啟動項目了。

      • 創建主進程配置

      const { app, BrowserWindow } = require('electron')
      
      const MultiWindow = require('./src/windows')
      
      const createWindow = () => {
          let win = new MultiWindow()
          win.createWin({ isMainWin: true })
      }
      
      app.whenReady().then(() => {
          createWindow()
          app.on('activate', () => {
              if (BrowserWindow.getAllWindows().length === 0) createWindow()
          })
      })
      
      app.on('window-all-closed', () => {
          if (process.platform !== 'darwin') app.quit()
      })

      配置vite.config.js

      在vite.config.js中引入vite-plugin-electron配置主進程入口electron-main.js文件。

      import { defineConfig, loadEnv } from 'vite'
      import react from '@vitejs/plugin-react'
      import electron from 'vite-plugin-electron'
      import { resolve } from 'path'
      import { parseEnv } from './src/utils/env'
      
      // https://vitejs.dev/config/
      export default defineConfig(({ command, mode }) => {
          const viteEnv = loadEnv(mode, process.cwd())
          const env = parseEnv(viteEnv)
      
          return {
              plugins: [
                  react(),
                  electron({
                      entry: 'electron-main.js',
                  })
              ],
      
              esbuild: {
                  // 打包去除 console.log 和 debugger
                  drop: env.VITE_DROP_CONSOLE && command === 'build' ? ["console", "debugger"] : []
              },
      
              /* 開發服務器配置 */
              server: {
                  // 端口
                  port: env.VITE_PORT,
                  // 代理配置
                  proxy: {
                      // ...
                  }
              },
      
              resolve: {
                  // 設置別名
                  alias: {
                      '@': resolve(__dirname, 'src'),
                      '@assets': resolve(__dirname, 'src/assets'),
                      '@components': resolve(__dirname, 'src/components'),
                      '@views': resolve(__dirname, 'src/views')
                  }
              }
          }
      })

      配置package.json

      在package.json文件中加入 "main": "electron-main.js" 入口配置,并且需要去掉 "type": "module" 。

      注意:官方提示electron28之后可以支持"type": "module"

      接下來就運行yarn electron:serve桌面端項目就能運行了。

      至于一些electron打包配置,這里就不詳細介紹了,之前有相關分享的文章。

      http://www.rzrgm.cn/xiaoyan2017/p/17436076.html

      • electron自定義無邊框拖拽導航欄

      創建窗口的時候設置 frame: false 即可創建一個無系統邊框的窗體。

      通過css設置 -webkit-app-region: drag 來實現拖拽區域。設置 -webkit-app-region: no-drag 取消拖拽響應。

      自定義最大化/最小化/關閉

      import { useState, useContext } from 'react'
      import { Modal } from '@arco-design/web-react'
      import { setWin } from '@/windows/action'
      
      function WinBtn(props) {
        const {
          color = '#fff',
          minimizable = true,
          maximizable = true,
          closable = true,
          zIndex = 2023,
      
          children
        } = props
      
        const [hasMaximized, setHasMaximized] = useState(false)
      
        window.electronAPI.invoke('win__isMaximized').then(res => {
          setHasMaximized(res)
        })
        window.electronAPI.receive('win__hasMaximized', (e, res) => {
          setHasMaximized(res)
        })
      
        // 最小化
        const handleWinMin = () => {
            window.electronAPI.send("win__minimize")
        }
        // 最大化/還原
        const handleWinMax2Min = () => {
            window.electronAPI.invoke("win__max2min").then(res => {
                console.log(res)
                setHasMaximized(res)
            })
        }
        // 關閉
        const handleWinClose = () => {
            if(window.config.isMainWin) {
              Modal.confirm({
                title: '提示',
                content: <div style={{ textAlign: 'center' }}>是否最小化至托盤,不退出程序?</div>,
                okButtonProps: {status: 'warning'},
                style: {width: 360},
                cancelText: '最小化至托盤',
                okText: '殘忍退出',
                onOk: () => {
                  setWin('close')
                },
                onCancel: () => {
                  setWin('hide', window.config.id)
                }
              })
            }else {
                setWin('close', window.config.id)
            }
        }
      
        return (
          <>
            <div className="vui__macbtn flexbox flex-alignc" style={{zIndex: zIndex}}>
              <div className="vui__macbtn-groups flexbox flex-alignc" style={{color: color}}>
                { JSON.parse(minimizable) && <a className="mbtn min" title="最小化" onClick={handleWinMin}><svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#995700" d="M8.048,4.001c0.163,0.012 0.318,0.054 0.459,0.137c0.325,0.191 0.518,0.559 0.49,0.934c-0.007,0.097 -0.028,0.192 -0.062,0.283c-0.04,0.105 -0.098,0.204 -0.171,0.29c-0.083,0.098 -0.185,0.181 -0.299,0.24c-0.131,0.069 -0.271,0.103 -0.417,0.114c-2.031,0.049 -4.065,0.049 -6.096,0c-0.163,-0.012 -0.318,-0.054 -0.459,-0.137c-0.325,-0.191 -0.518,-0.559 -0.49,-0.934c0.007,-0.097 0.028,-0.192 0.062,-0.283c0.04,-0.105 0.098,-0.204 0.171,-0.29c0.083,-0.098 0.185,-0.181 0.299,-0.24c0.131,-0.069 0.271,-0.103 0.417,-0.114c2.031,-0.049 4.065,-0.049 6.096,0Z"></path></svg></a> }
                { JSON.parse(maximizable) &&
                  <a className="mbtn max" title={hasMaximized ? '向下還原' : '最大化'} onClick={handleWinMax2Min}>
                    {
                      hasMaximized ?
                      <svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#4d0000" d="M5,10c0,0 0,-2.744 0,-4.167c0,-0.221 -0.088,-0.433 -0.244,-0.589c-0.156,-0.156 -0.368,-0.244 -0.589,-0.244c-1.423,0 -4.167,0 -4.167,0l5,5Z"></path><path fill="#006400" d="M5,0c0,0 0,2.744 0,4.167c0,0.221 0.088,0.433 0.244,0.589c0.156,0.156 0.368,0.244 0.589,0.244c1.423,0 4.167,0 4.167,0l-5,-5Z"></path></svg>
                      :
                      <svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#4d0000" d="M2,3c0,0 0,2.744 0,4.167c0,0.221 0.088,0.433 0.244,0.589c0.156,0.156 0.368,0.244 0.589,0.244c1.423,0 4.167,0 4.167,0l-5,-5Z"></path><path fill="#006400" d="M8,7c0,0 0,-2.744 0,-4.167c0,-0.221 -0.088,-0.433 -0.244,-0.589c-0.156,-0.156 -0.368,-0.244 -0.589,-0.244c-1.423,0 -4.167,0 -4.167,0l5,5Z"></path></svg>
                    }
                </a>
                }
                { JSON.parse(closable) && <a className="mbtn close" title="關閉" onClick={handleWinClose}><svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#4d0000" d="M5,3.552c0.438,-0.432 0.878,-0.861 1.322,-1.287c0.049,-0.044 0.101,-0.085 0.158,-0.119c0.149,-0.091 0.316,-0.137 0.49,-0.146c0.04,0 0.04,0 0.08,0.001c0.16,0.011 0.314,0.054 0.453,0.135c0.08,0.046 0.154,0.104 0.218,0.171c0.252,0.262 0.342,0.65 0.232,0.996c-0.045,0.141 -0.121,0.265 -0.218,0.375c-0.426,0.444 -0.855,0.884 -1.287,1.322c0.432,0.438 0.861,0.878 1.287,1.322c0.097,0.11 0.173,0.234 0.218,0.375c0.04,0.126 0.055,0.26 0.043,0.392c-0.011,0.119 -0.043,0.236 -0.094,0.344c-0.158,0.327 -0.49,0.548 -0.852,0.566c-0.106,0.005 -0.213,-0.007 -0.315,-0.035c-0.156,-0.043 -0.293,-0.123 -0.413,-0.229c-0.444,-0.426 -0.884,-0.855 -1.322,-1.287c-0.438,0.432 -0.878,0.861 -1.322,1.287c-0.11,0.097 -0.234,0.173 -0.375,0.218c-0.126,0.04 -0.26,0.055 -0.392,0.043c-0.119,-0.011 -0.236,-0.043 -0.344,-0.094c-0.327,-0.158 -0.548,-0.49 -0.566,-0.852c-0.005,-0.106 0.007,-0.213 0.035,-0.315c0.043,-0.156 0.123,-0.293 0.229,-0.413c0.426,-0.444 0.855,-0.884 1.287,-1.322c-0.432,-0.438 -0.861,-0.878 -1.287,-1.322c-0.106,-0.12 -0.186,-0.257 -0.229,-0.413c-0.025,-0.089 -0.037,-0.182 -0.036,-0.275c0.004,-0.363 0.211,-0.704 0.532,-0.874c0.13,-0.069 0.272,-0.105 0.418,-0.115c0.04,-0.001 0.04,-0.001 0.08,-0.001c0.174,0.009 0.341,0.055 0.49,0.146c0.057,0.034 0.109,0.075 0.158,0.119c0.444,0.426 0.884,0.855 1.322,1.287Z"></path></svg></a> }
                <i className="mr-10"></i>
                { children }
              </div>
              <div className="vui__mactitle">{window.config.title || '首頁'}</div>
          </div>
          </>
        )
      }
      
      export default WinBtn
      • electron自定義托盤圖標/托盤閃爍

      /**
       * Electron多窗口管理器
       * @author Andy  Q:282310962
       */
      
      const { app, BrowserWindow, ipcMain, Menu, Tray, dialog, globalShortcut } = require('electron')
      // const { loadEnv } = require('vite')
      const { join } = require('path')
      
      // 根目錄路徑
      process.env.ROOT = join(__dirname, '../../')
      
      const isDev = process.env.NODE_ENV === 'development'
      // const winURL = isDev ? 'http://localhost:3000/' : join(__dirname, 'dist/index.html')
      const winURL = isDev ? process.env.VITE_DEV_SERVER_URL : join(process.env.ROOT, 'dist/index.html')
      
      class MultiWindow {
          constructor() {
              // 主窗口對象
              this.main = null
              // 窗口組
              this.group = {}
      
              // 托盤圖標
              this.tray = null
              this.flashTimer = null
              this.trayIco1 = join(process.env.ROOT, 'resource/tray.ico')
              this.trayIco2 = join(process.env.ROOT, 'resource/tray-empty.ico')
      
              // 監聽ipcMain事件
              this.listenIpc()
              
              // 創建系統托盤
              this.createTray()
          }
      
          // 系統配置參數
          winOptions() {
              return {
                  // 窗口圖標
                  icon: join(process.env.ROOT, 'resource/shortcut.ico'),
                  backgroundColor: '#fff',
                  autoHideMenuBar: true,
                  titleBarStyle: 'hidden',
                  width: 900,
                  height: 600,
                  resizable: true,
                  minimizable: true,
                  maximizable: true,
                  frame: false, // 設置為 false 時可以創建一個無邊框窗口 默認值為 true
                  show: false, // 窗口是否在創建時顯示
                  webPreferences: {
                      contextIsolation: true, // 啟用上下文隔離(為了安全性)(默認true)
                      nodeIntegration: false, // 啟用Node集成(默認false)
                      preload: join(process.env.ROOT, 'electron-preload.js')
                  }
              }
          }
      
          // 創建新窗口
          createWin(options) {
              // ...
          }
      
          // ...
      
          // 主進程監聽事件
          listenIpc() {
              // 創建新窗體
              ipcMain.on('win-create', (event, args) => this.createWin(args))
      
              // ...
      
              // 托盤圖標閃爍
              ipcMain.on('win__flashTray', (event, bool) => this.flashTray(bool))
      
              // 屏幕截圖
              ipcMain.on('win__setCapture', () => {
                  // ...
              })
          }
      
          // 創建系統托盤圖標
          createTray() {
              console.log(__dirname)
              console.log(join(process.env.ROOT, 'resource/tray.ico'))
              
              const trayMenu = Menu.buildFromTemplate([
                  {
                      label: '打開主界面',
                      icon: join(process.env.ROOT, 'resource/home.png'),
                      click: () => {
                          try {
                              for(let i in this.group) {
                                  let win = this.getWin(i)
                                  if(!win) return
                                  // 是否主窗口
                                  if(this.group[i].isMainWin) {
                                      if(win.isMinimized()) win.restore()
                                      win.show()
                                  }
                              }
                          } catch (error) {
                              console.log(error)
                          }
                      }
                  },
                  {
                      label: '設置中心',
                      icon: join(process.env.ROOT, 'resource/setting.png'),
                      click: () => {
                          for(let i in this.group) {
                              let win = this.getWin(i)
                              if(win) win.webContents.send('win__ipcData', { type: 'CREATE_WIN_SETTING', value: null })
                          }
                      },
                  },
                  {
                      label: '鎖屏',
                      click: () => null,
                  },
                  {
                      label: '關閉托盤閃爍',
                      click: () => {
                          this.flashTray(false)
                      }
                  },
                  {type: 'separator'},
                  /* {
                      label: '重啟',
                      click: () => {
                          // app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) })
                          // app.exit(0)
      
                          app.relaunch()
                          app.quit()
                      }
                  }, */
                  {
                      label: '關于',
                      click: () => {
                          for(let i in this.group) {
                              let win = this.getWin(i)
                              if(win) win.webContents.send('win__ipcData', { type: 'CREATE_WIN_ABOUT', value: null })
                          }
                      }
                  },
                  {
                      label: '關閉應用并退出',
                      icon: join(process.env.ROOT, 'resource/logout.png'),
                      click: () => {
                          dialog.showMessageBox(this.main, {
                              title: '詢問',
                              message: '確定要退出應用程序嗎?',
                              buttons: ['取消', '最小化托盤', '退出應用'],
                              type: 'error',
                              noLink: false,  // true傳統按鈕樣式  false鏈接樣式
                              cancelId: 0
                          }).then(res => {
                              console.log(res)
      
                              const index = res.response
                              if(index == 0) {
                                  console.log('取消')
                              }if(index == 1) {
                                  console.log('最小化托盤')
                                  for(let i in this.group) {
                                      let win = this.getWin(i)
                                      if(win) win.hide()
                                  }
                              }else if(index == 2) {
                                  console.log('退出應用')
      
                                  try {
                                      for(let i in this.group) {
                                          let win = this.getWin(i)
                                          if(win) win.webContents.send('win__ipcData', { type: 'WIN_LOGOUT', value: null })
                                      }
                                      // app.quit 和 app.exit(0) 都可退出應用。
                                      // 前者可以被打斷并觸發一些事件,而后者將強制應用程序退出而不觸發任何事件或允許應用程序取消操作。
                                      app.quit()
                                  } catch (error) {
                                      console.log(error)
                                  }
                              }
                          })
                      }
                  }
              ])
              this.tray = new Tray(this.trayIco1)
              this.tray.setContextMenu(trayMenu)
              this.tray.setToolTip(app.name)
              this.tray.on('double-click', () => {
                  console.log('double clicked')
              })
      
              // 開啟托盤閃爍
              // this.flashTray(true)
          }
      
          // 托盤圖標閃爍
          flashTray(flash) {
              let hasIco = false
              
              if(flash) {
                  if(this.flashTimer) return
                  this.flashTimer = setInterval(() => {
                      this.tray.setImage(hasIco ? this.trayIco1 : this.trayIco2)
                      hasIco = !hasIco
                  }, 500)
              }else {
                  if(this.flashTimer) {
                      clearInterval(this.flashTimer)
                      this.flashTimer = null
                  }
                  this.tray.setImage(this.trayIco1)
              }
          }
      
          // 銷毀托盤圖標
          destoryTray() {
              this.flashTray(false)
              this.tray.destroy()
              this.tray = null
          }
      }
      
      module.exports = MultiWindow

      electron支持的一些環境變量。

      process.env.NODE_ENV
      process.env.VITE_DEV_SERVER_URL

      另外需要注意,__dirname變量指向當前文件。如:src/windows/index.js文件,則根目錄需要 ../../ 返回。

      Okay,以上就是electron27+react18+vite4搭建桌面端實踐項目的一些分享知識,希望對大家有所幫助哈!

      Vite5+Electron聊天室|electron31跨平臺仿微信EXE客戶端|vue3聊天程序

      Electron31-Vue3Admin管理系統|vite5+electron+pinia桌面端后臺Exe

      Electron32-ViteOS桌面版os系統|vue3+electron+arco客戶端OS管理模板

       

      posted @ 2023-10-26 01:22  xiaoyan2017  閱讀(2087)  評論(1)    收藏  舉報
      友情鏈接: UP主小店B站
      主站蜘蛛池模板: www夜插内射视频网站| 春菜花亚洲一区二区三区| 中文字幕乱码一区二区免费| 亚洲一区精品视频在线| 人妻日韩精品中文字幕| 国产久免费热视频在线观看| 天堂…中文在线最新版在线| 激情综合色综合啪啪五月| 中文国产不卡一区二区| 亚洲熟妇自偷自拍另欧美 | 99久久精品国产免费看| 亚洲色欲在线播放一区二区三区| 日本三级香港三级三级人妇久| 亚洲自拍偷拍中文字幕色| 麻豆精产国品一二三区区| 18禁亚洲一区二区三区| 亚洲中文字幕日产无码成人片| 亚洲日韩中文字幕在线播放| 亚洲蜜臀av乱码久久| 玩弄美艳馊子高潮无码| 起碰免费公开97在线视频| 亚洲综合色婷婷中文字幕| 四虎影视一区二区精品| 成人午夜污一区二区三区| 人妻丝袜无码专区视频网站| 久久久这里只有精品10| 无码AV无码免费一区二区| 亚洲精品一区二区三区小| 福利在线视频一区二区| 久久久久亚洲av成人网址| 2021亚洲国产精品无码 | 久久久久久久久久久免费精品| 99中文字幕国产精品| 搡老熟女老女人一区二区| 噜噜噜噜私人影院| 丁香婷婷在线观看| 在国产线视频A在线视频| 亚洲国产欧美在线看片一国产| 国产精品人成视频免| 国产农村老熟女乱子综合| 在线日韩日本国产亚洲|