From 38a8a3044535f38e03a1c3a318308fbdb91d7e41 Mon Sep 17 00:00:00 2001 From: nashaofu Date: Fri, 21 Apr 2023 20:51:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20windowCreated=20?= =?UTF-8?q?=E4=B8=8E=20windowClosed=20=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +- packages/electron-screenshots/README.md | 190 +++++++++--------- packages/electron-screenshots/src/index.ts | 14 ++ .../electron-screenshots/src/screenshots.ts | 4 +- packages/react-screenshots/README.md | 82 ++++---- 5 files changed, 163 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index fcddf1e..96cab9b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# screenshots +# 📷 screenshots -electron 截图插件和 react 截图插件,[在线示例](https://nashaofu.github.io/screenshots/) +`screenshots`是一个基于`electron`和`react`的截图插件,可以快速地实现截图功能,并支持多种截图操作,例如马赛克、文本、画笔、箭头、椭圆和矩形。此外,还提供了多语言支持,可以轻松地适配不同的语言环境。 + +在线示例:[https://nashaofu.github.io/screenshots/](https://nashaofu.github.io/screenshots/) ![react-screenshots](./screenshot.jpg) -## Features +## 特性 - 双击页面完成截图,触发`ok`事件,如果未选择截图区域,双击截取全屏,如果选择了截图区域,双击截取选择区域 - 右键点击取消截图,触发`cancel`事件 @@ -13,16 +15,16 @@ electron 截图插件和 react 截图插件,[在线示例](https://nashaofu.gi ## electron-screenshots -electron 截图插件,[electron-screenshots 文档](./packages/electron-screenshots/README.md) +[electron-screenshots](./packages/electron-screenshots/README.md)是`screenshots`的一个子项目,提供了与`electron`截图相关的功能。 -### Install +### 安装 [![NPM](https://nodei.co/npm/electron-screenshots.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/electron-screenshots/) ## react-screenshots -react 截图界面插件与`electron-screenshots`渲染 进程界面,[react-screenshots 文档](./packages/react-screenshots/README.md) +[react-screenshots](./packages/react-screenshots/README.md)是`screenshots`的另一个子项目,提供了与`react`相关的截图界面插件,可以与`electron-screenshots`渲染进程界面配合使用,当然也可以单独使用。 -### Install +### 安装 [![NPM](https://nodei.co/npm/react-screenshots.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/react-screenshots/) diff --git a/packages/electron-screenshots/README.md b/packages/electron-screenshots/README.md index b634fda..37beaff 100644 --- a/packages/electron-screenshots/README.md +++ b/packages/electron-screenshots/README.md @@ -13,42 +13,42 @@ ## Usage ```ts -import debug from 'electron-debug' -import { app, globalShortcut } from 'electron' -import Screenshots from './screenshots' +import debug from "electron-debug"; +import { app, globalShortcut } from "electron"; +import Screenshots from "./screenshots"; app.whenReady().then(() => { - const screenshots = new Screenshots() - globalShortcut.register('ctrl+shift+a', () => { - screenshots.startCapture() - screenshots.$view.webContents.openDevTools() - }) + const screenshots = new Screenshots(); + globalShortcut.register("ctrl+shift+a", () => { + screenshots.startCapture(); + screenshots.$view.webContents.openDevTools(); + }); // 点击确定按钮回调事件 - screenshots.on('ok', (e, buffer, bounds) => { - console.log('capture', buffer, bounds) - }) + screenshots.on("ok", (e, buffer, bounds) => { + console.log("capture", buffer, bounds); + }); // 点击取消按钮回调事件 - screenshots.on('cancel', () => { - console.log('capture', 'cancel1') - }) - screenshots.on('cancel', e => { + screenshots.on("cancel", () => { + console.log("capture", "cancel1"); + }); + screenshots.on("cancel", (e) => { // 执行了preventDefault // 点击取消不会关闭截图窗口 - e.preventDefault() - console.log('capture', 'cancel2') - }) + e.preventDefault(); + console.log("capture", "cancel2"); + }); // 点击保存按钮回调事件 - screenshots.on('save', (e, buffer, bounds) => { - console.log('capture', buffer, bounds) - }) - debug({ showDevTools: true, devToolsMode: 'undocked' }) -}) - -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() + screenshots.on("save", (e, buffer, bounds) => { + console.log("capture", buffer, bounds); + }); + debug({ showDevTools: true, devToolsMode: "undocked" }); +}); + +app.on("window-all-closed", () => { + if (process.platform !== "darwin") { + app.quit(); } -}) +}); ``` ### 注意 @@ -68,24 +68,24 @@ app.on('window-all-closed', () => { ```js // vue.config.js module.exports = { - publicPath: '.', + publicPath: ".", pluginOptions: { electronBuilder: { // 不打包,使用 require 加载 - externals: ['electron-screenshots'] - } - } -} + externals: ["electron-screenshots"], + }, + }, +}; ``` - esc 取消截图,可用以下代码实现按 esc 取消截图 ```js -globalShortcut.register('esc', () => { +globalShortcut.register("esc", () => { if (screenshots.$win?.isFocused()) { - screenshots.endCapture() + screenshots.endCapture(); } -}) +}); ``` - 加速截图界面展示,不销毁`BrowserWindow`,减少创建窗口的开销,可用以下代码实现。**需注意,启用该功能,会导致`window-all-closed`事件不触发,因此需要手动关闭截图窗口** @@ -95,42 +95,42 @@ globalShortcut.register('esc', () => { // 如果设置为 true 则会在第一次调用截图窗口时创建,后续调用时直接使用 // 且由于窗口不会 close,所以不会触发 app 的 `window-all-closed` 事件 const screenshots = new Screenshots({ - singleWindow: true -}) + singleWindow: true, +}); ``` ## Methods -- `Debugger`类型产考`debug`中的`Debugger`类型 +- `Debugger`类型产考[debug](https://github.com/debug-js/debug)中的`Debugger`类型 ```ts -export type LoggerFn = (...args: unknown[]) => void -export type Logger = Debugger | LoggerFn +export type LoggerFn = (...args: unknown[]) => void; +export type Logger = Debugger | LoggerFn; export interface Lang { - magnifier_position_label?: string - operation_ok_title?: string - operation_cancel_title?: string - operation_save_title?: string - operation_redo_title?: string - operation_undo_title?: string - operation_mosaic_title?: string - operation_text_title?: string - operation_brush_title?: string - operation_arrow_title?: string - operation_ellipse_title?: string - operation_rectangle_title?: string + magnifier_position_label?: string; + operation_ok_title?: string; + operation_cancel_title?: string; + operation_save_title?: string; + operation_redo_title?: string; + operation_undo_title?: string; + operation_mosaic_title?: string; + operation_text_title?: string; + operation_brush_title?: string; + operation_arrow_title?: string; + operation_ellipse_title?: string; + operation_rectangle_title?: string; } export interface ScreenshotsOpts { - lang?: Lang + lang?: Lang; // 调用日志,默认值为 debug('electron-screenshots') // debug https://www.npmjs.com/package/debug - logger?: Logger + logger?: Logger; // 是否复用截图窗口,加快截图窗口显示,默认值为 false // 如果设置为 true 则会在第一次调用截图窗口时创建,后续调用时直接使用 // 且由于窗口不会 close,所以不会触发 app 的 `window-all-closed` 事件 - singleWindow?: boolean + singleWindow?: boolean; } ``` @@ -147,39 +147,41 @@ export interface ScreenshotsOpts { ```ts interface Bounds { - x: number - y: number - width: number - height: number + x: number; + y: number; + width: number; + height: number; } export interface Display { - id: number - x: number - y: number - width: number - height: number + id: number; + x: number; + y: number; + width: number; + height: number; } export interface ScreenshotsData { - bounds: Bounds - display: Display + bounds: Bounds; + display: Display; } class Event { - public defaultPrevented = false + public defaultPrevented = false; public preventDefault(): void { - this.defaultPrevented = true + this.defaultPrevented = true; } } ``` -| 名称 | 说明 | 回调参数 | -| ------ | ------------ | --------------------------------------------------------------- | -| ok | 截图确认事件 | `(event: Event, buffer: Buffer, data: ScreenshotsData) => void` | -| cancel | 截图取消事件 | `(event: Event) => void` | -| save | 截图保存事件 | `(event: Event, buffer: Buffer, data: ScreenshotsData) => void` | +| 名称 | 说明 | 回调参数 | +| ------------- | ----------------------------------------------------------- | --------------------------------------------------------------- | +| ok | 截图确认事件 | `(event: Event, buffer: Buffer, data: ScreenshotsData) => void` | +| cancel | 截图取消事件 | `(event: Event) => void` | +| save | 截图保存事件 | `(event: Event, buffer: Buffer, data: ScreenshotsData) => void` | +| windowCreated | 截图窗口被创建后触发 | `($win: BrowserWindow) => void` | +| windowClosed | 截图窗口被关闭后触发,对`BrowserWindow` `closed` 事件的转发 | `($win: BrowserWindow) => void` | ### 说明 @@ -192,30 +194,30 @@ class Event { ```ts const screenshots = new Screenshots({ lang: { - magnifier_position_label: 'Position', - operation_ok_title: 'Ok', - operation_cancel_title: 'Cancel', - operation_save_title: 'Save', - operation_redo_title: 'Redo', - operation_undo_title: 'Undo', - operation_mosaic_title: 'Mosaic', - operation_text_title: 'Text', - operation_brush_title: 'Brush', - operation_arrow_title: 'Arrow', - operation_ellipse_title: 'Ellipse', - operation_rectangle_title: 'Rectangle' - } -}) - -screenshots.on('save', (e, buffer, data) => { + magnifier_position_label: "Position", + operation_ok_title: "Ok", + operation_cancel_title: "Cancel", + operation_save_title: "Save", + operation_redo_title: "Redo", + operation_undo_title: "Undo", + operation_mosaic_title: "Mosaic", + operation_text_title: "Text", + operation_brush_title: "Brush", + operation_arrow_title: "Arrow", + operation_ellipse_title: "Ellipse", + operation_rectangle_title: "Rectangle", + }, +}); + +screenshots.on("save", (e, buffer, data) => { // 阻止插件自带的保存功能 // 用户自己控制保存功能 - e.preventDefault() + e.preventDefault(); // 用户可在这里自己定义保存功能 - console.log('capture', buffer, data) -}) + console.log("capture", buffer, data); +}); -screenshots.startCapture() +screenshots.startCapture(); ``` ## Screenshot diff --git a/packages/electron-screenshots/src/index.ts b/packages/electron-screenshots/src/index.ts index d41fc2d..753f665 100644 --- a/packages/electron-screenshots/src/index.ts +++ b/packages/electron-screenshots/src/index.ts @@ -15,6 +15,20 @@ app.whenReady().then(() => { screenshots.startCapture(); }); + screenshots.on('windowCreated', ($win) => { + $win.on('focus', () => { + globalShortcut.register('esc', () => { + if ($win?.isFocused()) { + screenshots.endCapture(); + } + }); + }); + + $win.on('blur', () => { + globalShortcut.unregister('esc'); + }); + }); + // 防止不能关闭截图界面 globalShortcut.register('ctrl+shift+q', () => { app.quit(); diff --git a/packages/electron-screenshots/src/screenshots.ts b/packages/electron-screenshots/src/screenshots.ts index f8dc710..3848ac4 100644 --- a/packages/electron-screenshots/src/screenshots.ts +++ b/packages/electron-screenshots/src/screenshots.ts @@ -153,7 +153,7 @@ export default class Screenshots extends Events { // 复用未销毁的窗口 if (!this.$win || this.$win?.isDestroyed?.()) { - const windowTypes: Record = { + const windowTypes: Record = { darwin: 'panel', linux: 'dock', win32: 'toolbar', @@ -197,12 +197,14 @@ export default class Screenshots extends Events { acceptFirstMouse: true, }); + this.emit('windowCreated', this.$win); this.$win.on('show', () => { this.$win?.focus(); this.$win?.setKiosk(true); }); this.$win.on('closed', () => { + this.emit('windowClosed', this.$win); this.$win = null; }); } diff --git a/packages/react-screenshots/README.md b/packages/react-screenshots/README.md index 35b9fb0..894d601 100644 --- a/packages/react-screenshots/README.md +++ b/packages/react-screenshots/README.md @@ -11,29 +11,29 @@ 1. web 中使用 ```ts -import React, { ReactElement, useCallback } from 'react' -import Screenshots, { Bounds } from 'react-screenshots' -import url from './image.jpg' +import React, { ReactElement, useCallback } from "react"; +import Screenshots, { Bounds } from "react-screenshots"; +import url from "./image.jpg"; interface Bounds { - x: number - y: number - width: number - height: number + x: number; + y: number; + width: number; + height: number; } export default function App(): ReactElement { const onSave = useCallback((blob: Blob, bounds: Bounds) => { - console.log('save', blob, bounds) - console.log(URL.createObjectURL(blob)) - }, []) + console.log("save", blob, bounds); + console.log(URL.createObjectURL(blob)); + }, []); const onCancel = useCallback(() => { - console.log('cancel') - }, []) + console.log("cancel"); + }, []); const onOk = useCallback((blob: Blob, bounds: Bounds) => { - console.log('ok', blob, bounds) - console.log(URL.createObjectURL(blob)) - }, []) + console.log("ok", blob, bounds); + console.log(URL.createObjectURL(blob)); + }, []); return ( - ) + ); } ``` @@ -85,25 +85,25 @@ window.screenshots: GlobalScreenshots ```ts interface Bounds { - x: number - y: number - width: number - height: number + x: number; + y: number; + width: number; + height: number; } interface Lang { - magnifier_position_label: string - operation_ok_title: string - operation_cancel_title: string - operation_save_title: string - operation_redo_title: string - operation_undo_title: string - operation_mosaic_title: string - operation_text_title: string - operation_brush_title: string - operation_arrow_title: string - operation_ellipse_title: string - operation_rectangle_title: string + magnifier_position_label: string; + operation_ok_title: string; + operation_cancel_title: string; + operation_save_title: string; + operation_redo_title: string; + operation_undo_title: string; + operation_mosaic_title: string; + operation_text_title: string; + operation_brush_title: string; + operation_arrow_title: string; + operation_ellipse_title: string; + operation_rectangle_title: string; } ``` @@ -120,7 +120,7 @@ interface Lang { ### example ```js -import React from 'react' +import React from "react"; function App() { return ( @@ -132,7 +132,7 @@ function App() { onCancel={() => {}} onOk={() => {}} /> - ) + ); } ```