js-screen-shot

likaiaMIT更新放缓

原生 JS 实现的 Web 端截图插件,支持在浏览器里自定义选区、框选和编辑截图,适合需要网页内截屏能力的应用直接集成。

web端自定义截图插件(原生JS版)

v2.0.2发布于 2026-05-18 15:19 UTC1,000star136fork同步于 2026-11-07 07:33 UTC

怎么上手

由 README 提炼,执行前请确认
pnpm add js-web-screen-shot
# or
npm install js-web-screen-shot --save
硬件要求按 README 说明

README 未说明,插件为纯前端 JS 实现,可在任意支持 JS 的设备上运行

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

原生 JS 编写的 Web 端自定义截图插件,不依赖第三方库,可在任意支持 JS 的设备上运行

原生 JS 实现的 Web 端截图插件,支持在浏览器里自定义选区、框选和编辑截图,适合需要网页内截屏能力的应用直接集成。

核心能力

  • 支持 display-media、dom、snapdom、image 等多种截图来源
  • 内置矩形、圆形、箭头、涂鸦、马赛克、文本等标注工具
  • 提供撤销、下载、确认保存及截图完成回调
  • 兼容移动端触屏,移动端使用 html2canvas 模式
  • 支持 Electron 通过 injected-stream 传入屏幕流

容易踩的坑

使用 webrtc 模式或写入剪切板功能需网站运行在 https 或 localhost 环境;实例化插件必须等 DOM 加载完成,否则无法正常工作;移动端需在 head 中设置 viewport 禁止缩放,否则撤销时双击会放大界面

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v2.0.2
  1. v2.0.2最新正式版2026-05-18 · 2026-05-18 15:19 UTC

    Release v2.0.2

  2. v2.0.12026-05-14 · 2026-05-14 14:29 UTC
    查看更新说明

    Release v2.0.1

  3. v2.0.02026-05-12 · 2026-05-12 16:02 UTC
    查看更新说明

    Release v2.0.0

  4. v1.9.9-rc.29.t2025-10-29 · 2025-10-29 06:13 UTC

    这个版本没有写更新说明。

  5. v1.9.9-rc.272025-05-13 · 2025-05-13 15:25 UTC

    这个版本没有写更新说明。

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    js-web-screen-shot · npm pnpm github

    web端自定义截屏插件(原生JS版),运行视频:实现web端自定义截屏功能 ,效果图如下:截屏效果图

    写在前面

    关于此插件的更多介绍以及实现原理请移步:

    注意⚠️:本文档并非最新的,最新文档请移步官网

    插件安装

    pnpm add js-web-screen-shot
    
    # or
    
    npm install js-web-screen-shot --save
    

    插件使用

    由于插件采用原生js编写且不依赖任何第三方库,因此它可以在任意一台支持js的设备上运行。

    注意⚠️: 如果需要使用插件的webrtc模式或者截图写入剪切板功能,需要你的网站运行在https环境或者localhost环境。当然,也可以通过修改浏览器设置的方式实现在所有环境下都能运行。步骤如下: 1.打开谷歌浏览器,在地址栏输入chrome://flags/#unsafely-treat-insecure-origin-as-secure 2.在打开的界面中:下拉框选择enabled,地址填写你的项目访问路径。 img.png

    import形式使用插件

    • 在需要使用截屏插件的业务代码中导入插件
    import ScreenShot from "js-web-screen-shot";
    
    • 在业务代码中使用时实例化插件即可
    new ScreenShot();
    

    ⚠️注意:实例化插件时一定要等dom加载完成,否则插件无法正常工作。

    cdn形式使用插件

    • 将插件的dist文件夹复制到你的项目中
    • 使用script标签引入dist目录下的screenShotPlugin.umd.js文件
    <script src="./screenShotPlugin.umd.js"></script>
    
    • 在业务代码中使用时实例化插件即可
    // 截图确认按钮回调函数
    const callback = ({base64, cutInfo})=>{
      console.log(base64, cutInfo);
    }
    // 截图取消时的回调函数
    const closeFn = ()=>{
      console.log("截图窗口关闭");
    }
    new screenShotPlugin({
      capture: {
        source: "display-media"
      },
      completeCallback: callback,
      closeCallback: closeFn
    });
    

    ⚠️注意:实例化插件时一定要等dom加载完成,否则插件无法正常工作。

    推荐的 capture 配置

    从 2.0.0 开始,推荐优先使用 capture 来描述截图来源与渲染策略:

    new ScreenShot({
      capture: {
        source: "display-media",
        render: "browser-frame"
      }
    });
    

    capture 支持的配置如下:

    • source
      • display-media 浏览器原生屏幕捕获
      • injected-stream 外部传入屏幕流,适合 Electron
      • dom 使用 html2canvas 渲染当前页面
      • snapdom 使用 SnapDOM 渲染当前页面
      • image 使用外部传入的图片内容
    • render
      • browser-frame 当前标签页截图
      • window-frame 窗口截图
    • cursor
      • 屏幕捕获流是否包含鼠标指针,值为 never | motion | always,默认 never
      • 仅对 source: "display-media" 生效;injected-stream 模式下需要在创建外部流时自行处理
    • stream
      • 当 source 为 injected-stream 时必传
    • imageSrc
      • 当 source 为 image 时必传
    • snapdom
      • 当 source 为 snapdom 时可传,值为 SnapDOM 导出的 snapdom 对象;不传时会读取 window.snapdom
    • snapdomOptions
      • 当 source 为 snapdom 时可传,值为 SnapDOM 的截图配置

    旧参数 enableWebRtc、screenFlow、imgSrc、wrcWindowMode 仍然兼容,但已经进入废弃迁移阶段。新项目请直接使用 capture,旧参数将在后续版本中移除。

    electron环境下使用插件

    由于electron环境下无法直接调用webrtc来获取屏幕流,因此需要调用者自己稍作处理,具体做法如下所示:

    • 直接获取设备的窗口,主线程发送一个IPC消息handle
    // electron主线程
    import { desktopCapturer, webContents } from "electron";
    
    // 修复electron18.0.0-beta.5 之后版本的BUG: 无法获取当前程序页面视频流
    const selfWindws = async () =>
            await Promise.all(
                    webContents
                            .getAllWebContents()
                            .filter(item => {
                              const win = BrowserWindow.fromWebContents(item);
                              return win && win.isVisible();
                            })
                            .map(async item => {
                              const win = BrowserWindow.fromWebContents(item);
                              const thumbnail = await win?.capturePage();
                              // 当程序窗口打开DevTool的时候  也会计入
                              return {
                                name:
                                        win?.getTitle() + (item.devToolsWebContents === null ? "" : "-dev"), // 给dev窗口加上后缀
                                id: win?.getMediaSourceId(),
                                thumbnail,
                                display_id: "",
                                appIcon: null
                              };
                            })
            );
    
    // 获取设备窗口信息
    ipcMain.handle("IPC消息名称", async (_event, _args) => {
      return [
        ...(await desktopCapturer.getSources({ types: ["window", "screen"] })),
        ...(await selfWindws())
      ];
    });
    
    • 渲染线程(前端)发送消息封装处理(相应写法自己调整)
    // xxx.ts
    export const getDesktopCapturerSource = async () => {
      return await window.electron.ipcRenderer.invoke<Electron.DesktopCapturerSource[]>("IPC消息名称", []);
    }
    
    • 获取指定窗口的媒体流
    // yyy.ts
    export function getInitStream(source: any): Promise<MediaStream | null> {
        return new Promise((resolve, _reject) => {
            // 获取指定窗口的媒体流
            // 此处遵循的是webRTC的接口类型  暂时TS类型没有支持  只能断言成any
            (navigator.mediaDevices as any).getUserMedia({
                audio: false,
                video: {
                    mandatory: {
                        chromeMediaSource: 'desktop',
                        chromeMediaSourceId: source.id
                    },
                }
            }).then((stream: MediaStream) => {
                resolve(stream);
            }).catch((error: any) => {
                console.log(error);
                resolve(null);
            })
        });
    }
    
    • 前端调用设备窗口信息
    import { getDesktopCapturerSource } from "xxx.ts";
    import { getInitStream } from "yyy.ts";
    import ScreenShot from "js-web-screen-shot";
    
    export const doScreenShot = async ()=>{
      // 下面这两块自己考虑  
      const sources = await getDesktopCapturerSource(); // 这里返回的是设备上的所有窗口信息
      // 这里可以对`sources`数组下面id进行判断  找到当前的electron窗口  这里为了简单直接拿了第一个
      const stream = await getInitStream(sources[0]);
    
      new ScreenShot({
        capture: {
          source: "injected-stream",
          stream: stream!
        },
        level: 999,
      });
    }
    

    capture.cursor 只会影响浏览器原生 display-media 捕获。Electron 通过 capture.source = "injected-stream" 传入的流已经在外部创建,插件无法再从流里移除鼠标指针。

    如果 Electron 截图底图里仍然出现鼠标指针,可以在调用侧用 @nut-tree/nut-js 做兜底:截图前保存当前鼠标位置并移出屏幕区域,等 triggerCallback 触发后再移回。这个逻辑需要放在 Electron 有 Node 能力的一侧执行,并按系统要求授予辅助功能/自动化权限。

    import ScreenShot from "js-web-screen-shot";
    import { mouse, Point, straightTo } from "@nut-tree/nut-js";
    import { getDesktopCapturerSource } from "xxx.ts";
    import { getInitStream } from "yyy.ts";
    
    export const doScreenShotWithoutCursor = async () => {
      const previousPosition = await mouse.getPosition();
      await mouse.move(straightTo(new Point(-100, -100)));
    
      let cursorRestored = false;
      const restoreCursor = async () => {
        if (cursorRestored) return;
        cursorRestored = true;
        await mouse.move(straightTo(previousPosition));
      };
    
      const sources = await getDesktopCapturerSource();
      const stream = await getInitStream(sources[0]);
    
      new ScreenShot({
        capture: {
          source: "injected-stream",
          stream: stream!
        },
        triggerCallback: restoreCursor,
        cancelCallback: restoreCursor,
        closeCallback: restoreCursor,
        level: 999
      });
    };
    

    如果你的多屏坐标不允许负数位置,可以把 new Point(-100, -100) 换成主屏幕右下角外侧或项目里确认过的屏幕外坐标。

    感谢 @Vanisper 提供的在electron环境下使用本插件的兼容思路。

    使用 electron 编写 Mac 软件

    Mac 全屏场景下,系统菜单栏可能会覆盖截图工具栏。可以通过 menuBarHeight 设置菜单栏高度,插件在计算全屏工具栏位置时会扣除这部分高度。

    screenShotIns = new ScreenShot({
      menuBarHeight: 22
    });
    

    menuBarHeight 使用逻辑像素,常见 Mac 菜单栏高度是 22,Retina 屏幕视觉尺寸不变;如果开启系统缩放、辅助功能大字号,或使用刘海屏 MacBook,可以按实际项目微调到 24 或更高。

    electron示例代码

    如果你看完上个章节的使用方法,依然不是很理解的话,这里准备了一份在electron环境下使用本插件的demo,请移步electron-js-web-screen-shot-demo。

    兼容移动端

    插件对触屏设备做了兼容处理,如果你是pc端的触屏设备可以支持webrtc模式,如果是移动端那么就只能使用html2canvas模式。

    import ScreenShot from "js-web-screen-shot";
    
    const config = {
        capture: {
          source: "dom"
        }
    };
    const screenShotHandler = new ScreenShot(config);
    
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <!--禁止移动端浏览器的缩放-->
    <meta name="viewport" content="user-scalable=no">
    </head>
    <body>
    /body>
    </html>
    

    注意:在移动端使用时,需要在head标签里禁止浏览器的缩放行为,否则就会出现在使用撤销功能时,多次双击造成界面放大问题。

    Vue项目下使用乱码问题

    当你vue项目中使用h2c模式进行截图时,画布左上角可能会出现一些奇怪的字符,这是由于noscript标签导致的,将其删除即可。

    参数说明

    截图插件有一个可选参数,它接受一个对象,对象每个key的作用如下:

    • capture 推荐使用的新截图配置,值为Object类型:
      • source 截图来源,值为display-media | injected-stream | dom | snapdom | image
      • render 渲染策略,值为browser-frame | window-frame
      • cursor 屏幕捕获流是否包含鼠标指针,值为never | motion | always,默认 never,仅对 source: "display-media" 生效
      • stream 当 source 为 injected-stream 时必传,值为 MediaStream
      • imageSrc 当 source 为 image 时必传,值为 string
      • snapdom 当 source 为 snapdom 时可传,值为 SnapDOM 导出的 snapdom 对象;不传时会读取 window.snapdom
      • snapdomOptions 当 source 为 snapdom 时可传,值为 SnapDOM 的截图配置
    • enableWebRtc 已废弃。旧写法中用于控制是否启用 webrtc,值为boolean类型,值为false则使用html2canvas来截图
    • screenFlow 已废弃。旧写法中用于传入设备提供的屏幕流数据(常用于electron环境)
    • completeCallback 截图完成回调函数,值为Function类型,最右侧的对号图标点击后会将图片的base64地址与裁剪信息回传给你定义的函数,如果不传的话则会将这些数据放到sessionStorage中,你可以通过下述方式拿到他:
    sessionStorage.getItem("screenShotImg");
    
    • closeCallback 截图关闭回调函数,值为Function类型。
    • triggerCallback 截图响应回调函数,值为Function类型,使用html2canvas截屏时,页面图片过多时响应会较慢;使用webrtc截屏时用户点了分享,该函数为响应完成后触发的事件。回调函数返回一个对象,类型为: {code: number,msg: string, displaySurface: string | null,displayLabel: string | null},code为0时代表截图加载完成,displaySurface返回的的是当前选择的窗口类型,displayLabel返回的是当前选择的标签页标识,浏览器不支持时此值为null。
    • cancelCallback 取消分享回到函数,值为Function类型,使用webrtc模式截屏时,用户点了取消或者浏览器不支持时所触发的事件。回调函数返回一个对象,类型为:{code: number,msg: string, errorInfo: string},code为-1时代表用户未授权或者浏览器不支持webrtc。
    • saveCallback 保存截图回调函数,值为Function类型。回调函数中返回三个参数:
      • code 状态码,number类型,为0时代表保存成功
      • msg 消息码,string类型。
      • base64 截图的base64信息,string类型。
    • level 截图容器层级,值为number类型。
    • cutBoxBdColor 裁剪区域边框像素点颜色,值为string类型。
    • maxUndoNum 最大可撤销次数, 值为number类型
    • canvasWidth 画布宽度,值为number类型,必须与高度一起设置,单独设置无效。
    • canvasHeight 画布高度,值为number类型,必须与宽度一起设置,单独设置无效。
    • position 截图容器位置,值为{left?: number, top?: number}类型
    • clickCutFullScreen 单击截全屏启用状态,值为boolean类型, 默认为false
    • hiddenToolIco 需要隐藏的截图工具栏图标,值为Object类型,默认为{}。传你需要隐藏的图标名称,将值设为true即可,除关闭图标外,其他图标均可隐藏。可隐藏的key如下所示:
      • square 矩形绘制
      • round 圆形绘制
      • rightTop 箭头绘制
      • brush 涂鸦
      • mosaicPen马赛克工具
      • text 文本工具
      • separateLine 分割线
      • save 下载图片
      • undo 撤销工具
      • confirm 保存图片
    • showScreenData 截图组件加载完毕后,是否显示截图内容至canvas画布内,值为boolean类型,默认为false。
    • customRightClickEvent 自定义容器的右键点击事件,值为Object类型,接受2个参数:
      • state 是否拦截右键点击,值为boolean类型,默认为false。
      • handleFn 拦截后的事件处理函数,该属性为可选项,如果不传,默认行为是销毁组件。
    • imgSrc 已废弃。旧写法中用于传入截图内容(例如electron环境下已有图片数据)。“新写法”请改用 capture.imageSrc
    • loadCrossImg 是否加载跨域图片,值为boolean类型,默认为false。
    • proxyUrl 代理服务器地址,值为string类型,默认为""
    • screenShotDom 需要进行截图的容器,值为HTMLElement类型,默认使用的是body。
    • useRatioArrow 是否使用等比例箭头, 默认为false(递增变粗的箭头)。
    • imgAutoFit 是否开启图片自适应, 默认为false。如果自定义了截图内容,浏览器的缩放比例不为100%时,可以设置此参数来修复图片与蒙板大小不一致的问题。
    • cropBoxInfo 初始裁剪框,值为{ x: number; y: number; w: number; h: number }类型,默认不加载。
    • wrcReplyTime webrtc模式捕捉屏幕时的响应时间,值为number类型,默认为500ms。
    • wrcImgPosition webrtc模式下是否需要对图像进行裁剪,值为{ x: number; y: number; w: number; h: number }类型,默认为不裁剪。
    • noScroll 是否禁止页面滚动,值为boolean类型,默认为false。
    • maskColor 蒙层颜色,值为{ r: number; g: number; b: number; a: number }类型,默认为:{ r: 0; g: 0; b: 0; a: 0.6 }
    • toolPosition 工具栏展示位置,值为string类型,默认为居中展示,提供三个选项:
      • left 左对齐于裁剪框
      • center 居中对齐于裁剪框
      • right 右对齐于裁剪框
    • writeBase64 是否将截图内容写入剪切板,值为boolean类型,默认为true
    • exportOptions 截图导出配置,值为Object类型:
      • type 导出图片类型,值为image/png | image/jpeg | image/webp,默认为image/png
      • quality 导出图片质量,值为0 ~ 1之间的数字,默认为0.75。该参数主要对image/jpeg和image/webp生效,image/png通常会忽略质量参数。
    • wrcWindowMode 已废弃。旧写法中用于启用窗口截图模式。新写法请改用 capture.render = "window-frame"
    • hiddenScrollBar 是否隐藏滚动条,用webrtc模式截图时chrome 112版本的浏览器在部分系统下会挤压出现滚动条,如果出现你可以尝试通过此参数来进行修复。值为Object类型,有4个属性:
      • state: boolean; 启用状态, 默认为false
      • fillState?: boolean; 填充状态,默认为false
      • color?: string; 填充层颜色,滚动条隐藏后可能会出现空缺,需要进行填充,默认填充色为黑色。
      • fillWidth?: number; 填充层宽度,默认为截图容器的宽度
      • fillHeight?: number; 填充层高度,默认为空缺区域的高度

    使用当前标签页进行截图相对而言用户体验是最好的,但是因为chrome 112版本的bug会造成页面内容挤压导致截取到的内容不完整,因此只能采用其他方案来解决此问题了。wrcWindowMode和hiddenScrollBar都可以解决这个问题。

    • wrcWindowMode方案会更完美些,但是用户授权时会出现其他的应用程序选项,用户体验会差一些
    • hiddenScrollBar方案还是采用标签页截图,但是会造成内容挤压,底部出现空白。

    两种方案的优点与缺点讲完了,最好的办法还是希望chrome能在之后的版本更新中修复此问题。

    迁移建议

    如果你正在从旧参数迁移到新参数,可以按下面的映射来替换:

    • enableWebRtc: true -> capture.source: "display-media"
    • enableWebRtc: false -> capture.source: "dom"
    • screenFlow -> capture.source: "injected-stream" + capture.stream
    • imgSrc -> capture.source: "image" + capture.imageSrc
    • wrcWindowMode: true -> capture.render: "window-frame"
    • wrcWindowMode: false -> capture.render: "browser-frame"

    当前版本仍兼容旧参数,但运行时会给出废弃提示。建议尽快切换到 capture,旧参数将在不久的将来移除。

    上述类型中的?:为ts中的可选类型,意思为:这个key是可选的,如果需要就传,不需要就不传。

    imgSrc是url时,如果图片资源跨域了,必须让图片服务器允许跨域才能正常加载。同样的loadCrossImg设置为true时,图片资源跨域了也需要让图片服务器允许跨域。

    快捷键监听

    插件容器监听了三个快捷键,如下所示:

    • Esc,按下键盘上的esc键时,等同于点了工具栏的关闭图标。
    • Enter,按下键盘上的enter键时,等同于点了截图工具栏的确认图标。
    • Ctrl/Command + z,按下这两个组合键时,等同于点了截图工具栏的撤销图标。

    额外提供的API

    插件暴露了一些内部变量出来,便于调用者根据自己的需求进行修改。

    getCanvasController

    该函数用于获取截图容器的DOM,返回值为HTMLCanvasElement类型。

    示例代码:

    import ScreenShot from "js-web-screen-shot";
    
    const screenShotHandler = new ScreenShot();
    const canvasDom = screenShotHandler.getCanvasController();
    

    注意:如果截图容器尚未加载完毕,获取到的内容可能为null。

    destroyComponents

    该函数用于销毁截图容器,无返回值。

    示例代码:

    import ScreenShot from "js-web-screen-shot";
    
    const screenShotHandler = new ScreenShot();
    screenShotHandler.destroyComponents()
    
    completeScreenshot

    该函数用于将框选区域的截图内容写入剪切版,无返回值。

    该方法可以跟cropBoxInfo参数结合起来实现指定位置的自动截图,截图内容默认写入剪切版内,如果你想拿到截取到的base64内容可以通过completeCallback参数拿到,或者直接从sessionStorage中获取。

    该回调函数中返回的参数格式如下所示:

    • base64
    • cutInfo 裁剪框位置参数
      • startX
      • startY
      • width
      • height

    示例代码:

          const plugin = new screenShotPlugin(
            {
              clickCutFullScreen:true,
              capture: {
                source: "display-media",
                render: "window-frame"
              },
              cropBoxInfo:{x:350, y:20, w:300, h:300},
              completeCallback: ({base64, cutInfo}) => {
                console.log(base64, cutInfo);
              },
              triggerCallback:() => {
                // 截图组件加载完毕调用此方法来完成框选区域的截图
                plugin.completeScreenshot()
              }
            });
    

    注意:此方法在1.9.9版本之后不再返回字符串类型的数据,而是返回的对象格式。

    getCutBoxInfo

    该函数用于获取当前裁剪框的位置信息,返回值为一个对象:

    • startX x 点坐标
    • startY y 点坐标
    • width 裁剪框宽度
    • height 裁剪框高度

    示例代码:

    import ScreenShot from "js-web-screen-shot";
    
    const screenShotHandler = new ScreenShot();
    const info = screenShotHandler.getCutBoxInfo();
    

    工具栏图标定制

    如果你需要修改截图工具栏的图标,可以通过覆盖元素css类名的方式实现,插件内所有图标的css类名如下所示:

    • square 矩形绘制图标
    • round 圆型绘制图标
    • right-top 箭头绘制图标
    • brush 画笔工具
    • mosaicPen 马赛克工具
    • text 文本工具
    • save 保存
    • close 关闭
    • undo 撤销
    • confirm 确认

    以square为例,要修改它的图标,只需要将下述代码添加进你项目代码的样式中即可。

      .square {
        background-image: url("你的图标路径") !important;
        
        &:hover {
          background-image: url("你的图标路径") !important;
        }
        
        &:active {
          background-image: url("你的图标路径") !important;
        }
     }
    

    写在最后

    至此,插件的所有使用方法就介绍完了,该插件的Vue3版本,请移步:vue-web-screen-shot