【问题标题】:Vuex and Electron carrying state over into new windowVuex 和 Electron 将状态转移到新窗口
【发布时间】:2016-11-17 13:28:20
【问题描述】:

我目前正在使用 Electron 构建一个应用程序,到目前为止非常棒。

我正在使用Vue.jsVuex 来管理我的应用程序的主要状态,主要是用户状态(配置文件和已通过身份验证等...)

我想知道是否可以打开一个新窗口,并具有与主窗口相同的Vuex 状态,例如

如果用户未通过身份验证,我目前会在应用启动时显示一个登录窗口,这可以正常工作。

function createLoginWindow() {
  loginWindow = new BrowserWindow({ width: 600, height: 300, frame: false, show: false });
  loginWindow.loadURL(`file://${__dirname}/app/index.html`);
  loginWindow.on('closed', () => { loginWindow = null; });
  loginWindow.once('ready-to-show', () => {
    loginWindow.show();
  })
}

用户执行登录表单,如果成功则触发此功能:

function showMainWindow() {
  loginWindow.close(); // Also sets to null in `close` event
  mainWindow = new BrowserWindow({width: 1280, height: 1024, show: false});
  mainWindow.loadURL(`file://${__dirname}/app/index.html?loadMainView=true`);
  mainWindow.once('resize', () => {
    mainWindow.show();

  })
}

这一切都有效,唯一的问题是,mainWindowloginWindow 共享的 this.$store.close()'d 不同

有什么办法可以将Vuex this.$store 传递到我的新窗口,这样我就不必将所有内容都塞进mainWindow 并不断隐藏它,改变它的视图,而且我希望能够拥有其他的依赖Vuex 状态的窗口(朋友列表等)。

希望这不会太令人困惑,如果您需要澄清,请询问。谢谢。

【问题讨论】:

    标签: vue.js electron vuex


    【解决方案1】:

    虽然我可能会看到您如何做到这一点,但我会添加免责声明,因为您使用的是 Vue,所以您不应该这样做。相反,我会使用 vue 组件来构建这些单独的视图,然后您可以在 SPA 中实现您的目标。组件也可以是动态的,这可能有助于解决将它们隐藏在主窗口中的问题,即

    <component v-bind:is="currentView"></component>
    

    然后您只需将 currentView 设置为组件名称,它就可以完全访问您的 Vuex 存储,同时只安装/显示您想要的视图。

    但是,当您正在研究它时,我相信应该可以将 loginWindow 内的商店值传递给 mainWindow,但这不是一个纯粹的 Vue 解决方案。

    而是您在 loginWindows Vue 实例中创建一个方法,该方法输出一个普通对象,其中包含您要传递的所有 key: value 状态。然后将 loginWindows 变量设置为mainWindow 中的全局变量,这将允许它在其存储中更新这些值。即

    # loginWindow Vue model
    window.vuexValuesToPass = this.outputVuexStore()
    # mainWindow
    var valuesToUpdate = window.opener.vuexValuesToPass
    

    然后在 mainWindows Vue 实例中,您可以设置一个操作来使用您传递的所有值更新存储

    【讨论】:

      【解决方案2】:

      考虑到您在每次交互时都使用电子的 BrowserWindow,我会使用 ipc 通道通信。

      这是主进程

      import { ipcMain } from 'electron'
      let mainState = null
      
      ipcMain.on('vuex-connect', (event) => {
        event.sender.send('vuex-connected', mainState)
      })
      
      ipcMain.on('window-closed', (event, state) => {
        mainState = state
      })
      

      然后,我们需要为 Vuex 商店创建一个插件。我们称之为ipc。有一些有用的信息here

      import { ipcRenderer } from 'electron'
      import * as types from '../../../store/mutation-types'
      
      export default store => {
        ipcRenderer.send('vuex-connect')
      
        ipcRenderer.on('vuex-connected', (event, state) => {
          store.commit(types.UPDATE_STATE, state)
        })
      }
      

      在此之后,使用 store.commit 更新整个 store 状态。

      import ipc from './plugins/ipc'
      var cloneDeep = require('lodash.clonedeep')
      
      export default new Vuex.Store({
        modules,
        actions,
        plugins: [ipc],
        strict: process.env.NODE_ENV !== 'production',
        mutations: {
          [types.UPDATE_STATE] (state, payload) {
            // here we update current store state with the one
            // set at window open from main renderer process
            this.replaceState(cloneDeep(payload))
          }
        }
      })
      

      现在它仍然会在触发关闭窗口或任何其他您想要的事件时发送 vuex 状态。将其放在您可以访问存储状态的渲染器进程中。

      ipcRenderer.send('window-closed', store.state)
      

      请记住,我没有专门测试过上述场景。这是我在一个应用程序中使用的东西,它产生新的 BrowserWindow 实例并在它们之间同步 Vuex 存储。

      问候

      【讨论】:

      • 这是一个很好的工作方法 - 并且是唯一真正解决问题的答案。
      【解决方案3】:

      GuyC 关于使应用程序完全单页的建议是有道理的。尝试使用 vue-router 来管理 SPA 中路由之间的导航。

      我有一个粗略的解决方案来做你想做的事,它节省了导入像 vue-router 这样的东西的工作,但是通过配置的路由替换页面中的组件总是比加载新页面更顺畅:当打开一个新窗口时,我们有它的window 对象,我们可以将共享状态设置为window 的会话存储(或一些全局对象),然后让vuex 在新窗口中检索它,如created() {if(UIDNotInVuex) tryGetItFromSessionStorage();}created 是某个组件创建的钩子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-21
        • 2020-04-14
        • 1970-01-01
        • 2019-04-22
        • 2023-03-16
        • 2021-06-19
        • 1970-01-01
        • 2016-11-05
        相关资源
        最近更新 更多