Electron 集成 Vue & Vuetify 开发应用

  由于electron能够用 Nodejs 编写跨平台系统的应用软件,目标系统包括 windows、MacOs、Linux 这三大主流操作系统,因此能够省去大量的跨端开发工作。更因为能够重用 Vue 组件,因此可以编写出与 WEB 端媲美的漂亮界面,而且组件的重用更是大大的提高了开发的效率。

  VS code 作为优秀的跨平台编辑器也是前端开发不可或缺的,本次开发演示的主力编辑器。

一、项目初始化

  要electron支持Vue开发,需要做不少繁琐的配置工作,好在vue-cli的出现,使得我们可以使用现成的模板进行项目骨架的搭建。

  这里使用的是 simulatedgreg/electron-vue 这个项目模板。该项目模板的文档位于https://simulatedgreg.gitbooks.io/electron-vue/content/cn/getting_started.html

在终端窗口输入如下命令进行项目初始化

vue init simulatedgreg/electron-vue admin

项目初始化

注意:如果你使用的是 vue-cli 3 的话,需要全局安装 vue-init 才行。

yarn global add @vue/cli vue-init

二、安装依赖包

进入项目目录

cd admin

在终端窗口输入如下命令进行项目初始化

yarn

在安装依赖包的时候,因为要下载的electron依赖包较大,因此需要使用国内的镜像源,否则会因为国外站点太慢而卡在那里不动! 使用淘宝上ELECTRON_MIRROR进行依赖包的安装。 因此在 MacOs 上的依赖包安装命令如下:

ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ yarn

依赖安装

此时工程已经初始化完成。

三、运行工程

在工程文件夹内执行如下命令运行

yarn dev

开发模式运行

在 MacBook 上本地运行,程序的截图如下:

程序界面截图

四、使用 Vuetify 定制界面

  Vue 界面组件Vuetify作为Material Design的实现对各个终端具有良好的兼容性。 本文以 Vuetify 为例,其过程与方法同样适用于ElementUI等前端框架。

1. 引入 Vuetify

在终端窗口使用如下命令添加 Vuetify 的依赖,也可以参照Vuetify 快速开始

yarn add vuetify

引入Vuetify

使用 VS Code 打开工程文件夹根目录,项目目录结构如下图所示:

引入Vuetify

打开 src/main.js 添加 Vuetify 的引用

import Vue from "vue";
import axios from "axios";

import App from "./App";
import router from "./router";
import store from "./store";
//引入Vuetify及样式
import "vuetify/dist/vuetify.min.css";
import Vuetify from "vuetify";
Vue.use(Vuetify);
//

if (!process.env.IS_WEB) Vue.use(require("vue-electron"));
Vue.http = Vue.prototype.$http = axios;
Vue.config.productionTip = false;

打开src/renderer/components/LandingPage.vue将 template 部分修改成如下:

<template>
  <div>
    <v-toolbar dark color="primary">
      <v-toolbar-side-icon></v-toolbar-side-icon>
      <v-toolbar-title class="white--text">Vuetify Adminstrator</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>search</v-icon>
      </v-btn>
      <v-btn icon>
        <v-icon>apps</v-icon>
      </v-btn>
      <v-btn icon>
        <v-icon>refresh</v-icon>
      </v-btn>
      <v-btn icon>
        <v-icon>more_vert</v-icon>
      </v-btn>
    </v-toolbar>
    <main>
      <v-layout row>
        <v-flex xs12 sm6>
          <v-card>
            <v-toolbar color="cyan" dark>
              <v-toolbar-side-icon></v-toolbar-side-icon>

              <v-toolbar-title>Inbox</v-toolbar-title>

              <v-spacer></v-spacer>

              <v-btn icon>
                <v-icon>search</v-icon>
              </v-btn>
            </v-toolbar>
            <v-list two-line>
              <template v-for="(item, index) in items">
                <v-subheader v-if="item.header" :key="item.header"> {{ item.header }} </v-subheader>
                <v-divider v-else-if="item.divider" :inset="item.inset" :key="index"></v-divider>
                <v-list-tile v-else :key="item.title" avatar>
                  <v-list-tile-avatar>
                    <img :src="item.avatar" />
                  </v-list-tile-avatar>
                  <v-list-tile-content>
                    <v-list-tile-title v-html="item.title"></v-list-tile-title>
                    <v-list-tile-sub-title v-html="item.subtitle"></v-list-tile-sub-title>
                  </v-list-tile-content>
                </v-list-tile>
              </template>
            </v-list>
          </v-card>
        </v-flex>
      </v-layout>
    </main>
  </div>
</template>

<script>
  import SystemInformation from "./LandingPage/SystemInformation";

  export default {
    name: "landing-page",
    components: { SystemInformation },
    data() {
      return {
        items: [
          { header: "Today" },
          {
            avatar: "https://cdn.vuetifyjs.com/images/lists/1.jpg",
            title: "Brunch this weekend?",
            subtitle:
              "<span class='text--primary'>Ali Connors</span> &mdash; I'll be in your neighborhood doing errands this weekend. Do you want to hang out?",
          },
          { divider: true, inset: true },
          {
            avatar: "https://cdn.vuetifyjs.com/images/lists/2.jpg",
            title: 'Summer BBQ <span class="grey--text text--lighten-1">4</span>',
            subtitle: "<span class='text--primary'>to Alex, Scott, Jennifer</span> &mdash; Wish I could come, but I'm out of town this weekend.",
          },
          { divider: true, inset: true },
          {
            avatar: "https://cdn.vuetifyjs.com/images/lists/3.jpg",
            title: "Oui oui",
            subtitle: "<span class='text--primary'>Sandra Adams</span> &mdash; Do you have Paris recommendations? Have you ever been?",
          },
        ],
      };
    },
    methods: {
      open(link) {
        this.$electron.shell.openExternal(link);
      },
    },
  };
</script>

<style>
  @import url("https://fonts.cat.net/css?family=Roboto:100,300,400,500,700,900|Material+Icons");

  #wrapper {
    height: 100vh;
    padding: 60px 80px;
    width: 100vw;
  }

  #logo {
    height: auto;
    margin: 20px;
    width: 420px;
  }
</style>

2.修正运行时脚本错误

运行后发现调试控制台有 javascript 脚本错误发生,并且看起来界面有些错乱。

[Vuetify] Multiple instances of Vue

如下图所示:

引入Vuetify的运行图

经查得知是 electron 与 vuetify 集成时由于 electron 安全机制的原因导致没有正确引入 Vuetify 的 js 文件。参见:https://github.com/vuetifyjs/vuetify/issues/4068 ,相应的解决办法是:https://github.com/appurist/electrify/blob/master/.electron-vue/webpack.renderer.config.js#L21,即将.electron-vue/webpack.renderer.config.js的第 22 行的

//原来的引入模块白名单列表内只有vue
//let whiteListedModules = ['vue']
//将Vuetify加入引入模块的白名单后
let whiteListedModules = ["vue", "vuetify"];

重新运行应用,成功得到想要的漂亮界面!

成功运行图

五、安装 Vue-DevTools 调试插件

默认情况下在 MacOs 中,你需要先在 Chrome 中安装 Vue-DevTools 插件。其默认的安装位置在:

 /Users/**CurrentUsername**/Library/Application Support/Google/Chrome/Default/Extensions/nhdogjmejiglipccpnnnanhbledajbpd

我使用的是 4.1.5,故而实际路径为:

/Users/demo-user/Library/Application Support/Google/Chrome/Default/Extensions/nhdogjmejiglipccpnnnanhbledajbpd/4.1.5_0

将如下代码添加到 src/main/index.js 的 createWindow 函数中

if (process.env.NODE_ENV === "development") {
  let chromeDir = "/Users/demo-user/Library/Application Support/Google/Chrome/Default";
  let location = `${chromeDir}/Extensions/nhdogjmejiglipccpnnnanhbledajbpd/4.1.5_0`;
  BrowserWindow.addDevToolsExtension(location);
}

完整的函数代码如下:

function createWindow() {
  /**
   * Initial window options
   */
  if (process.env.NODE_ENV === "development") {
    let chromeDir = "/Users/demo-user/Library/Application Support/Google/Chrome/Default";
    let location = `${chromeDir}/Extensions/nhdogjmejiglipccpnnnanhbledajbpd/4.1.5_0`;
    BrowserWindow.addDevToolsExtension(location);
  }
  mainWindow = new BrowserWindow({
    height: 563,
    useContentSize: true,
    width: 1000,
    webPreferences: {},
  });

  mainWindow.loadURL(winURL);

  mainWindow.on("closed", () => {
    mainWindow = null;
  });
}

重新运行程序,即可看到 Vue-DevTools 已经可用了。

VueDevTools成功运行图

至此在 MacBookPro 上的 Electron 集成 Vue & Vuetify Demo 开发初步完成!