1. // Modules to control application life and create native browser window
    2. const { app, BrowserWindow, screen, ipcMain } = require('electron')
    3. const path = require('path')
    4. function createWindow() {
    5. // Create the browser window.
    6. const mainWindow = new BrowserWindow({
    7. width: 200,
    8. height: 200,
    9. frame: false,
    10. webPreferences: {
    11. // node默认会被关掉,但是我们用的是本地文件。开启没事儿
    12. nodeIntegration: false,
    13. preload: path.join(__dirname, 'preload.js')
    14. }
    15. })
    16. // and load the index.html of the app.
    17. mainWindow.loadFile('index.html')
    18. ipcMain.handle('window-close', () => {
    19. mainWindow.close()
    20. })
    21. windowMove(mainWindow)
    22. // Open the DevTools.
    23. // mainWindow.webContents.openDevTools()
    24. }
    25. // This method will be called when Electron has finished
    26. // initialization and is ready to create browser windows.
    27. // Some APIs can only be used after this event occurs.
    28. app.whenReady().then(() => {
    29. createWindow()
    30. app.on('activate', function () {
    31. // On macOS it's common to re-create a window in the app when the
    32. // dock icon is clicked and there are no other windows open.
    33. if (BrowserWindow.getAllWindows().length === 0) createWindow()
    34. })
    35. })
    36. // Quit when all windows are closed, except on macOS. There, it's common
    37. // for applications and their menu bar to stay active until the user quits
    38. // explicitly with Cmd + Q.
    39. app.on('window-all-closed', function () {
    40. if (process.platform !== 'darwin') app.quit()
    41. })
    42. // In this file you can include the rest of your app's specific main process
    43. // code. You can also put them in separate files and require them here.
    44. /**
    45. * 窗口移动
    46. * @param win
    47. */
    48. function windowMove(win) {
    49. let winStartPosition = { x: 0, y: 0 };
    50. let mouseStartPosition = { x: 0, y: 0 };
    51. let movingInterval = null;
    52. /**
    53. * 窗口移动事件
    54. */
    55. ipcMain.handle("window-move-open", (events, canMoving) => {
    56. if (canMoving) {
    57. // 读取原位置
    58. const winPosition = win.getPosition();
    59. winStartPosition = { x: winPosition[0], y: winPosition[1] };
    60. mouseStartPosition = screen.getCursorScreenPoint();
    61. // 清除
    62. if (movingInterval) {
    63. clearInterval(movingInterval);
    64. }
    65. // 新开
    66. movingInterval = setInterval(() => {
    67. // 实时更新位置
    68. const cursorPosition = screen.getCursorScreenPoint();
    69. const originX = winStartPosition.x + cursorPosition.x - mouseStartPosition.x;
    70. const originY = winStartPosition.y + cursorPosition.y - mouseStartPosition.y;
    71. console.log(originX, originX)
    72. const { workArea, id } = screen.getDisplayNearestPoint({ x: originX, y: originY })
    73. const { x, y, width, height } = workArea
    74. // 自定义
    75. const winWidth = 200
    76. const winHeight = 200
    77. const peekX = originX + winWidth
    78. const peekY = originY + winHeight
    79. if (originX - x > width - winWidth || originX - x < 0 || originY - y > height - winHeight || originY - y < 0) {
    80. const { id: xOtherId } = screen.getDisplayNearestPoint({ x: peekX, y: originY })
    81. const { id: yOtherId } = screen.getDisplayNearestPoint({ x: originX, y: peekY })
    82. console.log('边界', id, xOtherId, yOtherId)
    83. if (xOtherId !== id && yOtherId === id) {
    84. if (originY - y > height - winHeight || originY - y < 0) {
    85. console.log('边界,y轴动')
    86. } else {
    87. win.setPosition(originX, originY);
    88. }
    89. }
    90. if (yOtherId !== id && xOtherId === id) {
    91. if (originX - x > width - winWidth || originX - x < 0) {
    92. console.log('边界,x轴动')
    93. } else {
    94. win.setPosition(originX, originY);
    95. }
    96. }
    97. } else {
    98. win.setPosition(originX, originY);
    99. }
    100. }, 16);
    101. } else {
    102. clearInterval(movingInterval);
    103. movingInterval = null;
    104. }
    105. });
    106. }
    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'; style-src 'self' 'unsafe-inline'">
    7. <link href="./styles.css" rel="stylesheet">
    8. <title>Hello World!</title>
    9. </head>
    10. <body>
    11. <div class="blank">导航条</div>
    12. <button id="close">Close</button>
    13. <h1>Hello World!</h1>
    14. We are using Node.js <span id="node-version"></span>,
    15. Chromium <span id="chrome-version"></span>,
    16. and Electron <span id="electron-version"></span>.
    17. <!-- You can also require other files to run in this process -->
    18. <script src="./renderer.js"></script>
    19. </body>
    20. </html>
    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 {
    4. contextBridge,
    5. ipcRenderer
    6. } = require("electron");
    7. contextBridge.exposeInMainWorld(
    8. "api", {
    9. async aa() {
    10. await ipcRenderer.invoke('window-close')
    11. },
    12. async move(canMoving) {
    13. await ipcRenderer.invoke('window-move-open', canMoving)
    14. }
    15. }
    16. );
    17. window.addEventListener('DOMContentLoaded', () => {
    18. const replaceText = (selector, text) => {
    19. const element = document.getElementById(selector)
    20. if (element) element.innerText = text
    21. }
    22. for (const type of ['chrome', 'node', 'electron']) {
    23. replaceText(`${type}-version`, process.versions[type])
    24. }
    25. console.log('preload')
    26. })
    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. const close = document.querySelector("#close")
    8. close.addEventListener("click", () => {
    9. console.log('close')
    10. window.api.aa()
    11. })
    12. const blank = document.querySelector('.blank')
    13. let prevent = function (e) { e.preventDefault() }
    14. window.addEventListener('mousedown', (e) => {
    15. debugger
    16. if (e.target instanceof HTMLInputElement
    17. || e.target instanceof HTMLButtonElement
    18. || e.target instanceof HTMLTextAreaElement
    19. ) {
    20. window.addEventListener("selectstart", prevent);
    21. window.api.move(false);
    22. return;
    23. }
    24. window.api.move(true);
    25. })
    26. window.addEventListener('mouseup', (e) => {
    27. debugger
    28. window.removeEventListener("selectstart", prevent);
    29. window.api.move(false);
    30. })
    31. window.addEventListener('mouseup', () => {
    32. window.removeEventListener("selectstart", prevent);
    33. window.api.move(false);
    34. })
    1. /* styles.css */
    2. /* Add styles here to customize the appearance of your app */
    3. * {
    4. padding: 0;
    5. margin: 0;
    6. box-sizing: border-box;
    7. }
    8. .blank {
    9. width: 100%;
    10. height: 20px;
    11. background: red;
    12. }
    13. html,body{
    14. -moz-user-select: none;
    15. -khtml-user-select: none;
    16. user-select: none;
    17. }