// Modules to control application life and create native browser window
const { app, BrowserWindow, screen, ipcMain } = require('electron')
const path = require('path')
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 200,
height: 200,
frame: false,
webPreferences: {
// node默认会被关掉,但是我们用的是本地文件。开启没事儿
nodeIntegration: false,
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
ipcMain.handle('window-close', () => {
mainWindow.close()
})
windowMove(mainWindow)
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
/**
* 窗口移动
* @param win
*/
function windowMove(win) {
let winStartPosition = { x: 0, y: 0 };
let mouseStartPosition = { x: 0, y: 0 };
let movingInterval = null;
/**
* 窗口移动事件
*/
ipcMain.handle("window-move-open", (events, canMoving) => {
if (canMoving) {
// 读取原位置
const winPosition = win.getPosition();
winStartPosition = { x: winPosition[0], y: winPosition[1] };
mouseStartPosition = screen.getCursorScreenPoint();
// 清除
if (movingInterval) {
clearInterval(movingInterval);
}
// 新开
movingInterval = setInterval(() => {
// 实时更新位置
const cursorPosition = screen.getCursorScreenPoint();
const originX = winStartPosition.x + cursorPosition.x - mouseStartPosition.x;
const originY = winStartPosition.y + cursorPosition.y - mouseStartPosition.y;
console.log(originX, originX)
const { workArea, id } = screen.getDisplayNearestPoint({ x: originX, y: originY })
const { x, y, width, height } = workArea
// 自定义
const winWidth = 200
const winHeight = 200
const peekX = originX + winWidth
const peekY = originY + winHeight
if (originX - x > width - winWidth || originX - x < 0 || originY - y > height - winHeight || originY - y < 0) {
const { id: xOtherId } = screen.getDisplayNearestPoint({ x: peekX, y: originY })
const { id: yOtherId } = screen.getDisplayNearestPoint({ x: originX, y: peekY })
console.log('边界', id, xOtherId, yOtherId)
if (xOtherId !== id && yOtherId === id) {
if (originY - y > height - winHeight || originY - y < 0) {
console.log('边界,y轴动')
} else {
win.setPosition(originX, originY);
}
}
if (yOtherId !== id && xOtherId === id) {
if (originX - x > width - winWidth || originX - x < 0) {
console.log('边界,x轴动')
} else {
win.setPosition(originX, originY);
}
}
} else {
win.setPosition(originX, originY);
}
}, 16);
} else {
clearInterval(movingInterval);
movingInterval = null;
}
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
<link href="./styles.css" rel="stylesheet">
<title>Hello World!</title>
</head>
<body>
<div class="blank">导航条</div>
<button id="close">Close</button>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
const {
contextBridge,
ipcRenderer
} = require("electron");
contextBridge.exposeInMainWorld(
"api", {
async aa() {
await ipcRenderer.invoke('window-close')
},
async move(canMoving) {
await ipcRenderer.invoke('window-move-open', canMoving)
}
}
);
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
console.log('preload')
})
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// No Node.js APIs are available in this process because
// `nodeIntegration` is turned off. Use `preload.js` to
// selectively enable features needed in the rendering
// process.
const close = document.querySelector("#close")
close.addEventListener("click", () => {
console.log('close')
window.api.aa()
})
const blank = document.querySelector('.blank')
let prevent = function (e) { e.preventDefault() }
window.addEventListener('mousedown', (e) => {
debugger
if (e.target instanceof HTMLInputElement
|| e.target instanceof HTMLButtonElement
|| e.target instanceof HTMLTextAreaElement
) {
window.addEventListener("selectstart", prevent);
window.api.move(false);
return;
}
window.api.move(true);
})
window.addEventListener('mouseup', (e) => {
debugger
window.removeEventListener("selectstart", prevent);
window.api.move(false);
})
window.addEventListener('mouseup', () => {
window.removeEventListener("selectstart", prevent);
window.api.move(false);
})
/* styles.css */
/* Add styles here to customize the appearance of your app */
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.blank {
width: 100%;
height: 20px;
background: red;
}
html,body{
-moz-user-select: none;
-khtml-user-select: none;
user-select: none;
}