YIXUNFE / blog

文章区
151 stars 25 forks source link

利用 Electron 开发快速截图工具(一) #64

Open YIXUNFE opened 8 years ago

YIXUNFE commented 8 years ago

利用 Electron 开发快速截图工具(一)

上周和大家介绍了下 Electron,这周我们利用 Electron 实战开发一款简易的屏幕截图工具。先在这里罗列一下这款工具的一些需求点:


名词解释:

  • 主进程指 main.js;
  • 主界面指 index.html,是一个渲染进程;
  • 子界面,也是一个渲染进程。

这些文件名皆继承自 Electron 开胃篇(另可参阅 Electron Get Start 中的内容)。


设计思路

截图的实现核心在于获取屏幕截图,这里将会使用两个渲染进程配合实现完整功能。

我们先看看主界面的一些功能点。

界面设置

界面小巧,是指界面中仅仅包含几个按钮,比如截图、退出按钮。一般应用所具备的最小化、最大化、关闭三个按钮,我们不需要。

始终悬浮于屏幕之上,这点类似 QQ 的主界面,无论你当前使用的是哪款软件,它始终居于最上层。

Electron 中有一个比较重要的类,叫 BrowserWindow。我们需要从这个类中找寻对应的 API 以实现上述需求。

让我们来修改一下主进程文件 main.js中关于开打窗口的代码:

app.on('ready', function() {
  ...
  mainWindow = new BrowserWindow({
    width: 216, 
    height: 46, 
    resizable: false, 
    frame: false,
    alwaysOnTop: true,
    skipTaskbar: true
  });
  ...
});

这点代码的意思是,在 Electron 准备完成后,即打开一个大小为 216x46 的窗口,而且这个窗口是不可被拉伸的。

参数选项 frame:false 表示窗口是一个 Frameless Window,没有工具栏、菜单栏等。

参数选项 alwaysOnTop: true 表示窗口始终在其他窗口之前。

参数选项 skipTaskbar: true 让应用不会出现在任务栏中。


在渲染进程主文件 index.html 中,我们添加两个按钮,以便观察效果。

<ul class="items">
  <li id="capture">截图</li>
  <li id="close">关闭</li>
</ul>
html, body, ul, li {padding: 0; margin: 0;}
body {background: #f1f1f1}
.items {height: 30px; line-height: 30px; width: 200px; overflow: hidden; padding: 8px;}
.items li {border-radius: 4px; width: 80px; margin: 0 10px; height: 30px; float: left; text-align: center; line-height: 30px; list-style: none;  cursor: pointer}
.items li:hover {background: #000; color: #fff;}

效果图:

000

这里需要注意的是,我们的窗口由于没有边框部分,所以目前无法自由的拖动。在页面上添加 -webkit-app-region: drag 即可解决这个问题。

但是该属性会导致可点击按钮的点击事件难以触发,所以需要在按钮上添加 -webkit-app-region: no-drag 以提高体验。

body {-webkit-app-region: drag;}
.items li {-webkit-app-region: no-drag;}


快捷键设置

Electron 通过 globalShortcut 模块管理快捷键。用法也超级简单:

var globalShortcut = electron.globalShortcut;
globalShortcut.register('ctrl+shift+q', function () {
  mainWindow.webContents.send('global-shortcut-quit', 1);
}); 
globalShortcut.register('ctrl+shift+c', function () {
  mainWindow.webContents.send('global-shortcut-capture', 1);
});

这里我设置了两组快捷键,一个是截图,一个是退出。对应在渲染进程中的代码:

var ipc = require('ipc');
ipc.on('global-shortcut-quit', function (arg) {
  var event = new MouseEvent('click');
  document.getElementById('close').dispatchEvent(event);
});
ipc.on('global-shortcut-capture', function (arg) {
  var event = new MouseEvent('click');
  document.getElementById('capture').dispatchEvent(event);
});

ipc 模块用于实现主进程与渲染进程通信。在快捷键句柄触发时,主进程发送消息至渲染进程,渲染进程触发对应的事件句柄。


屏幕截图

Electron 为我们提供了 desktopCapturer 模块用以获取截图。查看文档

var desktopCapturer = require('electron').desktopCapturer;
desktopCapturer.getSources({types: ['window', 'screen']}, function(error, sources) {
  ...
})

上述代码最终会获得几个数据源,对应参数数组中的 windowscreenwindow 参数表示应用窗口,screen 表示屏幕窗口。另外还有一个和 tyoes 参数一起的是 thumbnailSize,默认截图的缩略图大小是 150x150

所以我们结合自身需求,代码会是这样的:

var desktopCapturer = require('electron').desktopCapturer,
  w = screen.width,
  h = screen.height

desktopCapturer.getSources({types: ['screen'], thumbnailSize: {width: w, height: h}}, function(error, sources) {
  if (error) throw error;
  localStorage['img'] = sources[0].thumbnail.toDataURL()
});

代码中我们指定缩略图即原图大小,最后将截图数据转化成 DataURL 形式存放于 localStorage 中,以便于子页面获取截图。


按钮功能

目前仅两个按钮:截图与关闭。

关闭按钮即关闭应用。由于在主进程 main.js 中已经有如下代码:

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

当所有应用窗口皆关闭时,即关闭应用。所以我们的关闭按钮只要确保主界面与子界面关闭即可。

subWindow && subWindow.close()
window.close()
此处有坑哦,在下一篇中有提及。


截图按钮的功能除了上面提到的截图,还需要打开子界面。子界面会展示屏幕截图,以便用户进一步选取其中部分进行保存或者复制黏贴。

subWindow = new BrowserWindow({width: w, height: h, resizable: false, skipTaskbar: true, frame: false, alwaysOnTop: true});
subWindow.loadURL('file://' + __dirname + '/sub.html');


这篇就讲到这里,下一篇我们将实现子界面中的选区截图等功能。


Thanks


jincdream commented 8 years ago

要是有人能大概翻译和描述下Electron Documentation就比较多人喜欢了

YIXUNFE commented 8 years ago

我们也觉得确实缺少一个组织做专门的前端技术相关的翻译工作,希望以后能有一批英文好的前端er为我们开路。