vue3 + electron搭建一个简单的桌面端

2023年 10月 8日 37.2k 0

vue3 + electron搭建一个简单的桌面端

一、初始化

  • 技术选型

    electron22、vite、vue3

    由于electron23以及以后的版本将不会支持windows 7/8/8.1(来自),这里主要选取electron22

  • 步骤

  • 创建vite项目

    // 创建项目
    yarn create vite
    
    // 添加pina
    yarn add pinia
    
  • 安装electron以及依赖

    // 安装electron
    yarn add electron@latest
    
    // 安装nodemon,监听文件,热更新
    yarn add nodemon
    
    // 安装electron-builder打包
    yarn add electron-builder
    
    // 安装concurrently,同时执行多个命令,因为需要先启动vite再启动electron
    yarn add concurrently
    
  • 安装element-plus

    yarn add element-plus
    
  • 配置目录结构

    将页面代码与electron代码分别放在render以及electron-main文件夹下

image-20231008114802105.png

electron-main文件夹中包括

        - modules                        //模块文件夹
          - controller                   //控制窗口通信
          - preload                      // 预加载脚本
        - shortcut                       // 快捷键配置
        - tray                           // 托盘配置
        - util                           // 工具类
        - windows                        // 窗口配置
        
       
      5.  配置package.json

        // 启动模块

        "scripts": {
                "serve": "concurrently "yarn dev" "yarn start" ",
                "dev": "vite",
                "build": "vue-tsc && vite build",
                "preview": "vite preview",
                "start": "nodemon --exec electron . --watch ./ --ext .js,.html,.scss,.vue,.ts,.css",
                "dist": "electron-builder"
        },

        // 打包模块
            "build": {
                "productName": "德为影像",
                "appId": "com.dewei",
                "copyright": "@dewei",
                "asar": true,
                "directories": {
                    "output": "build"
                },
                "files": [
                    "./dist",
                    "./package.json",
                    "./src/electron-main"
                ],
                "nsis": {
                    "oneClick": false,
                    "allowElevation": true,
                    "allowToChangeInstallationDirectory": true,
                    "createDesktopShortcut": true,
                    "createStartMenuShortcut": true
                },
                "dmg": {
                    "contents": [
                        {
                            "x": 410,
                            "y": 150,
                            "type": "link",
                            "path": "/Applications"
                        },
                        {
                            "x": 130,
                            "y": 150,
                            "type": "file"
                        }
                    ]
                },
                "mac": {
                    "icon": "build/001.png"
                },
                "win": {
                    "icon": "build/001.png",
                    "target": [
                        {
                            "target": "nsis",
                            "arch": [
                                "ia32"
                            ]
                        }
                    ]
                },
                "linux": {
                    "icon": "build/001.png"
                },
                "extraResources": [
                    {
                        "from": "./public/PrintScr.exe",
                        "to": "./extraResources/PrintScr.exe"
                    },
                    {
                        "from": "./public/PrScrn.dll",
                        "to": "./extraResources/PrScrn.dll"
                    }
                ]
            },

        // 需要配置项目的主入口,以及项目信息
        "name": "mi-desktop",
        "private": true,
        "version": "0.0.0",
        "main": "src/electron-main/main.js",
        "author": "dewei",
        "description": "ceshi",

二、进程之间的通信

  • IPC通道

    electron使用ipcMain和ipcRenderer模块来定义通道经常数据传输

    通常在controller文件夹中编写各个窗口的主进程代码,在perload文件夹中编写预加载脚本。electron会在全局的window下暴露出electronAPI,在渲染器中可以使用window.electronAPI.functionName来使用预加载脚本中暴露的方法

  • 渲染器到主进程(单项)

    在主进程中通过ipcMain.on监听事件。注意:事件名称唯一

    ipcMain.on('event-name', (e, value) => {
        console.log(value)
    });
    

    在预加载脚本中

    const { contextBridge, ipcRenderer } = require('electron');
    const sendName = (value) => {
        ipcRenderer.send('event-name', value);
    };
    contextBridge.exposeInMainWorld('electronAPI', {
        sendName
    });
    

    在渲染器也就是vue文件中

    const handleSendName = async () => {
        window.electronAPI.sendName('这是名字');
    };
    
  • 渲染器到注进程(双向)

    在主进程中监听事件

    ipcMain.handle('get-url', (e,value) => {
    	 let url = ''
         if(value=='bbb'){
         	url = 'aaaa'
         }
         return url;
    });
    

    在预加载中暴露方法

    const { contextBridge, ipcRenderer } = require('electron');
    const getUrl = async (value) => {
        const url = await ipcRenderer.invoke('get-url', value);
        return url;
    };
    contextBridge.exposeInMainWorld('electronAPI', {
        getUrl
    });
    

    在渲染器中使用方法

    const urlSring = async () => {
        let url = await window.electronAPI.getUrl('bbb');
    };
    
  • 主进程到渲染器

    在主进程中发送

    mainWindow.webContents.send('send-info', info);
    

    预加载暴露方法

    const { contextBridge, ipcRenderer } = require('electron');
    const getInfo = (info) => ipcRenderer.on('send-info', info);
    contextBridge.exposeInMainWorld('electronAPI', {
        getInfo
    });
    

    渲染器中监听

    window.electronAPI.getInfo((_event, value) => {
       console.log(value)  
    })
    

三、简单的通知功能

在渲染器中将接口获取到的数据传送到主进程中,在主进程中调用电脑的消息通知模块

渲染器

window.electronAPI.openNotification(msg);

预加载

const openNotification = async (message) => {
    let result = await ipcRenderer.invoke('on-openNotification-event', message);
};

主进程

const { ipcMain, Notification } = require('electron');
// 监听主窗口发送通知事件
const openNotification = () => {
    ipcMain.handle('on-openNotification-event', (event, message) => {
        const NOTIFICATION_TITLE = '您有一条新消息';
        const NOTIFICATION_BODY = message;
        new Notification({
            title: NOTIFICATION_TITLE,
            body: NOTIFICATION_BODY,
            silent: true,
            icon: '../../tray/icon.ico',
            timeoutType: 'never',
        }).show();
    });
};

四、截屏功能

新建一个截屏窗口,这个窗口为全屏透明,没有边框

const { LOAD_URL } = require('./config.js');
const path = require('path');
const isDev = require('electron-is-dev');
const { screen } = require('electron');

const mainWinURL = isDev ? `http://localhost:8080/#/cut` : `${LOAD_URL}#/cut`;

const getSize = () => {
    const { size, scaleFactor } = screen.getPrimaryDisplay();
    return {
        width: size.width * scaleFactor,
        height: size.height * scaleFactor,
    };
};

const createCutWindow = (BrowserWindow) => {
    const { width, height } = getSize();
    const win = new BrowserWindow({
        width,
        height,
        autoHideMenuBar: true,
        useContentSize: true,
        movable: false,
        frame: false,
        resizable: false,
        hasShadow: false,
        transparent: true,
        fullscreen: true,
        simpleFullscreen: true,
        alwaysOnTop: false,
        // opacity: 0.3,
        show: false,
        webPreferences: {
            webSecurity: true,
            nodeIntegration: true,
            contextIsolation: true,
            // 渲染器进程到主进程通信
            preload: path.resolve(__dirname, '../modules/preload/cut.js'),
        },
    });
    // 加载页面地址 线上内网可切换地址
    win.loadURL(mainWinURL);
    // 开发者工具
    win.webContents.openDevTools();
    win.maximize();
    win.setFullScreen(true);
    // 优雅打开界面
    // win.once('ready-to-show', () => {
    //     win.show();
    // });
    global.cutWindow = win;
};

module.exports = {
    createCutWindow,
};

然后再窗口初始化完成的时候在主进程中获取屏幕信息,将屏幕信息转化为url然后显示在渲染器上

const { id } = screen.getPrimaryDisplay();
let url = '';
let sources = await desktopCapturer.getSources({
    types: ['screen'],
    thumbnailSize: getSize(),
});
for (let source of sources) {
    if (parseInt(source.display_id, 10) === id) {
        url = source.thumbnail.toDataURL('image/png');
    }
}

页面代码


    


let bg = ref('');

在页面中引入canvas绘图工具konva。通过canvas选取要截图的信息

五、截屏结合百度ocr

在上一步获取到截屏信息之后,将图片信息转化为base64格式并存储到pinia中,调取百度的ocr功能。

在百度AI开放平台中申请建好项目,然后根据key获取token,详细操作见官网

通过watch监听pinia中的截图信息,当截图后调用文字识别接口

// 文字识别
const startOcr = () => {
    const base64Img = cutImage.value;
    const img = base64Img.replace(/^data:image/w+;base64,/, ''); //去掉base64位头部
    const param = {
        image: img,
    };
    axios({
        method: 'post',
        baseURL: PATH_URL + '/rest/2.0/ocr/v1/accurate_basic?access_token=' + accessToken,
        data: param,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
    })
        .then((res) => {
            wordsList.value = res.data.words_result;
        })
        .catch((err) => {
            console.error(err);
        });
};

六、开机自启动

在主进程中写入下列代码即可

const onAppReady = () => {
    // 设置开机自启
    const exeName = path.basename(process.execPath);
    app.setLoginItemSettings({
        // 设置为true注册开机自启
        openAtLogin: true,
        openAsHidden: false, //macOs
        path: process.execPath,
        args: ['--processStart', `"${exeName}"`],
    });
};
app.isReady() ? onAppReady() : app.on('ready', onAppReady);

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论