从零到一,用 Electron 开发桌面效率工具

从零到一,用 Electron 开发桌面效率工具Electron 已经不算新技术,最早是 github 从 Atom 编辑器衍生出来的框架。通过编写 Javascript, HTML, CSS 能快速编译出跨系统的桌面 app。Electron 的出现使得作为前端开发工程师的我们输出范围更广。 分享最近用 Electron …

Electron 已经不算新技术,最早是 github 从 Atom 编辑器衍生出来的框架。通过编写 Javascript, HTML, CSS 能快速编译出跨系统的桌面 app。Electron 的出现使得作为前端开发工程师的我们输出范围更广。

分享最近用 Electron 做的一个基于番茄工作法的小应用,由于实现难度不大,市面上已经有非常多类似的app。我们尝试用 Electron 来实现一个。

最终效果预览:

effect

🍅 工作法

番茄工作法的核心是将任务颗粒拆分到单位时间内(25分钟)可以完成,在这25分钟内专注在这个任务三,不允许做任何与任务无关的事,在任务任务完成之后可以短暂休息一会,再继续工作。

所以这个 app 的重点是让你创建任务,⏳ 25分钟,帮让 focus on 当前在做的任务。

站在巨人的肩膀上开发

尝试新技术的时候,不要从零开始学习如何搭建技术栈,先做出来,遇到问题再查。 Electron 社区有很多优秀的沉淀,工具,模板,组件,教程等等。

搜索 react 关键字,找到了 electron-react-boilerplate 这个样板库, 这个库已经集成了 react, redux, sass, flow, hmr webpack 等工具,同时准备好 electron-builder 打包工具,作为 electron 新手,我们优先选择开箱即用的工具,快速开启业务开发。

SVG 和 React Component

大概画了一下草图,准备进入开发阶段。考虑后面会用到 svg icon,先在 FlatIcon 上找些免费的图标,下载 SVG 文件。

通过 SVGR 在线工具导入 svg 内容生成 React Component 代码。(svgr 也有 cli 等工具)

用 SVG Component 的好处是可以在代码上更灵活地控制样式,相比 png 图标可交互性强,复用率高。

SVGR

托盘和托盘弹窗

这个 app 启动的时候就隐藏在托盘菜单的一角,点击的时候显示 BrowserWindow,通过 Electron 提供的方法,可以获得托盘和托盘弹窗的 Bounds 信息,设置坐标位置。

// main.js
const tray = new Tray(path.join(__dirname, '../static', 'tray.png'));

const mainWindow = new BrowserWindow({
  // ...others
  frame: false,
  resizable: true,
  transparent: true
});

const showWindow = () => {
  const { x, y } = getPositionFromActiveDisplay();
  mainWindow.setPosition(x, y, true);
  mainWindow.show();
};

const getPositionFromActiveDisplay = () => {
  const trayBounds = tray.getBounds();
  const windowBounds = mainWindow.getBounds();

  const x = Math.round(trayBounds.x + trayBounds.width / 2 - windowBounds.width / 2);
  const y = Math.round(trayBounds.y + trayBounds.height);

  return { x, y };
};

tray

👆图的三角是由前端代码绘制的,加上 frame 和 electron 背景色,应该长这样。

从零到一,用 Electron 开发桌面效率工具

渲染线程和主线程

app 需要倒计时功能,告诉用户距离任务完成时间还有多久。Electron 有渲染进程和主线程,BrowserWindow 不可见的时候,渲染进程会尽量减少消耗,所以如果 Tick 在渲染进程的话,当 app 处于后台时会出现非常大的时间偏差。这里使用 Electron 提供的 ipcMain 和 ipcRenderer 做进程通信。

在主线程每秒发送 Tick 事件

// main.js
ipcMain.once('store-ready', event => {
  const run = () => {
    setTimeout(() => {
      run();
      event.sender.send('tick');
    }, 1000);
  };
  run();
});

渲染进程就收事件并将 dispatch TICK action。

// app/index.js
const store = configureStore({
  tasks: electronStore.getTasks()
});

ipcRenderer.send('store-ready');
ipcRenderer.on('tick', () => {
  store.dispatch({
    type: TICK
  });
});

redux store 里面判断当前执行的任务计算倒计时时间。

switch  (action.type) {
  case TICK:
    return {
      ...state,
      rows: state.rows.map(task =>
          task.id === state.currentId
            ? {
                ...task,
                remain: Math.max(task.remain - 1, 0)
              }
            : task
      )
    };

数据持久存储

数据持久化有很多种方案,因为是前端浏览器,我们可以选择 localStorage, Cookie,indexDB 等等。考虑可靠性,持久化以及存储空间,还可以通过 Electron 写文件的方式,把数据写入到应用路径下。这样即使 app 被卸载了,只要数据没被清空,用户数据还在。

通过 Electron app getPath 可以获得应用存储路径

import { app } from 'electron';
app.getPath('userData');

mac 下应用 app 的路径是 /Users/user/Library/Application Support/focus。更简单的方式可以直接用开源库 electron-store,以 key-value 的格式存储 json 文件。

{
  "tasks": {
    "rows": [
      {
        "name": "任务名称",
        "id": "91ac7f05-76f4-46ea-addb-f392a3a29b54",
        "created_at": 1553398427806,
        "plan": 1500,
        "remain": 0,
        "done": true
      }
    ],
    "currentId": "91ac7f05-76f4-46ea-addb-f392a3a29b54"
  }
}

倒计时 UI

有些样式可能用 css 实现难度较大,而用 svg 的方式实现起来非常简单。比如倒计时 UI,路径圆角和路径长度用 CSS 实现复杂度较高。可以在 Sketch 上直接绘制处理,导出成 svg,直接通过 react 代码控制。

从零到一,用 Electron 开发桌面效率工具

export default function(props: Props) {
  const offset = percentage * totalLength;
  const cx =
    Math.cos(percentage * Math.PI * 2 - Math.PI * 0.5) * radius + radius;
  const cy =
    Math.sin(percentage * Math.PI * 2 - Math.PI * 0.5) * radius + radius;
  return (
    <svg>
      ...others
      <circle
        id="path-1"
        cx={cx}
        cy={cy}
        r="32"
        fill="white"
        style={{ transition: '1s linear' }}
      />
      <path
        ...others
        strokeLinecap="round"
        strokeDasharray={totalLength}
        strokeDashoffset={offset}
        style={{ transition: '1s linear' }}
      />
    </svg>
  );
}

临界状态判断

app 在任务时间结束时需要有 Notification,由于👆的 Tick 设计,判断任务是否完成可以放在 redux middleware 上。

// middlewares/tasks
export default ({ getState }) => next => action => {
  if (typeof action === 'object' && action.type === 'TICK') {
    const beforeCount = getTimeEndTaksCount(getState);
    next(action);
    const afterCount = getTimeEndTaksCount(getState);

    if (beforeCount !== afterCount) {
      new Notification('Focus,任务完成了吗?');
    }
  } else {
    next(action);
  }
};

经过一个 Tick action 之后,判断任务完成数是否有变化,并使用 HTML5 Notification 通知用户。

notification

Travis CI

功能开发完毕之后,使用 electron-builder 进行打包发布,构建之后推到 github release 下,用户可以直接在这下载到最新的包。

同样的, boilerplate 已经准备好 .travis.yml 文件,唯一需要我们操作的是在 github.com/settings/to… 上生成 token,在 www.travis-ci.org/ 构建之前配置 Environment VariablesGH_TOKEN

从零到一,用 Electron 开发桌面效率工具

tirgger build, 成功之后就能看到构建成功过的包,下载使用

从零到一,用 Electron 开发桌面效率工具

总结

使用 Electron,前端开发者可以使用自己的武器构建跨系统的桌面端应用,而且不用学习其他技术,缺点是一个小小的功能打包完的体积是 70M。

这个 app 从有想法到最终实现比预期的简单,感兴趣的同学也可以自己 DIY 些小玩意儿。完整的代码在 github 上github.com/HelKyle/foc…,欢迎体验,同时也欢迎 star~

demo

从零到一,用 Electron 开发桌面效率工具

今天的文章从零到一,用 Electron 开发桌面效率工具分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18534.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注