Before, because the project needs to do a desktop application, I learned some basic knowledge on bilibili and then referred to it[ https://zhuanlan.zhihu.com/p/75764907 ]This blog has built a desktop price query application of electron+vue. This article records the construction process and some problems encountered
I Fundamentals of electron
I think electron is a browser. What is displayed in it How to write is the same as how to write the usual page, but one is to open it directly with the browser and the other is to open it with the method of desktop application
preparation
1.cnpm init -y create package json
2. cnpm i electron -D installation
3. Create a new main JS entry file, write the main process code of electron here
4. Modify package Add JSON in script
"Package": "electron packer. / hello -- platform = Win32 -- arch = x64 -- icon = favicon. ICO -- out =. / out -- ASAR -- app version = 0.0.1 -- overwrite -- ignore = node_modules" use cnpm run package to package
5. Create a new html and display it on the electron window
Create an electron window to start formal learning
main.js directly refers to the main process, and html refers to the rendering process. The rendering process cannot directly use some properties of the main process, and remote is required
// main.js var electron = require('electron') var app = electron.app // Reference app var globalShortcut = electron.globalShortcut // Global shortcut var BrowserWindow = electron.BrowserWindow // Window reference var mainWindow = null // Declare the main window to open app.on('ready', () => { // Set up the window mainWindow = new BrowserWindow({ width: 900, height: 800, webPreferences: { nodeIntegration: true,// So that all node s can be used in our rendering process contextIsolation: false, enableRemoteModule: true // remote can only be used after configuration } }) // Register global functions globalShortcut.register('ctrl+e',()=>{ mainWindow.loadURL('https://jspang.com') }) // Judge whether this shortcut key is added successfully let isRegister = globalShortcut.isRegistered('ctrl+e') console.log('-----',isRegister,'-------') // If the debug mode of toggle cannot be opened in the debug panel below // mainWindow.webContents.openDevTools() // Import custom menu // require('./main/menu') // Add Web pages mainWindow.loadFile('demo7.html') //Load html page // BrowserView // Embed subpages in a page /* var BrowserView = electron.BrowserView var view = new BrowserView() mainWindow.setBrowserView(view) //view Put under the main window view.setBounds({//Set style location x:0, y:120, width:900, height:600 }) // What's in the page view.webContents.loadURL('https://www.baidu.com') */ // window.open sub window BrowserWindow / / opens a window // When closing the window, set mainwindow to null, otherwise more and more memory will be saved mainWindow.on('closed', () => { mainWindow = null }) }) app.on('will-quit',function(){ // Log out of the shortcut method before exiting this application globalShortcut.unregister('ctrl+e') //Cancel single shortcut key // globalShortcut.unregisterAll() / / cancel all shortcut keys })
// menu.js const { Menu, BrowserWindow } = require('electron') var template = [ { label: "Feng Laiyi", submenu: [ { label: 'Boutique spa', accelerator:'ctrl+n', click: () => { var win = new BrowserWindow({ width: 500, height: 500, webPreferences: { nodeIntegration: true, contextIsolation: false, } }) win.loadFile('yellow.html') win.on('closed', () => { win = null }) } }, { label: "Thai massage" } ] }, { label: "mighty wave crashing on a sandy shore", submenu: [ { label: 'Milk rose bath' }, { label: "foot massage" } ] } ] var m = Menu.buildFromTemplate(template) // Build a menu to use Menu.setApplicationMenu(m) //Setup menu
1. Test text
... <body> <button id="btn">Test text come in</button> <div id="myTest"></div> </body> <script> var fs = require('fs') window.onload = function(){ var btn = this.document.querySelector('#btn') var myTest = this.document.querySelector('#myTest') btn.onclick = function(){ fs.readFile('test.txt',(err,data) => { myTest.innerHTML = data }) } } </script>
2. Open a new window
... <body> <button id="btn">Open a new window</button> <div id="myTest"></div> </body> <script> const btn = this.document.querySelector('#btn') // This allows you to share main BrowserWindow in JS // main.js directly refers to the main process, and html refers to the rendering process. The rendering process cannot directly use some properties of the main process, and remote is required const BrowserWindow = require('electron').remote.BrowserWindow window.onload = function(){ btn.onclick = function(){ newWin = new BrowserWindow({ width:500, height:500 }) newWin.loadFile('yellow.html') newWin.on('closed',()=>{ newWin = null }) } } const {remote} = require('electron') var rightTemplate = [ {label:"paste",accelerator:'ctrl+c',}, {label:"copy",accelerator:'ctrl+v',} ] var m = remote.Menu.buildFromTemplate(rightTemplate) // Right click menu window.addEventListener('contextmenu',(e)=>{ // alert(1) e.preventDefault() m.popup({window:remote.getCurrentWindow()}) }) </script>
3. Open sub window
<body> <h1> <a id="aHref" href="https://www.baidu. Com "> Baidu</a> </h1> <button id="mybtn">Open sub window</button> <div id="mytext"></div> </body> <script> var {shell} = require('electron') var aHref = this.document.querySelector('#aHref') var mybtn = document.querySelector('#mybtn') var mytext = document.querySelector('#mytext') aHref.onclick = function(e){ e.preventDefault() // The default link will open in the current application var href = this.getAttribute('href') // This allows you to open in browser and Google browser shell.openExternal(href) } mybtn.onclick = function(){ window.open('./popup_page.html') } window.addEventListener('message',(msg)=>{ // console.log(msg) mytext.innerHTML = JSON.stringify(msg.data) }) </script> ...
<body> <h2>I'm the child window that pops up</h2> <button id="popbtn">Pass information to parent window</button> </body> <script> var popbtn = document.querySelector('#popbtn') popbtn.onclick = (e)=>{ // alert(1) window.opener.postMessage('I am the message transmitted by the sub window') } </script>
4. Open the pop-up dialog box of picture saving file
<body> <button id="openBtn">Open picture</button> <button id="saveBtn">Save file</button> <button id="messageBtn">Pop up dialog box</button> <img style="width:100%" id="images"> <script> const {dialog} = require('electron').remote const fs = require('fs') // Upload file const openBtn = document.querySelector('#openBtn') // You can also use input file js, which is electron ic's own way openBtn.onclick = function(){ dialog.showOpenDialog({ title:"Please choose your favorite photos", defaultPath:'./2.png',//You can choose to fill in the default photo path filters: [{name:'img',extensions:['png']}], buttonLabel:'Open my favorite pictures',// Set picture open button text }).then(res => { console.log(res) let images = document.querySelector('#images') images.setAttribute('src',res.filePaths[0]) }).catch(err=>{ console.log(err) }) } // Saving a file is equivalent to creating a new file. After the new file is created successfully, you can write content in it const saveBtn = document.querySelector('#saveBtn') saveBtn.onclick = function(){ dialog.showSaveDialog({ title:"Save file" }).then(res => { fs.writeFileSync(res.filePath,'jspang.com') }).catch(err=>{ console.log(err) }) } // Pop up dialog box const messageBtn = document.querySelector('#messageBtn') messageBtn.onclick = function(){ dialog.showMessageBox({ type:"warning", title:'It's up to you whether you go or not', message:"Are you going", buttons:['I want to go','i'm not coming' ] }).then(res=>{ console.log(res) // The subscript of buttons is returned }) } </script>
5. Disconnection reminder function
<body> <h2>JSPANG.com Disconnection reminder test</h2> </body> <script> // You can cut off the network and try it on the F12 debugging tool // online offline disconnection window.addEventListener('online',function(){ // It will only be triggered when the network is disconnected again alert('Come on') }) window.addEventListener('offline',function(){ alert('The network is disconnected,Leave first for a while~~') }) </script>
6. Bottom message notification
<body> <button id="notifyBtn">Notification message</button> </body> <script> var notifyBtn = document.querySelector('#notifyBtn') var option = { title:'waiter,Here comes the order,Come out to pick up guests!', body:'A senior official turned over your sign' } notifyBtn.onclick = function(){ new window.Notification(option.title,option) } </script>
7. Shear board function
<body> <div> Activation code: <span id="code">jasdfdlfjdsklfjkldsfj</span> <button id='btn'>Copy activation code</button> </div> <script> // The clipboard can be used in both the rendering process and the main process const {clipboard} = require('electron') var btn = document.querySelector('#btn') var code = document.querySelector('#code') btn.onclick = function(){ clipboard.writeText(code.innerHTML) alert('Copy successful') } </script>
II Build vue+electron project
Create vue project
vue create electron-vue-demo
custom installation
Automatic installation of electron
vue add electron-builder
During the installation process, it may get stuck due to network problems. We can forcibly end it and then execute it again
After installation, background. Will be automatically generated in src directory JS (electron code) and modify the package json
Modify package json
In package Add in JSON
"main": "background.js",
Add in scripts
"electron:build": "vue-cli-service electron:build",
"electron:serve": "vue-cli-service electron:serve",
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps"
Add in devDependencies
"electron": "^5.0.6",
"vue-cli-plugin-electron-builder": "^1.3.5",
After installing the dependency package
cnpm install
Compile and start APP
npm run electron:serve
Compilation and packaging
npm run electron:build
vue packaged separately
npm run build
Modify the electron configuration file
The configuration files of electron and vue are put together in vue config. JS configuration
Or in package Add a build: {} configuration under JSON
In Vue config. Add more configurations in JS. Other configurations can be queried on the official website
pluginOptions: { electronBuilder: { builderOptions: { "appId": "com.example.app", "productName": "Price-look-up",//The project name is also the name of the generated installation file, namely ademo exe "copyright": "Copyright © 2021",//Copyright information "directories": { "output": "./dist_out"//Output file path }, "extraResources": { "from": "./public/config.js", // Put config Copy the JS file to the resources folder so that it is not packaged "to": "./config.js" }, "win": {//win related configuration "icon": "./favicon.ico",//Icon. The current icon is in the root directory. Note that there are two pits here "target": [ { "target": "nsis",//Making installation program with nsis "arch": [ "x64"//64 bit ] } ] }, "nsis": { "oneClick": false, // One click installation "allowElevation": true, // Allow request for promotion. If false, the user must restart the installer with elevated privileges. "allowToChangeInstallationDirectory": true, // Allow to modify the installation directory "installerIcon": "./favicon.ico",// Installation Icon "uninstallerIcon": "./favicon.ico",//Uninstall Icon "installerHeaderIcon": "./favicon.ico", // Head Icon during installation "createDesktopShortcut": true, // Create desktop icon "createStartMenuShortcut": true,// Create start menu icon "shortcutName": "Price-look-up", // Icon name } } } }
In background JS can modify the webPreFerences configuration and customize the header, such as
... async function createWindow() { // Create the browser window. const win = new BrowserWindow({ width: 1000, height: 800, // frame: false, / / cancel the default header and customize the header webPreferences: { // Use pluginOptions.nodeIntegration, leave this alone // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION, nodeIntegration: true, // node can be used on render templates contextIsolation: false, // In the previous version of electron, contextIsolation was false by default, but now it is true by default, so if you want to use node, you have to change contextIsolation to false enableRemoteModule: true,// You can use remote }, icon: `${__static}/favicon.ico` }) // Register global shortcut key Ctrl+ F12 to open development tool debugging globalShortcut.register('ctrl+F12', () => { win.webContents.openDevTools() }) if (process.env.WEBPACK_DEV_SERVER_URL) { // Load the url of the dev server if in development mode await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL) if (!process.env.IS_TEST) win.webContents.openDevTools() } else { createProtocol('app') // Load the index.html when not in development win.loadURL('app://./index.html') } createMenu() } ...
Problems encountered:
1. Use require(electron) to display on the rendering template__ dirname is undefined or FS existsSync is not a function
terms of settlement:
hold const {getCurrentWindow} = require('electron').remote Change to const {getCurrentWindow} = window.require('electron').remote webpack Will compile automatically js The document should read window.require Time webpack Will not compile until node To compile
The browser will still prompt window Require is not a function error, but if you open it in the way of electron ic desktop application, it will display normal
window.require is not a function
at eval (Header_menu.vue?a063:19)
at Module.../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader-v16/dist/index.js?!./src/views/Header_menu.vue?vue&type=script&lang=js
2. We often failed in the process of running npm run electron:build packaging before. After checking, it is probably because of network problems. Some packages required for downloading electron packaging can not be downloaded. We can download them manually and then package them, or we can change them to Taobao image packaging. I changed it to Taobao image packaging and then package them successfully