vue-electron构建多窗口页面

1.用脚手架搭建框架

参考vue-cli2的webpack模板骨架搭建的electron和Vue结合。electron-vuevue-clielectron结合的项目,比单独使用vue构建起的electron项目要方便很多.(需要使用node 7或者更高的版本)官方推荐yarn作为包的管理器,能更好的处理依赖关系,并使用yarn clean 帮助减少最后的文件构建。我们需要检查的第一项是 npm 的版本,并确保它是最新的。这个可以使用 npm-windows-upgrade 来完成。如果你使用 yarn,则可以跳过此项检查。

# 安装 vue-cli 和 脚手架样板代码
npm install -g vue-cli
vue init simulatedgreg/electron-vue my-project

# 安装依赖并运行你的程序
cd my-project
yarn # 或者 npm install
yarn run dev # 或者 npm run dev

2. 完成配置

(1).在配置文件下增加muti-page.config.js

 

const glob = require('glob');
const path = require('path');
const PAGE_PATH = path.resolve(__dirname, '../src/renderer');
const HtmlWebpackPlugin = require('html-webpack-plugin');

exports.entries = function () {
  /*用于匹配 pages 下一级文件夹中的 index.js 文件 */
  var entryFiles = glob.sync(PAGE_PATH + '/*/main.js')
  var map = {}
  entryFiles.forEach((filePath) => {
    /* 下述两句代码用于取出 pages 下一级文件夹的名称 */
    var entryPath = path.dirname(filePath)
    var filename = entryPath.substring(entryPath.lastIndexOf('\/') + 1)
    /* 生成对应的键值对 */
    map[filename] = filePath
  })
  return map
}

exports.htmlPlugin = function () {
  let entryHtml = glob.sync(PAGE_PATH + '/*/index.ejs')
  let arr = []
  entryHtml.forEach((filePath) => {
      var entryPath = path.dirname(filePath)
      var filename = entryPath.substring(entryPath.lastIndexOf('\/') + 1)
      let conf = {
        template: filePath,
        filename: filename + `/index.html`,
        chunks: ['manifest', 'vendor', filename],
        inject: true,
        nodeModules: path.resolve(__dirname, '../node_modules')
      }
      if (process.env.NODE_ENV === 'production') {
        let productionConfig = {
          minify: {
            removeComments: true,         // 移除注释
            collapseWhitespace: true,     // 删除空白符和换行符
            removeAttributeQuotes: true   // 移除属性引号 
          },
          chunksSortMode: 'dependency'    // 对引入的chunk模块进行排序
        }
        conf = {...conf, ...productionConfig} //合并基础配置和生产环境专属配置
      }
      arr.push(new HtmlWebpackPlugin(conf))
  })
  return arr
}

(2)在.electron-vue文件夹下的 webpack.renderer.config.js修改,修改后如下:

'use strict'

process.env.BABEL_ENV = 'renderer'

const path = require('path')
const { dependencies } = require('../package.json')
const webpack = require('webpack')

const BabiliWebpackPlugin = require('babili-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const {entries, htmlPlugin} = require('./muti-page.config')
/**
 * List of node_modules to include in webpack bundle
 *
 * Required for specific packages like Vue UI libraries
 * that provide pure *.vue files that need compiling
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
 */
let whiteListedModules = ['vue']
console.log()
let rendererConfig = {
  devtool: '#cheap-module-eval-source-map',
  // entry: {
  //   renderer: path.join(__dirname, '../src/renderer/main.js')
  // },
  entry: entries,
  externals: [
    ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
  ],
  module: {
    rules: [
      // {
      //   test: /\.(js|vue)$/,
      //   enforce: 'pre',
      //   exclude: /node_modules/,
      //   use: {
      //     loader: 'eslint-loader',
      //     options: {
      //       formatter: require('eslint-friendly-formatter')
      //     }
      //   }
      // },
      {
        test: /\.scss$/,
        use: ['vue-style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.sass$/,
        use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax']
      },
      {
        test: /\.less$/,
        use: ['vue-style-loader', 'css-loader', 'less-loader']
      },
      {
        test: /\.css$/,
        use: ['vue-style-loader', 'css-loader']
      },
      {
        test: /\.html$/,
        use: 'vue-html-loader'
      },
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.node$/,
        use: 'node-loader'
      },
      {
        test: /\.vue$/,
        use: {
          loader: 'vue-loader',
          options: {
            extractCSS: process.env.NODE_ENV === 'production',
            loaders: {
              sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
              scss: 'vue-style-loader!css-loader!sass-loader',
              less: 'vue-style-loader!css-loader!less-loader'
            }
          }
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          query: {
            limit: 10000,
            name: 'imgs/[name]--[folder].[ext]',
            fallback: 'file-loader',
            outputPath: './',
            publicPath: '../'
          }
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'media/[name]--[folder].[ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          query: {
            limit: 10000,
            name: 'fonts/[name]--[folder].[ext]'
          }
        }
      }
    ]
  },
  node: {
    __dirname: process.env.NODE_ENV !== 'production',
    __filename: process.env.NODE_ENV !== 'production'
  },
  plugins: [
    new VueLoaderPlugin(),
    new webpack.ProvidePlugin({
      $:'jquery',
      jQuery: 'jquery'
    }),
    new MiniCssExtractPlugin({filename: 'styles.css'}),
    // new HtmlWebpackPlugin({
    //   filename: 'index.html',
    //   template: path.resolve(__dirname, '../src/index.ejs'),
    //   minify: {
    //     collapseWhitespace: true,
    //     removeAttributeQuotes: true,
    //     removeComments: true
    //   },
    //   nodeModules: process.env.NODE_ENV !== 'production'
    //     ? path.resolve(__dirname, '../node_modules')
    //     : false
    // }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
    // 注释原来的HtmlWebpackPlugin插件代码,在数组后添加.concat(htmlPlugin())
  ].concat(htmlPlugin()),
  output: {
    // filename: '[name].js',修改filename的[name].js 为[name]/index.js,1、是为了将js文件和html文件归类在一起;2、[name].js时html访问的是绝对路径
    filename: '[name]/index.js',
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, '../dist/electron')
  },
  resolve: {
    alias: {
      '@': path.join(__dirname, '../src/renderer'),
      'vue$': 'vue/dist/vue.esm.js'
    },
    extensions: ['.js', '.vue', '.json', '.css', '.node']
  },
  target: 'electron-renderer'
}

/**
 * Adjust rendererConfig for development settings
 */
if (process.env.NODE_ENV !== 'production') {
  rendererConfig.plugins.push(
    new webpack.DefinePlugin({
      '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
    })
  )
}

/**
 * Adjust rendererConfig for production settings
 */
if (process.env.NODE_ENV === 'production') {
  rendererConfig.devtool = ''

  rendererConfig.plugins.push(
    new BabiliWebpackPlugin(),
    new CopyWebpackPlugin([
      {
        from: path.join(__dirname, '../static'),
        to: path.join(__dirname, '../dist/electron/static'),
        ignore: ['.*']
      }
    ]),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  )
}

module.exports = rendererConfig

(3)在src文件下增加渲染进程窗口的配置newPage.js


import { BrowserWindow, ipcMain, screen } from 'electron';

let win = null;
const winURL = process.env.NODE_ENV === 'development' ? 'http://localhost:9080/newPage' : `file://${__dirname}/newPage/index.html`;

function createNewPageWindow() {
  const size = screen.getPrimaryDisplay().workAreaSize; // 获取显示器的宽高
  // const winSize = win.getSize(); // 获取窗口宽高
  win = new BrowserWindow({
    width: size.width,
    height: size.height,
    minWidth: 500,
    minHeight: 130,
    type: 'toolbar', // 创建的窗口类型为工具栏窗口
    frame: true, // 要创建无边框窗口
    movable: true, // 窗口是否可以移动
    show: true, // 先不让窗口显示
    webPreferences: {
      devTools: true, // 关闭调试工具
      webSecurity: true
    },
    useContentSize: true
  });
  // 设置窗口的位置 注意x轴要桌面的宽度 - 窗口的宽度
  win.loadURL(winURL);
  // win.setPosition((size.width - winSize[0]) / 2, 350);
  // 监听渲染完成
  if (process.env.NODE_ENV === 'development') {
    win.webContents.on('did-frame-finish-load', () => {
      win.webContents.once('devtools-opened', () => {
        // win.focus();
      });
      win.webContents.openDevTools();
    });
  }
  win.once('ready-to-show', () => {
    win.show();
  });
  // 监听窗口关闭
  win.on('close', () => {
    win = null;
  });
  global.newPage = {
    id: win.id
  };
}

/**
 * 监听创建新窗口
 */
ipcMain.on('showNewPageWindow', () => {
  if (win) {
    if (win.isVisible()) {
      createNewPageWindow();
    } else {
      win.showInactive();
    }
  } else {
    createNewPageWindow();
  }
});

/**
 * 监听隐藏新窗口
 */
ipcMain.on('hideNewPageWindow', () => {
  if (win) {
    win.hide();
  }
});

(4)在主进程界面引入newPage.js

import { app, BrowserWindow } from 'electron' // eslint-disable-line

/**
 * Set `__static` path to static files in production
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
 */
if (process.env.NODE_ENV !== 'development') {
  global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') // eslint-disable-line
}
let mainWindow;
const winURL = process.env.NODE_ENV === 'development'
  ? 'http://localhost:9080/main'
  : `file://${__dirname}/main/index.html`;

function createWindow() {
  /**
   * Initial window options
   */
  mainWindow = new BrowserWindow({
    height: 563,
    useContentSize: true,
    width: 1000,
    webPreferences: {
      webSecurity: false,
      devTools: true
    },
    show: false,
    title: 'vue-electron多界面',
    autoHideMenuBar: true,
    alwaysOnTop: true
    // backgroundColor: '#2e2c29'
  });
  mainWindow.loadURL(winURL);
  mainWindow.once('ready-to-show', () => {
    mainWindow.maximize(); // 最大化
    // mainWindow.show()
  });
  mainWindow.on('closed', () => {
    mainWindow = null;
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });
  if (process.env.NODE_ENV === 'development') {
    mainWindow.webContents.on('did-frame-finish-load', () => {
      mainWindow.webContents.once('devtools-opened', () => {
        // mainWindow.focus();
      });
      mainWindow.webContents.openDevTools();
    });
  }
  // 引入newPage.js,负责悬浮窗口内主进程和渲染进程之间的通信
  require('./newPage');
  global.mainWindow = {
    id: mainWindow.id
  };
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});

/**
 * Auto Updater
 *
 * Uncomment the following code below and install `electron-updater` to
 * support auto updating. Code Signing with a valid certificate is required.
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
 */

/*
import { autoUpdater } from 'electron-updater'

autoUpdater.on('update-downloaded', () => {
  autoUpdater.quitAndInstall()
})

app.on('ready', () => {
  if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
 */

 

 

参考自:https://blog.csdn.net/weixin_41855143/article/details/89408218

 

 

Logo

前往低代码交流专区

更多推荐