Electron+Vue3 MAC 版日历开发记录(32)——使用vueuse

2,644 阅读2分钟

今天本来想着提交一版,但发现有一个功能没实现,那就是:每隔一段时间实时获取天气预报。

在之前的 ClockService 类中,我们使用到 setInterval(fn, 1000) 来做定时器,在当时为了一些 Typescript type 搞得焦头烂额,后来一直想着用 vueuse,这回有了理由了。

// ClockService.ts
'use strict';

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

export default class ClockService {
  format = 'MMMDo HH:mm';
  // onTickHandler: ((toString: (arg0: ClockService) => string) => void) | null = null;
  onTickHandler: ((arg0: ClockService) => void) | null = null;
  intervalId: NodeJS.Timeout | null = null;
  params: ClockSettingParams;
  constructor() {
    Moment.locale(app.getLocale());
    this.params = {} as ClockSettingParams;
    // lll MMMDo dddd HH:mm:ss
    this.setFormat('MMMDo HH:mm');
    this.start();
  }

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

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

    return this;
  }

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

    return this;
  }

  onTick(callback: ((arg0: ClockService) => void) | null): this {
    this.onTickHandler = callback;

    return this;
  }
}

useIntervalFn

Collection of essential Vue Composition Utilities 官网:vueuse.org/

有了 vueuse,我们就可以直接使用 useIntervalFn vueuse.org/shared/useI…

安装 vueuse:

yarn add @vueuse/core

首先在 setup 里重写 getWeather 方法:

const getWeather = async (location: FLocation) => {
  const weatherService = new WeatherService();
  weather.value = await weatherService.getWeathers(location);
};

紧接着就可以使用 vueuse 提供的函数了:

const changeShowWeather = ref(false);

const intervalFnOptions = reactive({
  immediate: changeShowWeather.value,
} as IntervalFnOptions);

const { pause, resume, isActive } = useIntervalFn(() => {
  getWeather(store.state.location);
}, 7200000, intervalFnOptions);

return {
  weather,
  eventService,
  visibleFullSetting,
  store,
  event,
  getWeather,
  pause,
  resume,
  isActive,
  changeShowWeather,
};

这样,我们就可以将对应的参数和函数 return 出去了。

在 watch 里,实时监听 changeShowWeather 值,随着设置里修改 changeShowWeather,就可以在此函数里重启或者停止该监听器:

  watch: {
    changeShowWeather(newval) {
      this.store.commit('changeShowWeather', newval);
      if (this.changeShowWeather) {
        this.getWeather(this.store.state.location);
        // 增加定时器,每隔2个小时更新一次天气预报
        this.resume();
      } else {
        this.pause();
      }
    },
  },

这样,就可以达到每隔两小时重新请求 getWeathers 获取天气预报了。

到此,我们使用到了 useIntervalFn

源码

学习源码是最好提升自我能力的方法,我们把源码 copy 出来给大家看看:

import { ref } from 'vue-demi'
import { tryOnUnmounted } from '../tryOnUnmounted'
import { Pausable, Fn, isClient } from '../utils'

export interface IntervalFnOptions {
  /**
   * Execute the callback immediate after calling this function
   *
   * @default true
   */
  immediate?: boolean
}

/**
 * Wrapper for `setInterval` with controls
 *
 * @param cb
 * @param interval
 * @param options
 */
export function useIntervalFn(cb: Fn, interval = 1000, options: IntervalFnOptions = {}): Pausable {
  const {
    immediate = true,
  } = options

  let timer: any = null
  const isActive = ref(false)

  function clean() {
    if (timer) {
      clearInterval(timer)
      timer = null
    }
  }

  function pause() {
    isActive.value = false
    clean()
  }

  function resume() {
    if (interval <= 0)
      return
    isActive.value = true
    clean()
    timer = setInterval(cb, interval)
  }

  if (immediate && isClient)
    resume()

  tryOnUnmounted(pause)

  return {
    isActive,
    pause,
    resume,
  }
}

接下来,我们重构刚开始说的那个 ClockService 类:

import type { Pausable } from '@vueuse/core';

export default class ClockService {
  format = 'MMMDo HH:mm';
  onTickHandler: ((arg0: ClockService) => void) | null = null;
  pausable: Pausable;
  params: ClockSettingParams;
  constructor() {
    Moment.locale(app.getLocale());
    this.params = {} as ClockSettingParams;
    // lll MMMDo dddd HH:mm:ss
    this.setFormat('MMMDo HH:mm');
    this.pausable = useIntervalFn(() => {
      if (this.onTickHandler) {
        this.onTickHandler(this);
      }
    }, 1000);
    this.start();
  }

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

    this.pausable.resume();

    return this;
  }

  stop(): this {
    this.pausable.pause();

    return this;
  }

这就很简单,直接看代码,不用再做解释了。

总结

我们完全可以直接参考 vueuse 提供的源代码,不需要引用这个插件,但我们发现还有很多地方可以用到,比如 @vueuse/electron 相关的功能 vueuse.org/electron/RE…,也可以在这个过程中,好好学习我心中的大神是如何封装函数和做开源代码的。