基于vue + electron创造一个随心开发组件的跨端桌面应用(持续更新~)

7,243 阅读10分钟

我正在参加跨端技术专题征文活动,详情查看:juejin.cn/post/710123…

本文所述开源项目已获发起者(我是个提pr的)授权,想让我给他拐点star✌️

前言

身为一名热爱开源的程序员,如果自己的项目在开源社区被star是非常开心的事情,那么如果我们每天工作或者学习的时候打开电脑,就能看到我们的github情况,又或者这个时候有人送给你了一个star,那心情,立马就好起来了,除此之外,之后还会不断扩展其他的好用的组件,来丰富应用。

下面我会从这个应用的一些功能的实现细节讲起,包括初始化托盘菜单开机自启存储用户数据GitHub信息健康翻页时钟打包配置除此之外还有还有项目的使用方式功能介绍,希望可以给掘友带来帮助。

项目使用vue + electron,是为了未使用过electron,但是熟悉Vue的掘友提供可扩展开发的方式,其中项目为了掘友们可以开发出自己的桌面组件,已经在其目录下制定好了基本的布局与路由,掘友们可以据此随心开发,希望掘友们可以创造出出好玩的桌面组件。

应用初始化

在app目录入口文件main.js中我们需要如下工作:

  1. 引入模块
  2. 选择模式(因为选要有调试模式使用一些工具)
  3. 注册协议
  4. 窗口配置
  5. 就绪启动

调试模式

通过环境的判断来设置布尔值

const isDevelopment = process.env.NODE_ENV !== 'production'

通过布尔值来进行开发工具的启用,因为是使用vue+electron,所以用到了vue-devtools

app.on('ready', () => {
  if (isDevelopment && !process.env.IS_TEST) {
    try {
      installExtension(VUEJS3_DEVTOOLS)
    } catch (e) {
      console.error('Vue Devtools failed to install:', e.toString())
    }
  }
})

就绪启动

在应用初始化的ready事件中进行启动,关于app控制应用程序的事件生命周期。可以参考官方文档app | Electron (electronjs.org)

app.on('ready', async () => {
  initTray()
  appEvent()
  setTimeout(() => {
    autoWindow()
  }, 300)
  autoUpdater.checkForUpdatesAndNotify()
})

  • 初始化系统托盘:initTray()
  • 应用事件监听: appEvent()
  • 启动窗口:autoWindow()(这里需要注意的是使用了定时器是因为其用于适配Linux系统窗口不透明的问题)
  • 检查更新:autoUpdater.checkForUpdatesAndNotify()

路由

托盘菜单

electron托盘的创建是依靠Tray来实现的,所以我们第一步是创建一个Tray,参数为图标路径

let TrayMenu = new Tray(__static + '/icon.png')

之后通过Menu.buildFromTemplate创建菜单项,比如

const contextMenu = Menu.buildFromTemplate([
    { label: '插件列表', submenu: pluginMenu },
    { label: '插件自启', submenu: pluginOpen },
    { label: '退出', click: () => app.quit() },
  ])

通过我们创建的托盘实例调用setContextMenu,传入我们的菜单项,设置菜单

TrayMenu.setContextMenu(contextMenu)

最后在入口文件调用即完成托盘的初始化

开机自启

  1. 在托盘模块引入app
import { app, Tray, Menu } from 'electron'
  1. 在托盘中设置开机自启功能项
{
      label: '开机自启',
      type: 'checkbox',
      checked: app.getLoginItemSettings.openAtLogin,
      click: () => {
      
      },
},
  1. 获得是否选择开机自启的布尔值
const open = app.getLoginItemSettings.openAtLogin

4.调用setLoginItemSettingsapi设置启动

app.setLoginItemSettings({ openAtLogin: !open })

存储用户数据

由于桌面应用退出后需要保存用户的信息,vue是无法保存的,所以我使用了electron-store,在应用退出后来保存用户的github数据,并且它是以文件形式缓存数据,保存,当然我们首先npm install electron-store,这里是封装了一个storage文件模块化调用即可。

import Store from 'electron-store'

// 初始化 store
const store = new Store({
  // 版本更新初始化
  migrations: {
    '>=0.3.0': (store) => {
      store.clear()
    },
  },
})

// 获取存储值
export const cget = (node, key, def) => {
  const value = store.get(node + '.' + key)
  return value === undefined ? def : value
}

// 设置存储值
export const cset = (node, key, value) => {
  return store.set(node + '.' + key, value)
}

GitHub信息监控

数据获取

在页面组件中我们通过上面封装的函数进行数据的设置与获取,这里又封装了一下,让参数更加自由一些

// 信息获取
const get = (key, def) => {
  return cget('github', key, def)
}

// 信息保存
const set = (key, value) => {
  return cset('github', key, value)
}

在我们的data项中直接初始化设置数量,比如star数

 star: get('star', 0), // star 数
 newStar: get('star', 0), // 新 star 数

实时更新

在mounted生命周期中使用定时器调用getGithubData()函数进行数据更新,一分钟更新一次

setInterval(() => {
      this.getGithubData()
}, 60000)

数据更新

定时获取后我们是通过计算属性来拿到实时更新的加减,下面拿计算属性中的fork数更新举例

forkChange() {
      const changeNum = this.newFork - this.fork
      if (changeNum != 0) {
        this.sendNotice('fork is changed')
      }
      if (changeNum >= 0) {
        return '+' + changeNum
      } else {
        return changeNum
      }
    },

做一个数据的判断,并且如果有数据更新就触发提示函数。

翻页时钟

在苹果商店中我下载了一款翻页时钟,感觉非常好用,所以我想在插件中加入这个功能,参考了zhuanlan.zhihu.com/p/93519427的…

翻页时钟分为两个功能,一个是时钟功能,一个是翻页功能

image.png

下面我会从切换数字,**

切换数字

在翻页中的核心其实是切换数字,将切换数字封装成一个函数,在此之前,需要将时钟的状态进行一个初始化,如下,形成一个数组包含六个元素,分别对应着时钟的六个格子,false为翻转结束状态即数字未改动

let fliping = [false, false, false, false, false, false]

数字切换函数体如下

const changeNumber = (digit, num) => {
  // 正在翻转中则返回
  if (fliping[digit]) return
  fliping[digit] = true

  // 获取 DOM
  const flip = document.querySelectorAll('.flip')[digit]
  const front = document.querySelectorAll('.front')[digit]
  const back = document.querySelectorAll('.back')[digit]

  // 更改背后数字 & 增加动画
  back.setAttribute('class', `digital back n-${num}`)
  flip.classList.add('go')

  // 600ms 后清除动画 & 修改前面数字
  setTimeout(() => {
    flip.classList.remove('go')
    front.setAttribute('class', `digital front n-${num}`)
    // 翻转结束
    fliping[digit] = false
  }, 600)
}

切换数字函数中包含两个参数,digit为数组下标即要切换的格子,num为切换数字值 除此之外还需要对时钟的状态进行判断,避免出现快速连续翻转情况,其是通过fliping[digit]来判断,在此并没有采用响应式的方法,所以是直接通过DOM获取各格子并进行赋值,在翻页场景下使用双向绑定可能会有些麻烦。

定时回调

在整个翻页时钟三个功能是通过定时器的回调来进行控制的,即interval,在初始状态定义为null

let interval = null

当需要进行定时or倒计时or开启时钟时,都需要进行一个停止计时器的操作

interval && clearInterval(interval)

钟的核心理念

下面以番茄钟代码举例

const pomodoroClock = () => {
  interval && clearInterval(interval)
  // 番茄工作时间
  let pomodoro = [0, 25, 0]
  interval = setInterval(() => {
     pomodoro[2]--
     if (pomodoro[2] === -1) {
      pomodoro[2] = 59
      pomodoro[1]--
     }
     if(pomodoro[1] === -1) {
      pomodoro = [0,5,0]
     }
     // 转为字符串
     const timeStr = numToStr(pomodoro[0], 2) + numToStr(pomodoro[1], 2) + numToStr(pomodoro[2], 2)
     // 遍历时间字符串
     for (let i = 0, len = timeStr.length; i < len; i++) {
      // 判断数字是否修改
      if (timeStr[i] !== old[i]) {
        // 修改翻牌器数字
        changeNumber(i, timeStr[i])
      }
    }
    old = timeStr
  },1000)
}

时间的数据格式

数据格式在处理状态下是通过数值形式来进行处理的,比如说在番茄钟的倒计时减法,初始状态下是使用以数值为数组元素的数组进行一个时间的初始化,再通过字符串转换,将数值形式的时间转换为字符串再通过遍历循环来进行时间的更新,计时和时钟都是根据这个进行翻页。

数据留存

因为这个翻页时钟开发了三个时间功能,所以在功能切换上肯定会存在更新问题,所以特别要注意的是需要使用old来对数据进行一个留存,比如在时钟与番茄中的切换上在没有留存的情况下会导致数据不更新问题,所以在时钟,番茄钟,倒计时要留存数据比如番茄钟的 old = timeStr,还有就是因为在判断时间更新的情况下是需要用到old来进行判断的

时间的回溯与流逝

番茄钟和计时器其本质是时间的回溯与流逝,所以在数据判断上需要一个对时分秒的判断与更改 时间前进就对60秒1分进位,60分1时进位,时间倒退则为,0秒分减位,以此类推,如上述番茄钟

 if (pomodoro[2] === -1) {
      pomodoro[2] = 59
      pomodoro[1]--
}

打包配置

因为是基于vue+electron,所以打包需要在vue.config.json进行配置

  electronBuilder: {
      nodeIntegration: true,
      mainProcessFile: 'app/main.js',
      rendererProcessFile: 'pages/main.js',
      builderOptions: {
        productName: 'Monit',
        appId: 'com.fzf404.monit',
        artifactName: '${productName}-${version}-${os}-${arch}.${ext}',
        linux: {
          target: 'AppImage',
          publish: ['github'],
        },
        mac: {
          target: {
            target: 'dmg',
            arch: ['x64', 'arm64'],
          },
        },
      },
    },

配置了主进程和渲染进程的入口文件路径,以及相关的构建选项

  • 主进程入口: mainProcessFile
  • 渲染进程入口:rendererProcessFile
  • 构建选项: builderOptions
    • 打包后exe文件前缀: productName
    • 包名:appId
    • 工件文件名模板:artifactName
    • 不同端口的打包形式:linux&mac&win

如何使用

掘友们想基于现在的版本继续向上开发,比如说:一个实时监测掘金信息的桌面应用(我也想这么干来着)

克隆下来二次开发:项目传送门:监控github信息的桌面小组件 (github.com)

又或者直接下载使用,支持linux,window,mac

  1. 下载地址: fzf404/Monit (github.com)
  2. 当前版本(0.2.4):

🚨 v0.3.0 版本前的最终版,v0.3.0 起会引入插件机制,除 Github 外还支持其他平台及电脑控制。

✨ Mac 系统安装可能会提示 Monit.app 已损坏,请参考 项目中README.md 中的 安装 部分

🚑 目前只支持 Windows 端自动检查更新

✨ 支持了各平台的开机自启,增加了消息通知功能

♿ 菜单栏增加了 开机自启 和 消息通知 的开关

功能介绍

github信息实时监测

image.png

  1. 启动或点击右上角设置按钮会弹出信息模态框,输入你的github用户名即可(说起来还可以监测其他人的github信息)

image.png

  1. 左上角第三个按钮的作用分别为是退出,隐藏,置顶/取消置顶

  2. 左侧依次为用户获得的follower、star、fork总数并可以显示实时动态

  3. 当数字变动时点击可查看变动详情

  4. 右侧为全部仓库及star数,点击可跳转到浏览器查看仓库详情,仓库列表可以滚动

  5. 网络异常时右上角红色图标会有一个断网指示

翻页时钟

WPS图片拼图.png

翻页时钟共分为三个功能,一个功能为时钟,另一个为计时,还有一个为番茄钟(未上线)其中时钟和计时功能是通过按钮控制的

下一步的想法

  1. 音乐播放器❌
  2. todo待办项❌
  3. bilibili创作监测❌
  4. 掘金创作信息监测❌
  5. 翻页时钟✅
  6. 计数器✅ 目前项目中初步搭建好了todo还有bilibili的文件,如果掘友感兴趣可以进行二次开发并提pr。

最后

关于electron,我这几天也在社区中看到一些好文章比如说

如果喜欢这款跨端监测github桌面应用软件,欢迎star与一键三连😍

小活动

如果掘友们有好的其他功能想法欢迎在评论区中进行留言并点赞,在6月十五号我会抽出一名幸运掘友分别送出克里克抱枕!!!

幸运掘友

image.png

image.png 恭喜中奖掘友,请留下你的联系方式我会和你联系并将克里克抱枕邮寄给你!!!