阅读 666

Electron+Vue3 MAC 版日历开发记录(7)——Menubar 时间显示

这是我参与更文挑战的第7天,活动详情查看: 更文挑战

今天开始说到了 Mac Menubar 的功能显示了。

开篇之前

Mac 有一个不太起眼却又非常有价值的地方——顶部菜单右边的 Menubar。事实上,Mac 的 Menubar 设计绝不是仅仅和 Windows 一样的展示常驻后台的程序,它依托于顶部 Menubar 的「任何情况都会存在」的特性。扩展了 Mac 下与其他应用的交互,从简单的展示到快捷的操作,用好 Menubar 是可以有效提升 Mac 效率。

所以,一样的,我也想在开发的 Mac 日历也有这样的展示功能。

Electron Tray

这里就不得不先介绍 Electron's Tray。

含义:添加图标和上下文菜单到系统通知区 官方文档:www.electronjs.org/docs/api/tr…

在本项目中,主要借鉴 Timestamp,封装成 TrayService

import type { Rectangle} from 'electron';
import { Tray, nativeImage} from 'electron';
export default class TrayService {
  tray: Tray;
  label: string;
  clickHandler: any;

  constructor() {
    this.label = '';
    const icon = nativeImage.createEmpty();
    this.tray = new Tray(icon);
    this.tray.on('click', () => (this.clickHandler || (() => {}))());
  }

  getBounds(): Rectangle {
    return this.tray.getBounds();
  }

  getLabel(): string {
    return this.label;
  }

  setLabel(label: string): this {
    if (this.tray.isDestroyed()) {
      return this;
    }

    this.tray.setTitle((this.label = label));
    return this;
  }

  onClick(fn: any): void {
    this.clickHandler = fn;
  }
}
复制代码

这里主要介绍代码:

  1. 因为我没设计好这个产品的 Icon,所以这里先置空;
  2. Label 的内容有外部控制,今天主要是显示「农历 星期 时间」三个元素信息,之后还会有更复杂的内如呈现 (这里先保密);
  3. click 事件,这个好理解,只要点击 Tray,Electron 显示或者消失;
  4. 因为要做到日历的 Electron 显示在 Menubar 正下方,所以需要借助 getBounds() 值,具体查看文档:www.electronjs.org/docs/api/tr…

Electron 显示

完成了 TrayService,现在需要把 Electron 显示在其正下方。

// Tray 点击事件,获取 getBounds(),为 Election 显示服务
this.trayService.onClick(() => {
  const bounds = this.trayService.getBounds();
  const currentMousePosition = screen.getCursorScreenPoint();
  const currentDisplay = screen.getDisplayNearestPoint(
    currentMousePosition,
  );
  this.setPosition(bounds.x + bounds.width / 2, currentDisplay.workArea.y);

  if (this.isVisible()) {
    this.hide();
  } else {
    this.show();
  }
});
复制代码

this.setPosition() 方法:

setPosition(x: number, y: number, centerToX = true): this {
this.window.setPosition(
  centerToX ? Math.round(x - this.window.getSize()[0] / 2) : x,
  y,
);
return this;
}
复制代码

内容输出

万事具备,只欠我们需要展示的内容。今天只是动态显示:「农历 星期 时间」。

为了配合动态实时显示效果,需要借助定时器功能,这里封装为:ClockService,直接看代码:

'use strict';

import { app } from 'electron';
const Moment = require('moment');
import LunarService from './LunarService';

export default class ClockService {
  format: any;
  onTickHandler: any;
  intervalId: any;
  constructor() {
    Moment.locale(app.getLocale());
    // this.setFormat("MM/DD HH:mm:ss");
    // lll
    this.setFormat('MMMDo dddd HH:mm:ss');
    this.start();
  }

  start(): this {
    if (typeof this.onTickHandler !== 'function') {
      this.onTickHandler = () => {};
    }

    this.intervalId = setInterval(() => this.onTickHandler(this), 1000);

    return this;
  }

  stop(): this {
    if (this.intervalId) {
      this.intervalId = clearInterval(this.intervalId);
    }

    return this;
  }

  onTick(callback: any): this {
    this.onTickHandler = callback;

    return this;
  }

  getFormat(): any {
    return this.format;
  }

  setFormat(format: any): this {
    if (typeof format !== 'string') {
      return this;
    }

    this.format = format;

    return this;
  }

  toString(): string {
    const lunarService = new LunarService();
    const dayTextInChinese = lunarService.showNongliData(true);
    return dayTextInChinese + ' ' + Moment().format(this.getFormat());
  }
}
复制代码

相信大家都能理解这功能的含义了。在定时器执行时,实时拿到显示的内容,填充到 Tray 的 Label 上:

this.clockService.onTick((clock: { toString: () => string; }) => {
  this.trayService.setLabel(clock.toString());
});
复制代码

所以具体只看上面的 clock.toString() 函数了,显示农历数据 + Moment() 值。

这个「农历数据」和日历每个日期里展示的一致,看之前笔记的应该不陌生了:

showNongliData(changeShowFestivals: boolean): string {

if (changeShowFestivals) {
  const solarFestivals = this.solar.getFestivals();

  if (solarFestivals.length > 0) {
    return solarFestivals.join(' ');
  }

  const lunarFestivals = this.lunar.getFestivals();

  if (lunarFestivals.length > 0) {
    return lunarFestivals.join(' ');
  }
}

return this.lunar.getJieQi() ||
`${this.lunar.getMonthInChinese()}月${this.lunar.getDayInChinese()}`;
}
复制代码

小结

哦了,最后,我们 yarn watch 直接看效果:

至于 Memubar 上内容的显示,有待于下一步不断的挖掘。

注:随着时间的推移,发现 Timestamps 使用了新的时间组件:date-fns,可能下一阶段我也会参考使用这个,目前阶段因为 FullCalendar 也是使用的 Moment.js,所以我还是沿用使用这个组件,尽可能减少第三方的引入和减小软件的体积。

今天算是开始涉猎 Electron 的开发了,至于更多的 Electron 功能我们继续折腾,未完待续!

这个项目的所有记录基本放进专栏里了,欢迎查看: Electron+Vue3 MAC 版日历开发记录

文章分类
前端