自定义菜单栏实现点击添加按钮打开渲染进程的Dialog.vue模态框

时间:2024-11-18 07:27:46

实现思路:渲染进程页面初始化后就通知主进程,然后把event事件保存在该js文件外,当点击添加时因为是在其他位置,所以才要这样使用。然后点击添加后由主进程主动向渲染进程传递参数通知要做的操作。

代码如下:

// 第一步

// 进入主页面后给主进程通信 Home.vue
<script setup lang="ts" name="Home">
    import {provide, ref, onMounted} from 'vue'

    onMounted(async () => {
      window.getSource.openDialog()
    })

</script>



// preload.js
const {ipcRenderer, contextBridge} = require('electron')

const openDialog = () => ipcRenderer.send('on-opendialog-event')

contextBridge.exposeInMainWorld('getSource', {
    openDialog
})



// 主进程 main.js
const { app, Menu, ipcMain } = require('electron')

// 监听 on-opendialog-event 事件
let event = null
ipcMain.on('on-opendialog-event', (e, message) => {
    event = e;
})

// 第二步

// 主进程内自定义菜单点击 添加 后触发事件
const { app, Menu, ipcMain } = require('electron')

const isMac = process.platform === 'darwin'

// 监听 on-opendialog-event 事件
let event = null
ipcMain.on('on-opendialog-event', (e, message) => {
    event = e;
})


const template = [
  // { role: 'appMenu' }
  ...(isMac
    ? [{
        label: app.name,
        submenu: [
          { role: 'about' },
          { type: 'separator' },
          { role: 'services' },
          { type: 'separator' },
          { role: 'hide' },
          { role: 'hideOthers' },
          { role: 'unhide' },
          { type: 'separator' },
          { role: 'quit' }
        ]
      }]
    : []),
  // { role: 'fileMenu' }
  {
    label: 'File',
    submenu: [
      isMac ? { role: 'close' } : { role: 'quit' }
    ]
  },
  // { role: 'editMenu' }
  {
    label: 'Edit',
    submenu: [
      { role: 'undo' },
      { role: 'redo' },
      { type: 'separator' },
      { role: 'cut' },
      { role: 'copy' },
      { role: 'paste' },
      ...(isMac
        ? [
            { role: 'pasteAndMatchStyle' },
            { role: 'delete' },
            { role: 'selectAll' },
            { type: 'separator' },
            {
              label: 'Speech',
              submenu: [
                { role: 'startSpeaking' },
                { role: 'stopSpeaking' }
              ]
            }
          ]
        : [
            { role: 'delete' },
            { type: 'separator' },
            { role: 'selectAll' }
          ])
    ]
  },
  // { role: 'viewMenu' }
  {
    label: 'View',
    submenu: [
      { role: 'reload' },
      { role: 'forceReload' },
      { role: 'toggleDevTools' },
      { type: 'separator' },
      { role: 'resetZoom' },
      { role: 'zoomIn' },
      { role: 'zoomOut' },
      { type: 'separator' },
      { role: 'togglefullscreen' }
    ]
  },
  // { role: 'windowMenu' }
  {
    label: 'Window',
    submenu: [
      { role: 'minimize' },
      { role: 'zoom' },
      ...(isMac
        ? [
            { type: 'separator' },
            { role: 'front' },
            { type: 'separator' },
            { role: 'window' }
          ]
        : [
            { role: 'close' }
          ])
    ]
  },
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click: async () => {
          const { shell } = require('electron')
          await shell.openExternal('https://electronjs.org')
        }
      }
    ]
  },

  // 第一步看这个就可以
  {
    label: 'action',
    submenu: [
        {
            label: '添加(打开dialog)',
            click: () => {
                // 作用: 主进程通知渲染进程
                // 点击后主进程触发preload预加载内对应的事件,然后渲染进程触发打开弹窗
                event.sender.send('on-renderer-event', 'add')
            }
        }
    ]
  },
]

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)



// preload.js处理主进程的事件event.sender.send('on-renderer-event', 'add')
const {ipcRenderer, contextBridge} = require('electron')

const openDialog = () => ipcRenderer.send('on-opendialog-event')

const onRendererEvent = () => {
    return new Promise((resolve, reject) => {
        ipcRenderer.on('on-renderer-event', (e, message) => {
            // 主进程通知后就触发这个回调
            resolve(message)
        })
    })
}

contextBridge.exposeInMainWorld('getSource', {
    openDialog,
    onRendererEvent
})



// 最后渲染进程Home.vue接收到传来的add,对类型进行监听后弹窗
<script setup lang="ts" name="Home">
    import {provide, ref, onMounted} from 'vue'

    let type = ref('');
   
    onMounted(async () => {
      window.getSource.openDialog()
      
      // 主进程触发preload,preload通知这里执行
      const res = await window.getSource.onRendererEvent()
      type.value = res;
    })

</script>

<template>
  <main>
    <div>home</div>
    <SearchBar :type="type" />
    <List />

  </main>
</template>


// Searbar.vue监听type的值
<script setup lang="ts" name="SearchBar">
    import {ref, inject, watch} from 'vue'
    import Dialog from './Dialog.vue'
    
    const props = defineProps(['type'])

    const {show, setShow} = inject('on-show-event', {show: false, setShow: () => {}})

    function handleShowDialog () {
        setShow()
    }

    // 这里监听
    watch(() => props.type, () => {
        if (props.type == 'add') {
            handleShowDialog();
        }
    })
</script>

<template>
  <div class="search_bar">
    <div @click="handleShowDialog">+</div>
    <input placeholder="请输入关键词" type="text">
  </div>

  <Dialog></Dialog>

</template>

<style lang="less" scoped>
    .search_bar {
        width: 100%;
        display: flex;
        align-items: center;
        height: 60px;
        background-color: #ccc;

        > div {
            margin-left: 20px;
            background-color: aqua;
            width: 16px;
            height: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-right: 20px;
        }

        > input {
            flex: 1;
        }
    }
</style>



效果如下: