Electron+Vue3 MAC 版日历开发记录(22)——配置 Tray 显示功能

1,719 阅读3分钟

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

今天想要实现的功能,主要想法来自于以下几个截图,对我们菜单栏(Tray)的日期显示做配置:

但我们一开始没想着这么复杂 (随着项目的推荐,会不断完善),只想对 Tray 做一个合理的使用,本身菜单栏能显示的区域不大,如果占据了太多,对其他应用的显示也不友好:

对于每个人都有不同的显示数据的需要,所以完全有必要做一个 Setting 来配置 Tray 时间的显示。

增加 Setting 页面

增加一个 Setting 页面用于配置 Tray 显示的参数配置,再加上之前的 Setting,配置项增加了不少,所以在 Setting 组件里,我该用了 Naive UI 的 NTabs 标签页组件来切换不同的配置项。

先看看效果图:

具体代码主要参考官网文档来的,也比较简单:

<template>
  <n-drawer-content
    title="设置"
    closable
  >
    <n-tabs
      default-value="normalSetting"
      size="large"
    >
      <n-tab-pane
        name="normalSetting"
        tab="通用设置"
      >
        <n-space vertical>
          <h4>获取节假日</h4>
          <n-switch
            v-model:value="inputSwitchFestivalsModel"
            size="large"
            @update-value="updateFestivalsModel"
          />
          <h4>获取天气预报</h4>
          <n-switch
            v-model:value="inputSwitchWeatherModel"
            size="large"
            @update-value="updateWeatherModel"
          />
          <n-space
            v-if="inputSwitchWeatherModel"
            inline
          >
            <n-input-number
              v-model:value="longitude"
              :min="-180"
              :max="180"
              :show-button="false"
              placeholder="经度"
              @update:value="changeLocalLocation"
            />
            <n-input-number
              v-model:value="latitude"
              :min="-90"
              :max="90"
              :show-button="false"
              placeholder="纬度"
              @update:value="changeLocalLocation"
            />
          </n-space>
        </n-space>
      </n-tab-pane>
      <n-tab-pane
        name="menuSetting"
        tab="菜单栏设置"
      >
        <n-space vertical>
          <h4>显示节假日(农历)</h4>
          <n-switch
            v-model:value="trayFestivalsModel"
            size="large"
            @update-value="updateTraySetting"
          />
          <h4>显示天气预报</h4>
          <n-switch
            v-model:value="trayWeatherModel"
            size="large"
            @update-value="updateTraySetting"
          />
          <h4>显示星期</h4>
          <n-switch
            v-model:value="trayWeekModel"
            size="large"
            @update-value="updateTraySetting"
          />
          <h4>显示秒钟</h4>
          <n-switch
            v-model:value="traySecondsModel"
            size="large"
            @update-value="updateTraySetting"
          />
        </n-space>
      </n-tab-pane>
      <n-tab-pane
        name="focusSetting"
        tab="专注设置"
      >
        <n-space vertical>
          <n-slider
            v-model:value="focus_time"
            :step="5"
            :min="5"
            :max="120"
          />
          <n-button
            type="primary"
            size="large"
            @click="focus"
          >
            <template #icon>
              <n-icon>
                <caret-right-icon />
              </n-icon>
            </template>
            {{ focusLabel }}
          </n-button>
        </n-space>
      </n-tab-pane>
    </n-tabs>
  </n-drawer-content>
</template>

只要菜单栏的参数有变化,我们就直接用 electron.ipcRenderer.send 把参数推送到 Main 主线程去获取:

updateTraySetting(): void {
  window.electron.ipcRenderer.send('updateTraySetting', {
    trayFestivalsModel: this.trayFestivalsModel,
    trayWeatherModel: this.trayWeatherModel,
    trayWeekModel: this.trayWeekModel,
    traySecondsModel: this.traySecondsModel,
  });
},

配置 Tray 时间显示参数

每次获取变化的参数后,我们都需要对参数作处理,拼接成 Momentjs 可识别的格式,在这里我需要感谢 Momentjs 插件,提供了不少 format 参数配置。

moment().format('MMMM Do YYYY, h:mm:ss a'); // June 22nd 2021, 9:11:20 pm
moment().format('dddd');                    // Tuesday
moment().format("MMM Do YY");               // Jun 22nd 21
moment().format('YYYY [escaped] YYYY');     // 2021 escaped 2021
moment().format();                          // 2021-06-22T21:11:20+08:00

具体 format 拼接方法如下:

// ClockService.js
  /* {
    trayFestivalsModel: true,
    trayWeatherModel: false,
    trayWeekModel: true,
    traySecondsModel: true
  }*/
  setParams(params: any) {
    this.params = params;

    // MMMDo dddd HH:mm:ss
    let default_format = 'MMMDo ';

    if (this.params.trayWeekModel) {
      default_format = default_format.concat('dddd ');
    }

    default_format = default_format.concat('HH:mm');

    if (this.params.traySecondsModel) {
      default_format = default_format.concat(':ss');
    }

    return this.setFormat(default_format);
  }

还有一个参数是:是否显示农历:

// ClockService.js
  toString(): string {
    let showString = '';
    if (this.params.trayFestivalsModel) {
      const lunarService = new LunarService();
      const dayTextInChinese = lunarService.showNongliData(true);
      showString = showString.concat(...[dayTextInChinese, ' ']);
    }

    return showString.concat(Moment().format(this.getFormat()));
  }

这样,基本就能达到在 Setting 配置后,可以实时看到 Tray 显示的变化。

当然,在获取事件那,增加一个捕获方法:

ipcMain.on('updateTraySetting', (_, params) => {
  if (mainApp == null) {
    mainApp = new App();
  }
  mainApp.setClockParams(params);
});

具体运行效果可以 fork 代码实际看看~~

继续重构部分

今天继续昨天说的那个问题,怎么把多个 n-drawer合并成为一个:

<n-drawer
    v-model:show="visibleFullSetting"
    :width="settingDrawerWidth"
    placement="left"
  >
    <setting-sub
      v-model:changeShowWeather="changeShowWeather"
      v-model:changeShowFestivals="changeShowFestivals"
      v-model:location="location"
      @focusClick="focusClick"
    />
  </n-drawer>
  <n-drawer
    v-model:show="visibleFullDateView"
    :width="hlDrawerWidth"
    placement="left"
  >
    <date-view-sub
      v-model:date="date"
    />
  </n-drawer>
  <n-drawer
    v-model:show="visibleECSub"
    :width="ecDrawerWidth"
    placement="left"
  >
    <event-create-sub
      v-model:event="event"
      @addEventClick="addEventClick"
    />
  </n-drawer>

这里主要用到了 Vue 官网文档说的一个概念:计算属性和侦听器

Vue 提供了一种更通用的方式来观察和响应当前活动的实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这么重构之后:

<n-drawer
    v-model:show="showDrawer"
    :width="settingDrawerWidth"
    placement="left"
  >
    <setting-sub
      v-if="visibleFullSetting"
      v-model:changeShowWeather="changeShowWeather"
      v-model:changeShowFestivals="changeShowFestivals"
      v-model:location="location"
      @focusClick="focusClick"
    />
    <date-view-sub
      v-if="visibleFullDateView"
      v-model:date="date"
    />
    <event-create-sub
      v-if="visibleECSub"
      v-model:event="event"
      @addEventClick="addEventClick"
    />
  </n-drawer>
  
  // watch
  visibleFullSetting(newValue) {
  this.showDrawer = newValue || this.visibleFullDateView || this.visibleECSub;
},
visibleFullDateView(newValue) {
  this.showDrawer = this.visibleFullSetting || newValue || this.visibleECSub;
},
visibleECSub(newValue) {
  this.showDrawer = this.visibleFullSetting || this.visibleFullDateView || newValue;
},

上面代码是命令式且重复的,并且 showDrawer 是 Model 动态绑定的,本身修改不会改变这三个变量,所以我们进一步改进,将它与计算属性的版本进行比较:

  computed: {
    showDrawer(): boolean {
      return this.visibleFullSetting || this.visibleFullDateView || this.visibleECSub;
    },
  },

好很多了,不是吗?

但这时候会提示 showDrawer,是只读的,所以我们需要加入 Setter。

计算属性的 Setter

// ...
  computed: {
    showDrawer: {
      // getter
      get(): boolean {
        return this.visibleFullSetting || this.visibleFullDateView || this.visibleECSub;
      },
      // setter
      set(newValue: boolean) {
        this.visibleFullSetting = newValue;
        this.visibleFullDateView = newValue;
        this.visibleECSub = newValue;
      }
    },
  },
// ...

这么一顿操作后,如果直接点「关闭」n-drawer 按钮后,触发 set 方法,把这几个人变量重置为 false。保证代码的准确性和完整性。

小结

今晚主要完成 Tray 显示的动态配置功能和已知遗留的小尾巴继续重构。

明天我们继续今天没完成的「天气」的 Tray 展示,明天继续。未完待续!

代码已同步到 github 上了:github.com/fanly/fanly…