Electron实现简单demo

93 阅读3分钟

整体效果

image.png

整体目录结构

image.png

主窗口开发

index.js

const electron = require('electron');
const {app, BrowserWindow, Menu} = electron;
const path = require('path');
const url = require('url');

 let win = null;
 app.on('ready', () => {
     win = new BrowserWindow({
         width: 800,
         height: 600
     });
     // win.loadURL("https://baidu.com")
     win.loadURL(url.format({
         pathname: path.resolve(__dirname, './html/main.html'),
         protocol: 'file:',
         slashes: true
     }));

     // 定义菜单
     const mainMenu = Menu.buildFromTemplate(menuTemplate);
     Menu.setApplicationMenu(mainMenu);
 });

const menuTemplate = [
    // 文件菜单项
    {
        label: '文件',
        submenu: [
            {
                label: '新增信息',
            },
            {
                label: '清空信息',
            },
            {
                label: '退出',
                accelerator: process.platform == 'darwin' ? 'Command+Q' : 'Ctrl+Q',
                click: ()=> {
                    app.quit();
                }
            }
        ]
    },
    // 开发者工具菜单项
    {
        label: '开发者工具',
        submenu: [
            {
                label: '打开/关闭',
                click: (item, focusedWindow)=> {
                    focusedWindow.toggleDevTools()
                }
            },
            {
                label: '刷新一下',
                role: 'reload',
                accelerator: process.platform == 'darwin' ? 'Command+F5' : 'Ctrl+F5'
            }
        ]
    }
];

此时效果 image.png

安装cross-env模块包,帮助我们设置process环境变量

npm install cross-env --save-dev

线上及开发环境配置

package.json

{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "cross-env NODE_ENV=delevopment electron .",
    "start-prod": "cross-env NODE_ENV=production electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cross-env": "^7.0.3",
    "electron": "^21.0.0",
    "electron-packager": "^16.0.0"
  }
}
npm start // run可忽略

image.png

npm run start-prod  // run不可忽略

image.png

index.js使用process判断当前环境

const checkEnv = () => {
    let env = process.env.NODE_ENV;
    let devConfig =
        // 开发者工具菜单项
        {
            label: '开发者工具',
            submenu: [
                {
                    label: '打开/关闭',
                    click: (item, focusedWindow)=> {
                        focusedWindow.toggleDevTools()
                    }
                },
                {
                    label: '刷新一下',
                    role: 'reload',
                    accelerator: process.platform == 'darwin' ? 'Command+F5' : 'Ctrl+F5'
                }
            ]
        };
    // 开发环境
    if (env != 'production') {
        menuTemplate.push(devConfig)
    }

};

子窗口开发并打开

add.html

<!DOCTYPE html>
<html>
<head>
    <title>新增信息</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" type="text/css" href="./css/basic.css" />
</head>
<body>
<section class="form-box">
    <form>
        <label for="info">请输入信息名称</label>
        <input type="text" name="info" id="info" placeholder="请输入信息名称" autofocus />
        <button type="submit" class="btn btn-add">添加</button>
    </form>
</section>

<style type="text/css">
    .form-box{width:80%;margin:0 auto;margin-top:5px;}
    .btn-add{width:100%;margin-top:2px;}
</style>
</body>
</html>

子窗口通信 add.html

const electron = require('electron');
const { ipcRenderer } = electron;
const form = document.querySelector('form');

// submit 事件
form.addEventListener('submit',(ev) => {
    ev.preventDefault(); // 阻止刷新
    let val = document.querySelector('#info').value;
    // console.log(val);
    // 发送传递信息
    ipcRenderer.send("info:add", val);
});

index.js监听事件信息传递

index.js

// 事件监听: 监听事件信息的传递
const eventListen = () => {

    // 监听新增窗口传递过来的 信息项
    ipcMain.on('info:add',(e, val) => {
        win.webContents.send('info:add', val);
        addWin.close();
    })

};
eventListen();

主窗口通信

main.html

const electron  = require('electron');
const { ipcRenderer } = electron;
const ul = document.querySelector('#wrap');
const spaceSection = document.querySelector('.space-section');

// 接收 新增信息窗口传递过来的数据
ipcRenderer.on('info:add',(e, val) => {
    const li = document.createElement('li');
    ul.className = 'collection';
    li.className = "collection-item";
    li.innerHTML = val+' <i class="close-btn">×</i>';
    ul.append(li);
    spaceSection.style.display = 'none';
});

package.json整体代码

{
  "name": "electron-infolist",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "cross-env NODE_ENV=development electron .",
    "start-prod": "cross-env NODE_ENV=production electron .",
    "build-win": "electron-packager . info-list-app --out=dist --overwrite --platform=win32 --arch=x64 --prune=true --icon=icon/win/icon.ico",
    "build-linux": "electron-packager . info-list-app --out=dist --overwrite --platform=linux --arch=x64 --prune=true --icon=icon/linux/icon.png",
    "build-mac": "electron-packager . info-list-app --out=dist --overwrite --platform=darwin --arch=x64 --prune=true --icon=icon/mac/icon.icns"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cross-env": "^6.0.0",
    "electron": "^6.0.10",
    "electron-packager": "^13.1.1"
  }
}

index.js整体代码

const electron = require('electron');
const { app, BrowserWindow, Menu, ipcMain } = electron;
const path = require('path');
const url = require('url');

let win = null;
let addWin = null;
app.on('ready', () => {
    win = new BrowserWindow({
        width: 800, height: 600, webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });
    win.loadURL(url.format({
        pathname: path.resolve(__dirname,'./html/main.html'),
        protocol: 'file:',
        slashes: true
    }));

    // 定义菜单
    const mainMenu = Menu.buildFromTemplate(menuTemplate);
    Menu.setApplicationMenu(mainMenu);

    // 点击主窗口的关闭按钮
    win.on('closed', () => {
        app.quit();
    });
});

// 顶部菜单 模板
const menuTemplate = [
    // 文件菜单项
    {
        // 顶部菜单的名称
        label: '文件',
        // 顶部菜单下面的子菜单列表
        submenu: [
            {
                label: '新增信息',
                click: () => {
                    createAddWindow()
                }
            },
            {
                label: '清空信息',
                click: () => {
                    win.webContents.send('info:clear');
                }
            },
            { label: '退出',
                accelerator: process.platform == 'darwin' ? 'Command+D' : 'Ctrl+D',
                click: () => {
                    // 退出
                    app.quit();
                }
            }
        ]
    }
];

// 创建一个新的窗口
const createAddWindow = () => {
    addWin = new BrowserWindow({
        width: 600, height: 300, webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });
    addWin.loadURL(url.format({
        pathname: path.resolve(__dirname,'./html/add.html'),
        protocol: 'file:',
        slashes: true
    }));
};

// 检测当前环境
const checkEnv = () => {
    if(process.env.NODE_ENV == undefined){
        process.env.NODE_ENV = 'production';
    }
    let env = process.env.NODE_ENV;
    // 开发者工具菜单项
    let devConfig =  {
        label: '开发者工具',
        submenu: [
            {
                label: '打开/关闭',
                accelerator: process.platform == 'darwin' ? 'Command+I' : 'Ctrl+I',
                click: (item, focusedWindow) => {
                    focusedWindow.toggleDevTools();
                }
            },
            { label: '刷新一下',
                role: 'reload',
                accelerator: process.platform == 'darwin' ? 'Command+F5' : 'Ctrl+F5'
            }
        ]
    };
    console.log(env);
    // 开发的环境
    if(env !== 'production'){
        menuTemplate.push(devConfig);
    }
};
checkEnv();


// 事件监听: 监听事件信息的传递
const eventListen = () => {

    // 监听新增窗口传递过来的 信息项
    ipcMain.on('info:add',(e, val) => {
        win.webContents.send('info:add', val);
        addWin.close();
    })

};
eventListen();

main.html整体代码

<!DOCTYPE html>
<html>
<head>
    <title>信息列表</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" type="text/css" href="./css/basic.css" />
</head>
<body>

<!-- 标题面板 -->
<nav>
    <div class="nav-wrapper">
        <a href="#" class="brand-logo">信息列表</a>
    </div>
</nav>

<!-- 信息列表 -->
<ul id="wrap">
    <!-- <li class="collection-item"> 信息列表项001 <i class="close-btn">×</i> </li>
    <li class="collection-item"> 信息列表项002 <i class="close-btn">×</i> </li>
    <li class="collection-item"> 信息列表项003 <i class="close-btn">×</i> </li>
    <li class="collection-item"> 信息列表项004 <i class="close-btn">×</i> </li>
    <li class="collection-item"> 信息列表项005 <i class="close-btn">×</i> </li> -->
</ul>

<!-- 提示 -->
<h3 class="space-section"> 暂无信息,请添加信息 </h3>

<style type="text/css">
    .space-section{ text-align: center;color:#666;font-size:18px;height:100px;line-height: 100px; }
    ul li {position: relative;}
    .close-btn{position: absolute;width:30px;height:30px;text-align: center;cursor: pointer;font-size:25px;right: 10px;top: 7px;color:#ccc;}
    .close-btn:hover{color:#333;}
</style>

<script>
    const electron  = require('electron');
    const { ipcRenderer } = electron;
    const ul = document.querySelector('#wrap');
    const spaceSection = document.querySelector('.space-section');

    // 接收 新增信息窗口传递过来的数据
    ipcRenderer.on('info:add',(e, val) => {
        const li = document.createElement('li');
        ul.className = 'collection';
        li.className = "collection-item";
        li.innerHTML = val+' <i class="close-btn">×</i>';
        ul.append(li);
        spaceSection.style.display = 'none';
        domListener();
    });

    // 接收 清空信息的按钮事件传递
    ipcRenderer.on('info:clear',(e) => {
        ul.className = '';
        ul.innerHTML = '';
        spaceSection.style.display = 'block';
    });

    // dom 监听
    function domListener(){
        document.querySelectorAll('.close-btn').forEach(el => {
            el.addEventListener('click', function(ev){
                this.parentNode.remove();
                // 判断列表是否为空
                if(ul.children.length == 0){
                    ul.className = ''
                    // ul.classList.remove('collection')
                    spaceSection.style.display = 'block';
                }
            });
        })
    }
    domListener();


</script>
</body>
</html>

add.html整体代码

<!DOCTYPE html>
<html>
<head>
    <title>新增信息</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" type="text/css" href="./css/basic.css" />
</head>
<body>
<section class="form-box">
    <form>
        <label for="info">请输入信息名称</label>
        <input type="text" name="info" id="info" placeholder="请输入信息名称" autofocus />
        <button type="submit" class="btn btn-add">添加</button>
    </form>
</section>

<style type="text/css">
    .form-box{width:80%;margin:0 auto;margin-top:5px;}
    .btn-add{width:100%;margin-top:2px;}
</style>

<script>
    const electron = require('electron');
    const { ipcRenderer } = electron;
    const form = document.querySelector('form');

    // submit 事件
    form.addEventListener('submit',(ev) => {
        ev.preventDefault(); // 阻止刷新
        let val = document.querySelector('#info').value;
        // console.log(val);
        // 发送传递信息
        ipcRenderer.send("info:add", val);
    });

</script>
</body>
</html>

打包

image.png