electron-vue 创建桌面应用


electron-vue 创建桌面应用

为了学习 vue 并创建桌面应用,

我使用了 electron-vue 来进行搭建,

它集成了很多 vue 的工具,用来学习 vue 非常方便;

这里我用 IT Tools 这个项目来讲解一下,

整个项目目前提供了四个模块,分别是

  • “正则表达式”
  • “时间戳转化”
  • “颜色盒子”
  • “Json转化”

在这几个模块中,可以发现使用组件化的好处,处理多个组件之间各种数据变化非常方便!

这里我就以 “正则表达式” 页面来说明:

创建 Electron-Vue 项目

克隆项目,从electron-vue 克隆项目,然后开始编写代码;

https://github.com/SimulatedGREG/electron-vue.git

通过"正则表达式"这个模块,来了解 Vue 组件通信;

electron-vue 一开始已经为你生成一些文件页面,我们可以按照他的方法创建我们自己的页面;

创建路由:

src/renderer/router/index.js 文件中添加路由:

export default new Router({ routes: [ { path: '/', name: 'landing-page', component: require('@/components/LandingPage').default }, { path: '/regex-page', name: 'regex-page', component: require('@/components/RegexPage').default } ] });

这里我们的 url 为 /regex-page,并且require 了RegexPage组件,这个组件要放置在components 目录下,所以我创建了文件:src/renderer/components/RegexPage.vue

 

编写组件:

可以通过复制 LandingPage.vue 组件,将它改成新组件即可:

要实现这个页面,头部两个输入框,输入后都能与下面的textarea 内容进行比较处理,得出结论;

这个用 组件化 vue 比纯粹用js jquery 的 dom 操作要方便太多了;

通过 template 包裹写成vue组件:

<template>
  <div id="regex-page">

    <div class="regex-inner" v-show="currentTab === 'Home'">
    <div class="regex-top">
      <div class="regex-top-label">
        <label>Your regular expression:</label>
      </div>
      <div class="regex-top-fields">
        <div class="regex-diagonal">/</div>
        <div class="regex-diagnoal-input">
          <input type="text" name="regex-exp" @input='execRegex' :value='regexExp' />
        </div>

 
 

        <div class="regex-diagonal">/</div>
        <div>
          <input type="text" name="regex-opt" @input="execRegex" :value="regexOpt" />
        </div>
      </div>

     </div>

 
 

     <div class="regex-bottom">
      <div class="regex-content">
        <label>Your test string: </label>
        <textarea class="regex-textarea" name="regex-content" @input="execRegex" :value='regexCont'></textarea>
      </div>

 
 

      <div class="result-content result-init" v-if="regexResult['status'] == 0">
        {{ regexResult['content'] }}
      </div>

 
 


      <div class="result-content result-match" v-if="regexResult['status'] == 1">
        <div>
          <div class="regex-match-btn">
            <label>Match Result:</label>
            <a href="javascript:void(0)" class="clean-fields" @click="cleanAllFields">Clean Fields</a>
          </div>
          <div class="result-item">
            <span v-for="(cont, indx) in regexResult['matchedContext']" :class="indx%2 !== 0 ? 'match' : null">{{ cont }}</span>
          </div>
        </div>
        <ul v-if="regexResult['content'].length > 0">
          <label>Match Groups:</label>
          <div class="match-groups">
            <li v-for="(itemGroup, index) in regexResult['content']">
              <div class="group-item">
              <label>Match Group {{ index + 1 }}:</label>
              <ul>
                <li v-if="i !== 0" v-for="(item, i) in itemGroup">{{ i }}: {{ item }}</li>
              </ul>
              </div>
            </li>
          </div>
        </ul>
        </div>

 
 

        <div class="result-content result-not-match" v-if="regexResult['status'] == -1">
          {{ regexResult['content'] }}
        </div>
      </div>
    </div>

</div>
</template>

<script>
import { mapState, mapActions } from 'vuex'

export default {
  name: 'regex-page',
  computed: {
    ...mapState('Regex', {
      regexExp: state => state.regexExp,
      regexOpt: state => state.regexOpt,
      regexCont: state => state.regexCont,
      regexResult: state => state.regexResult})
  },

    methods: {
    ...mapActions('Regex', [
      'setNav',
      'cleanFields',
      'regexMatch'
    ]),
    cleanAllFields () {
      this.cleanFields()
    },
    execRegex (event) {
      this.regexMatch(event)
    },
    updateNav (title, index) {
      this.setNav({ title: title, index: index })
    }

  }

}
</script>
<style lang="scss" scoped>

* {

}

</style>

 至于,输入框之间的交互,我使用 vuex 来实现他们之间数据的传递;

 

 

使用 Vuex 管理状态:
一、创建 store 目录,并创建 modules 目录用来管理不同的命名空间的State, Actions, Mutations 
创建src/renderer/store/modules/Regex.js 文件:
const state = {
  regexExp: '',
  regexOpt: '',
  regexCont: '',
  regexResult: { status: 0, content: "Here's result." }
}

const mutations = {
  REGEX_MATCH (state, target) {
    if (target.name === 'regex-exp') {
      state.regexExp = target.value
    }
    if (target.name === 'regex-opt') {
      state.regexOpt = target.value
    }
    if (target.name === 'regex-content') {
      state.regexCont = target.value
    }
    ...
}


const actions = {
  cleanFields ({ commit }) {
    commit('CLEAN_FIELDS')
  },
  regexMatch ({ commit }, payload) {
    commit('REGEX_MATCH', payload.target)
  }
}


export default {
  state,
  mutations,
  actions
}

state 给默认状态;

mutations 更改对应 state;

actions 用于写异步来改变状态或提交 mutations 的更改;

 

state 的方法被我写在computed,这样组件中可以使用;

在methods 方法中使用 mapActions,并定义其他方法来调用这些action;

 

 

二、main.js 加入 store 容器

import App from './App'
import router from './router'
import store from './store'

if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.http = Vue.prototype.$http = axios
Vue.config.productionTip = false

new Vue({
  components: { App },
  router,
  store,
  template: '<App/>'
}).$mount('#app')

 

 

 

三、组件中通过 computed 或 data 使用 State,通过 methods 触发 Actions 方法

  
import { mapState, mapActions } from 'vuex'

export default {
  name: 'regex-page',
  computed: {
    ...mapState('Regex', {
      regexExp: state => state.regexExp,
      regexOpt: state => state.regexOpt,
      regexCont: state => state.regexCont,
      regexResult: state => state.regexResult})
    },

    methods: {
    ...mapActions('Regex', [
      'setNav',
      'cleanFields',
      'regexMatch'
    ]),
    cleanAllFields () {
      this.cleanFields()
    },
    execRegex (event) {
      this.regexMatch(event)
    },
    updateNav (title, index) {
      this.setNav({ title: title, index: index })
    }

  }
}

在组件文件中引用了

mapState, mapActions

方法,他可以获取这个 store 里的 state 和 action 方法,

不过要注意命名空间的使用,此处使用了Regex作为命名空间,所以要在mapState 和 mapActions 中加 命名空间;

 

命名空间定义文件在:src/renderer/store/modules/index.js 文件;

const files = require.context('.', false, /\.js$/)
const modules = {} files.keys().forEach(key => { if (key === './index.js') return modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default modules[key.replace(/(\.\/|\.js)/g, '')]['namespaced'] = true }) export default modules

但是直接 (‘Regex’, [regexExp: state => state.regexExp]) 是无法使用的,必须在 module 中声明 namespaced: true 才可以;

…mapActions() 是将里面的对象 扁平化 到 外面的对象中;

直接 mapActions  只是打开了方法,还未执行:

删除 createSharedMutations() 的方法后,action 生效;

 

绑定到组件上

<input type="text" name="regex-exp" @input='execRegex' value='regexExp' />

  

 

大体上就是这样,剩余就是处理方法的逻辑,在  Mutation 的方法中实现;

 

Vue 生命周期问题:

这里我要提一下另一个页面模块:“JSON 转化”;
我在做 “Json 转化” 的时候 ,由于转化后的 json 对象构造成 html 后要用 v-html 显示;
但是这些 html 标签中有的要绑定事件,直接在 component 中写 methods,发现事件无法被触发; 

为了让 v-html 中的事件生效,我查阅了 vue 组件的生命周期;

  v-html 在组件 mounted 之后,也就是 state 变化之后渲染,所以我们必须在 updated 之后绑定事件

但是又有问题,因为 state 不变化,就不会 updated 局部组件,而我们点击其他页面后,回到当前页面,在去触发事件,发现事件没了?
尝试添加 mounted 来绑定事件,成功触发事件;  【当点击其他页面,然后返回时,state 的不变,不会再次调用 updated 方法,但是重新执行了挂载方法 mounted】

生成桌面应用

运行命令:
npm run build:mas # 生成mac应用
npm run build:linux # 生成linux 应用
npm run build:win32 # 生成windows应用

可以在 /build 目录中看到生成的应用目录

 

对mac 应用进行打包:

将生成的应用放入新建的目录,命名为 IT-Tools,再复制“应用程序”的软链 到 IT-Tools目录中;

cmd+空格:打开文件搜索 disk ,打开磁盘管理,点击文件-新建映像-来自文件夹的映像;

 
感谢大家阅读, 如果您对 it-tools 此项目感兴趣,欢迎关注或者给我问题; 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM