Electron-react实现 自定义通知 ,帮你踩坑!

摸鱼无聊怎么办,怼着代码死里干!

为了接触更多的新技术,拓展自己的技术能力,本文给大家带来我第一次使用electron的技术文章,记录了对electron的一些基本的认识,主要介绍了electron的一些基本的架构和api的使用,由于对react的熟悉度还是比较低,所以这次选择的脚手架是electron-react

Electron自带的Notifytion通知

定义普通消息通知看看效果

js 复制代码
const notification = new Notification({
    title: '测试',
    body: '测试内容',
});
notification.show();

这个内容比较简单,而且根据官方提供的api也无法对弹窗做更大的修改,所以准备通过用新建窗口的方法来制作一个弹窗。

自定义弹窗结果展示

虽然效果很简单,但是途中踩了很多的坑,各位看官接着往下看

这个速度确实有点慢 后续看看如何优化

主进程加载窗口

准备该消息通知在桌面的右下角显示

使用screen.getPrimaryDisplay().workAreaSize获取用于获取主显示器(primary display)的工作区尺寸,即可用的工作区域的大小, x和y是偏移量

resolveHtmlPath是electron-react提供的的一个路径函数,获取渲染进程文件夹的目录下的文件,也是打包后的renderer下的文件

js 复制代码
//main
import { app, BrowserWindow, shell, ipcMain,screen  } from 'electron';
const { width ,height} = screen.getPrimaryDisplay().workAreaSize
  const digalogWidth = 400
  const dialogHeight = 150
  const dialogWindow = new BrowserWindow({
    width:digalogWidth,
    height:dialogHeight,
    x:width-digalogWidth,
    y:height-dialogHeight,
    // frame: false, // 隐藏标题栏和缩放按钮
    webPreferences: {
      nodeIntegration: true,
      // session: session.fromPartition('persist:main'),
      devTools: false,
    },
  }); 
  dialogWindow.loadURL(resolveHtmlPath('dialog.html'));

新建弹窗dialog目录

新建文件夹来存放需要打开的页面,这里称为窗口可能更加合适

主进程中监听渲染进程的事件

js 复制代码
//mainjs

ipcMain.on('ipc-example', async (event, arg) => {
  const msgTemplate = (pingPong: string) => `IPC test: ${pingPong}`;
  event.reply('ipc-example', msgTemplate('pong'));
  showNotification()
});

const showNotification = () => {
  new BrowserWindow({ frame: false }).show()
  //在主进程中监听消息弹窗的显示请求
  const { width ,height} = screen.getPrimaryDisplay().workAreaSize
  const digalogWidth = 400
  const dialogHeight = 150
  const dialogWindow = new BrowserWindow({
    width:digalogWidth,
    height:dialogHeight,
    x:width-digalogWidth,
    y:height-dialogHeight,
    // autoHideMenuBar: true,
    // frame: false, // 隐藏标题栏和缩放按钮
    webPreferences: {
      nodeIntegration: true,
      session: session.fromPartition('persist:main'),
      devTools: false,
    },
  }); 
  dialogWindow.loadURL(resolveHtmlPath('dialog.html'));
  
}

渲染进程触发

js 复制代码
//App.tsx
function Hello() {
  const showLoading = ()=> {
   window.electron.ipcRenderer.sendMessage('ipc-example', ['show']);
  }
  return (
    <div>
      <div className="Hello">
        <img width="200" alt="icon" src={icon} />
      </div>
      <h1>electron-react-boilerplate</h1>
      <div className="Hello">
          <button type="button" onClick={showLoading}>
            <span role="img" aria-label="books">
              📚
            </span>
            Read our docs1
          </button>
          <button type="button">
            <span role="img" aria-label="folded hands">
              🙏
            </span>
            Donate
          </button>
      </div>
    </div>
  );
}

开始踩坑

加载dialog.html页面

主进程和渲染进程都已经好了,新增一个窗口,我们就需要放入一个html,但是根据官方提供的模版来看,是没有html的,所以到底是怎么生成的呢,一开始我是根本不知道的

我们可以看到其实是有一个html的文件的,但是在目录中只有index.ejs,这一步是在webpack中实现的

js 复制代码
new HtmlWebpackPlugin({
  filename: path.join('index.html'),
  template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
  minify: {
    collapseWhitespace: true,
    removeAttributeQuotes: true,
    removeComments: true,
  },
  isBrowser: false,
  env: process.env.NODE_ENV,
  isDevelopment: process.env.NODE_ENV !== 'production',
  nodeModules: webpackPaths.appNodeModulesPath,
}),

webpack通过加载模版将结果输出到index.html中,所以要实现dialog.html的页面渲染到新窗口中,我们可以模仿官方给我们的写法。

js 复制代码
new HtmlWebpackPlugin({
  filename: path.join('dialog.html'),
  template: path.join(webpackPaths.srcRendererPath, 'components/index.ejs'),
  minify: {
    collapseWhitespace: true,
    removeAttributeQuotes: true,
    removeComments: true,
  },
  isBrowser: false,
  env: process.env.NODE_ENV,
  isDevelopment: process.env.NODE_ENV !== 'production',
  nodeModules: webpackPaths.appNodeModulesPath,
}),

这一步就是把我们的dialog模板输出到和index.html同样的目录下。

filename: path.join('dialog.html')这一步要写好,一开始我写的是 component/dialog.html,想要生成的路径是在component下面,结果失败了。

注意template的路径,指向的是新窗口的模板。修改之后记得重启,否则可能会出现找不到dialog.html的情况 ,表现形式为在控制台会404

js 复制代码
components/index.ejs
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      http-equiv="Content-Security-Policy"
      content="script-src 'self' 'unsafe-inline'"
    />
    <title>下班通知</title>
  </head>
  <body>
    <div id="dialog"></div>
  </body>
</html>

加载index.js

这里的index.js是给dialog.html使用的

js 复制代码
webPreferences: {
  nodeIntegration: true,
  devTools: true,
},

把新建窗口的devtools打开,查看一下控制台

这里又踩了一下坑,由于webpack打包的原因,这里我们新建窗口,用到的js都是同一个js,但是我们来看一下我们的根目录js是怎么写的

js 复制代码
renderer/index.tsx

import { createRoot } from 'react-dom/client';
import App from './App';
import Dialog from './components/dialog';

const container = document.getElementById('root') as HTMLElement;
const root = createRoot(container);
root.render(<App />);

这里加载的是id=root这个节点,但是dialog.html中只有id=dialog这节点,所以就会发生报错

使用BrowserWindow打开新窗口的时候,都会默认加载同一个js

骚操作

既然你同一个js,那种得区分开来吧,这里是通过判断窗口的标题来执行不同的操作,虽然有点不正规,但是也是可以实现的,后续会通过切割分包的形式看看是否可行

js 复制代码
import { createRoot } from 'react-dom/client';
import App from './App';
import Dialog from './components/dialog';

if(document.title=='Electron'){
  const container = document.getElementById('root') as HTMLElement;
  const root = createRoot(container);
  root.render(<App />);
}else{
  const container = document.getElementById('dialog') as HTMLElement;
  const root = createRoot(container);
  root.render(<Dialog />);
}

到这一步我们就已经完成了生成dialog.html文件,加载dialog.html文件,并且将react的内容挂载到dialog.html上面。虽然看几个步骤都比较简单,但是其中的排错由于是第一次上手耗费了比较多的时间,单单上面这几个坑都够我喝一壶的了,最终也是能简单的实现这个效果。

🙏 感谢您花时间阅读这篇文章!如果觉得有趣或有收获,请关注我的更新,给个喜欢和分享。您的支持是我写作的最大动力!✍️🌟

往期好文推荐

相关推荐
程序员爱技术1 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会2 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、2 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜2 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师2 小时前
CSS的三个重点
前端·css
耶啵奶膘4 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^5 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie6 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic7 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿7 小时前
webWorker基本用法
前端·javascript·vue.js