screen1.gif

    1. {
    2. "name": "rabid-oil-clean-6o8jz",
    3. "productName": "rabid-oil-clean-6o8jz",
    4. "description": "My Electron application description",
    5. "keywords": [],
    6. "main": "./main.js",
    7. "version": "1.0.0",
    8. "author": "liubo",
    9. "scripts": {
    10. "start": "electron ."
    11. },
    12. "dependencies": {},
    13. "devDependencies": {
    14. "electron": "20.0.1"
    15. }
    16. }
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    6. <!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> -->
    7. <title>Hello World!</title>
    8. </head>
    9. <body>
    10. <h1>Hello World!</h1>
    11. We are using Node.js <span id="node-version"></span>,
    12. Chromium <span id="chrome-version"></span>,
    13. and Electron <span id="electron-version"></span>.
    14. <br />
    15. <button id="newWIn">新建窗口</button>
    16. <br />
    17. <button id="upload1">下载1</button>
    18. <button id="upload2">下载2</button>
    19. <br />
    20. <button id="cancel1">取消1</button>
    21. <button id="cancel2">取消2</button>
    22. <br />
    23. <div>
    24. <div>下载任务</div>
    25. <div id="downloads">
    26. </div>
    27. </div>
    28. <h1 id="h1"></h1>
    29. <!-- You can also require other files to run in this process -->
    30. <script src="./child.js"></script>
    31. <style>
    32. * {
    33. padding: 0;
    34. margin: 0;
    35. word-break: break-all;
    36. }
    37. </style>
    38. </body>
    39. </html>
    1. // This file is required by the index.html file and will
    2. // be executed in the renderer process for that window.
    3. // No Node.js APIs are available in this process because
    4. // `nodeIntegration` is turned off. Use `preload.js` to
    5. // selectively enable features needed in the rendering
    6. // process.
    7. // All of the Node.js APIs are available in the preload process.
    8. // It has the same sandbox as a Chrome extension.
    9. const { ipcRenderer, contextBridge } = require("electron");
    10. window.addEventListener("DOMContentLoaded", () => {
    11. const replaceText = (selector, text) => {
    12. const element = document.getElementById(selector);
    13. if (element) element.innerText = text;
    14. };
    15. for (const type of ["chrome", "node", "electron"]) {
    16. replaceText(`${type}-version`, process.versions[type]);
    17. }
    18. });
    19. window.app = {
    20. ipcReceive: (channel, callback) => {
    21. ipcRenderer.on(channel, (eventt, ...rest) => {
    22. callback(...rest);
    23. });
    24. },
    25. ipcSend: (channel, ...msg) => {
    26. ipcRenderer.send(channel, ...msg);
    27. },
    28. ipcInvoke: (channel, ...msg) => {
    29. return ipcRenderer.invoke(channel, ...msg);
    30. },
    31. }
    32. let newWIn = document.querySelector("#newWIn");
    33. let cancel1 = document.querySelector("#cancel1");
    34. let cancel2 = document.querySelector("#cancel2");
    35. let upload1 = document.querySelector("#upload1");
    36. let upload2 = document.querySelector("#upload2");
    37. let h1 = document.querySelector("#h1");
    38. let downloads = document.querySelector("#downloads");
    39. (async function () {
    40. let res = await window.app.ipcInvoke("getCount");
    41. console.log(res, "-------------");
    42. h1.innerHTML = res;
    43. })();
    44. newWIn.addEventListener("click", () => {
    45. window.app.ipcInvoke("createWindow");
    46. });
    47. cancel1.addEventListener("click", () => {
    48. window.app.ipcInvoke("cancel", { id: 1 });
    49. });
    50. cancel2.addEventListener("click", () => {
    51. window.app.ipcInvoke("cancel", { id: 2 });
    52. });
    53. upload1.addEventListener("click", () => {
    54. window.app.ipcInvoke("upload", {
    55. id: 1,
    56. url: "https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe",
    57. });
    58. });
    59. upload2.addEventListener("click", () => {
    60. window.app.ipcInvoke("upload", {
    61. id: 2,
    62. url: "https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe",
    63. });
    64. });
    65. window.app.ipcReceive("data-update", (data) => {
    66. console.log(data, "-------------");
    67. h1.innerHTML = data;
    68. });
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    6. <!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> -->
    7. <title>Hello World!</title>
    8. </head>
    9. <body>
    10. <h1>Hello World!</h1>
    11. We are using Node.js <span id="node-version"></span>,
    12. Chromium <span id="chrome-version"></span>,
    13. and Electron <span id="electron-version"></span>.
    14. <button id="newWIn">新建窗口</button>
    15. <br />
    16. <button id="upload1">下载1</button>
    17. <button id="upload2">下载2</button>
    18. <br />
    19. <button id="cancel1">取消1</button>
    20. <button id="cancel2">取消2</button>
    21. <br />
    22. <div>
    23. <div>下载任务</div>
    24. <div id="downloads">
    25. </div>
    26. </div>
    27. <h1 id="h1"></h1>
    28. <!-- You can also require other files to run in this process -->
    29. <script src="./renderer.js"></script>
    30. <style>
    31. * {
    32. padding: 0;
    33. margin: 0;
    34. word-break: break-all;
    35. }
    36. </style>
    37. </body>
    38. </html>
    1. // Modules to control application life and create native browser window
    2. const { app, BrowserWindow, ipcMain } = require('electron')
    3. const path = require('path')
    4. const http = require('http')
    5. const https = require('https')
    6. ipcMain.handle('createWindow', () => {
    7. createWindow()
    8. })
    9. let manage = []
    10. let count = 0
    11. ipcMain.handle('upload', (event, { id, url }) => {
    12. console.log(id, url)
    13. download(id, url)
    14. })
    15. function filter(manage) {
    16. let res = []
    17. for (let cur of manage) {
    18. let could = {}
    19. for (let n of Object.keys(cur)) {
    20. if (n === 'client') {
    21. could[n] = null
    22. } else {
    23. could[n] = cur[n]
    24. }
    25. }
    26. res.push(could)
    27. }
    28. return res
    29. }
    30. function download(id, url) {
    31. let run = manage.find(n => n.id === id)
    32. if (run && run.status === 'runing') return
    33. let cur = run ? run : {
    34. id,
    35. url,
    36. persent: 0,
    37. // controller,
    38. client: null,
    39. status: 'runing'
    40. }
    41. if (!run) {
    42. manage.push(cur)
    43. } else {
    44. run.persent = 0
    45. run.status = 'runing'
    46. }
    47. debugger;
    48. const options = {
    49. method: "GET",
    50. responseType: "blob",
    51. // signal,
    52. headers: {
    53. // "Content-Type": "application/json"
    54. },
    55. };
    56. console.log(url, options);
    57. if (url.startsWith("https://")) {
    58. const clientRequest = https.request(url, options, (incomingMessage) => {
    59. debugger;
    60. console.log(`状态码: ${incomingMessage.statusCode}`);
    61. let contentLength = incomingMessage.headers["content-length"];
    62. let load = 0;
    63. incomingMessage.on("data", (d) => {
    64. // console.log(incomingMessage)
    65. debugger;
    66. load += d.length;
    67. // process.stdout.write(d);
    68. let persent = Math.floor((load / contentLength) * 10000) / 100;
    69. console.log(d.length, load, contentLength, `${persent}%`);
    70. cur.persent = persent
    71. let res = filter(manage)
    72. notify(JSON.stringify(res))
    73. });
    74. incomingMessage.on("end", () => {
    75. console.log("end");
    76. });
    77. });
    78. cur.client = clientRequest
    79. clientRequest.end();
    80. clientRequest.on("error", (error) => {
    81. console.error(error);
    82. });
    83. clientRequest.on("close", (val) => {
    84. console.log("close");
    85. });
    86. } else {
    87. const clientRequest = http.request(url, options, (incomingMessage) => {
    88. debugger;
    89. console.log(`状态码: ${incomingMessage.statusCode}`);
    90. let contentLength = incomingMessage.headers["content-length"];
    91. let load = 0;
    92. incomingMessage.on("data", (d) => {
    93. // console.log(incomingMessage)
    94. debugger;
    95. load += d.length;
    96. // process.stdout.write(d);
    97. let persent = Math.floor((load / contentLength) * 10000) / 100;
    98. console.log(d.length, load, contentLength, `${persent}%`);
    99. cur.persent = persent
    100. let res = filter(manage)
    101. notify(JSON.stringify(res))
    102. });
    103. incomingMessage.on("end", () => {
    104. console.log("end");
    105. });
    106. });
    107. cur.client = clientRequest
    108. clientRequest.end();
    109. clientRequest.on("error", (error) => {
    110. console.error(error);
    111. });
    112. clientRequest.on("close", (val) => {
    113. console.log("close");
    114. });
    115. }
    116. }
    117. /* 通知给窗口 */
    118. function notify(message) {
    119. let wins = BrowserWindow.getAllWindows()
    120. for (let win of wins) {
    121. // console.log(win)
    122. win.webContents.send('data-update', message)
    123. }
    124. }
    125. ipcMain.handle('cancel', (event, { id }) => {
    126. console.log(id)
    127. let cur = manage.find(n => n.id === id)
    128. // cur.controller.abort();
    129. cur.status = 'cancel'
    130. cur.client.destroy()
    131. let res = filter(manage)
    132. notify(JSON.stringify(res))
    133. })
    134. ipcMain.handle('getCount', () => {
    135. return count
    136. })
    137. function createWindow() {
    138. // Create the browser window.
    139. const mainWindow = new BrowserWindow({
    140. width: 800,
    141. height: 600,
    142. webPreferences: {
    143. preload: path.join(__dirname, 'preload.js')
    144. }
    145. })
    146. // and load the index.html of the app.
    147. mainWindow.loadFile('index.html')
    148. // Open the DevTools.
    149. // mainWindow.webContents.openDevTools()
    150. }
    151. // This method will be called when Electron has finished
    152. // initialization and is ready to create browser windows.
    153. // Some APIs can only be used after this event occurs.
    154. app.whenReady().then(() => {
    155. createWindow()
    156. app.on('activate', function () {
    157. // On macOS it's common to re-create a window in the app when the
    158. // dock icon is clicked and there are no other windows open.
    159. if (BrowserWindow.getAllWindows().length === 0) createWindow()
    160. })
    161. })
    162. // Quit when all windows are closed, except on macOS. There, it's common
    163. // for applications and their menu bar to stay active until the user quits
    164. // explicitly with Cmd + Q.
    165. app.on('window-all-closed', function () {
    166. if (process.platform !== 'darwin') app.quit()
    167. })
    168. // In this file you can include the rest of your app's specific main process
    169. // code. You can also put them in separate files and require them here.
    1. // All of the Node.js APIs are available in the preload process.
    2. // It has the same sandbox as a Chrome extension.
    3. const { ipcRenderer, contextBridge } = require("electron");
    4. window.addEventListener('DOMContentLoaded', () => {
    5. const replaceText = (selector, text) => {
    6. const element = document.getElementById(selector)
    7. if (element) element.innerText = text
    8. }
    9. for (const type of ['chrome', 'node', 'electron']) {
    10. replaceText(`${type}-version`, process.versions[type])
    11. }
    12. })
    13. contextBridge.exposeInMainWorld('app', {
    14. ipcReceive: (channel, callback) => {
    15. ipcRenderer.on(channel, (eventt, ...rest) => {
    16. callback(...rest)
    17. })
    18. },
    19. ipcSend: (channel, ...msg) => {
    20. ipcRenderer.send(channel, ...msg)
    21. },
    22. ipcInvoke: (channel, ...msg) => {
    23. return ipcRenderer.invoke(channel, ...msg)
    24. },
    25. })
    1. // This file is required by the index.html file and will
    2. // be executed in the renderer process for that window.
    3. // No Node.js APIs are available in this process because
    4. // `nodeIntegration` is turned off. Use `preload.js` to
    5. // selectively enable features needed in the rendering
    6. // process.
    7. let newWIn = document.querySelector('#newWIn')
    8. let cancel1 = document.querySelector('#cancel1')
    9. let cancel2 = document.querySelector('#cancel2')
    10. let upload1 = document.querySelector('#upload1')
    11. let upload2 = document.querySelector('#upload2')
    12. let h1 = document.querySelector('#h1')
    13. let downloads = document.querySelector("#downloads")
    14. ; (async function () {
    15. let res = await window.app.ipcInvoke('getCount')
    16. console.log(res, '-------------')
    17. h1.innerHTML = res
    18. })()
    19. newWIn.addEventListener('click', () => {
    20. window.app.ipcInvoke('createWindow')
    21. })
    22. cancel1.addEventListener('click', () => {
    23. window.app.ipcInvoke('cancel', { id: 1 })
    24. })
    25. cancel2.addEventListener('click', () => {
    26. window.app.ipcInvoke('cancel', { id: 2 })
    27. })
    28. upload1.addEventListener('click', () => {
    29. window.app.ipcInvoke('upload', { id: 1, url: 'https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe' })
    30. })
    31. upload2.addEventListener('click', () => {
    32. window.app.ipcInvoke('upload', { id: 2, url: 'https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe' })
    33. })
    34. window.app.ipcReceive('data-update', (data) => {
    35. console.log(data, '-------------')
    36. h1.innerHTML = data
    37. })