iMap | 一款基于 Electron 和 Vue 的跨平台旅行地图生成器

项目地址:https://huangxizhou.com/project/iMap

技术栈

项目目录

.
├── LICENSE
├── README.md
├── build··········································electron-packager 打包出来的各平台应用
│   └── icons······································各平台应用图标
│       ├── icon.icns
│       ├── icon.ico
│       └── icon.png
├── dist···········································应用构建后的代码目录
│   ├── electron
├── package.json···································应用层级的 package.json
├── src············································electron 入口文件文件夹
│   ├── index.ejs
│   ├── main·······································electron 主进程文件文件夹
│   │   ├── index.dev.js
│   │   └── index.js
│   └── renderer···································Vue 相关的目录
│       ├── App.vue································单页面的主结构
│       ├── assets·································静态资源文件夹
│       │   ├── img································项目配图
│       │   │   ├── china.png
│       │   │   ├── excel_example.png
│       │   │   └── world.png
│       │   └── my-theme···························iVew 自定义主题相关目录
│       ├── components·····························Vue 相关组件目录
│       │   ├── Layout·····························布局组件
│       │   │   └── Header.vue·····················导航栏
│       │   ├── Page·······························页面组件
│       │   │   ├── Auth.vue·······················用户权限获取组件
│       │   │   ├── Chart.vue······················制作地图组件
│       │   │   ├── ForgetPassword.vue·············忘记密码组件
│       │   │   ├── Help.vue·······················帮助文档组件
│       │   │   ├── Home.vue·······················主页组件
│       │   │   ├── Login.vue······················登录页组件
│       │   │   ├── Map.vue························地图类型组件
│       │   │   ├── MyProject.vue··················我的项目组件
│       │   │   ├── Register.vue···················注册组件
│       │   │   └── Update.vue·····················登录组件
│       │   └── Ui·································功能组件
│       │       ├── AddPointModal.vue··············添加地点组件
│       │       ├── DelPointModal.vue··············删除地点组件
│       │       └── EditPointModal.vue·············修改地点组件
│       ├── data···································Echarts 相关数据存放文件夹
│       │   ├── china.json·························中国地图 json 数据
│       │   ├── map.js·····························导入坐标数据
│       │   └── world.json·························世界地图 json 数据
│       ├── filter·································Vue 过滤器目录
│       │   └── index.js
│       ├── main.js································Vue 入口文件
│       ├── router·································Vue 路由文件
│       │   └── index.js
│       ├── server·································ajax相关操作文件
│       │   ├── ajax.js····························二次封装ajax
│       │   └── url.js·····························接口别名
│       ├── store··································Vuex 数据目录
│       │   ├── actions.js·························涉及多个 mutations 的 action 集合 
│       │   ├── index.js···························Vuex 入口文件
│       │   ├── modules····························模块目录
│       │   │   ├── excel.js·······················Excel 数据相关模块
│       │   │   └── user_info.js···················用户数据相关模块
│       │   └── mutations_types.js·················mutation-types 声明  
│       ├── tool···································工具文件夹
│       │   └── index.js
│       └── version································应用版本文件夹
│           └── version.js
└── yarn.lock

接口与数据问题

本项目使用的是官方推荐的axios

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

本来之前想使用 prototype 来写侵入式代码,但维护起来还是很麻烦,最终还是撸了个开箱即用的 axios 二次封装的js文件出来:

// POST 请求
post({...obj}) {
  return new Promise((resolve, reject) => {
    axios.post(obj.url, obj.data, {
        headers: {
          "Authorization": user && user.accessToken
        }
      }).then((data) => {
      if(data.data.code === 0) {
        // ...
      } else if (data.data.code === 1)  {
        // ...        
      } else {
        // ...  
      }
    }).catch((data) => {
      reject(data)
    })
  })     
}

一般来说,在接收到后端返回的数据时,可以使用resolve(data.data)来直接处理数据,当然也可以按需引入一些 UI 组件与过滤器,直接在 ajax 封装文件中就可以过滤数据并进行全局提示,提升用户体验。

对于 GET 请求,由于项目有使用到百度地图开放 API 来获取城市经纬度,涉及到 jsonp 跨域问题,尴尬的是 axios 官方说明不会支持 jsonp ,所以只能引入 jsonp 这个 npm 包,并且将请求此接口从 GET 请求中单独提取出来。

getLocation({...obj}) {
    return new Promise((resolve, reject) => {
      jsonp(obj.url + '?' + qs.stringify(obj.data) , null,  (err, data) => {
        if (err) {
          Message.error('请求错误')
        } else {
          if(data.status === 0) {
            resolve(data)
          }
        }
      })
    })
  }

GET 请求 ajax 代码封装与 POST 基本一致,只是将 obj.data 换成 { paramas: obj.data } 即可。

关于 Vuex 的使用

Vuex是个能把组件的共享状态抽取出来,当做一个全局单例模式进行管理。这样不管你在何处改变状态,都会通知使用该状态的组件做出相应修改。

在本项目中,需要提取到全局管理的数据有 userInfoexcelData,前者保存在全局中,可以减少请求用户信息接口的数量,节约资源,后者由于 Excel 文件上传到后端后只做解析,不保存,所以全局管理 excelData 很重要。

在这里就单独说一说添加城市坐标的操作好了:
首先是 mutations_types 声明文件

// mutations_types.js
export const ADD_EXCEL_DATA = 'ADD_EXCEL_DATA'
...

声明 statemutations
在 Vuex 中,更改 Vuex 的 store 中的状态的唯一方法就是 mutations

// modules/excel.js
import * as types from '../mutations_types'

// state
const state = {
  excelData: {}
}

// mutations
const mutations = {
  ...
  // 添加 excelData
  [types.ADD_EXCEL_DATA] (state, data) {
    state.excelData.data.push(data)
  },
  ...
}

// 导出 state, mutations
export default {
  state,
  mutations
}

然而,Mutations 必须是同步函数,所以我们还需要 actions

// actions.js
import * as types from './mutations_types'

...
// 添加 excelData
export const addExcelData = ({ commit }, data) => {
    commit(types.ADD_EXCEL_DATA, data)
}
...

最后,再在入口文件注入 modules 和 actions即可

...
export default new Vuex.Store({
  actions,
  modules: {
    excel
  }
})

这样一来,关于 excelData 的 数据管理的任督二脉已经打通,现在就看如何来使用了

在组件中可以使用 mapStatemapActions 辅助函数来简化代码
mapState函数用在计算属性中

// AddPointModal.vue
  computed: {
    ...mapState({
      excelData: state => state.excel.excelData,
      countAlias: 'excelData'
    })
  }

mapActions 函数在本项目中用于 methods 中

methods: {
    ...mapActions({
      addExcelData: 'addExcelData'
    })
    ...
}

在函数中调用

this.addExcelData(Arrary)

这样就成功将一个新的数组元素添加到 excelData 中了。

如何获取 Excel 数据

本项目采用 Leancloud 来作为后端支持,使用的是Node.js(express),对于获取用户的 Excel 数据并不想保存数据的话,本项目的思路是将 Node 作为一个文件中转的存在,上传用户 Excel 文件至服务器后,在 /public 目录下保存Excel文件,再在下次用户上传时,清空 /public 目录。

用户 Excel 处理的库本项目选择的是 node-xlsx

特别注意的是,在前端文件中,上传用户 Excel 文件是需要使用 formData 来上传的

let formData = new FormData()
formData.append('file', this.file)

后端使用 formidable 这个库来接收 Excel 文件并使用 form.parse 来解析。

关于使用 Echarts

ECharts,一个纯 Javascript 的图表库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖轻量级的 Canvas 类库 ZRender,提供直观,生动,可交互,可高度个性化定制的数据可视化图表。

对于在 Vue 项目中使用 Echarts , 本项目采用的是 vue-echarts
chart.vue 文件中,我们利用一个三元运算符来动态切换地图类型

this.selectMapType === 'china' ?  ECharts.registerMap('china', chinaMap) : ECharts.registerMap('world', worldMap)

对于地图数据的导入,本项目的方法是的是导入一个对象,返回地图 option 数据:

// map.js
...
export default {
    getMapData({...obj}) {
    ...
        return {
           // 地图配置数据
        }
    }
}

再在前端文件中使用这个函数即可: this.option = map.getMapData(this.excelData)

Vue 中父子组件双向绑定

在本项目中,我将添加、编辑、删除地点的弹窗全部提取到公用 Ui 组件文件夹中,然而这就需要利用 v-model 来实现组件 props 双向绑定

// template
<Modal :value="value" v-model="showModal"></Modal>


// script
export default {
  props: {
      value: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return: {
        showModal: false
    }
  },
  watch:{
    value(val) {
      this.showModal = val
    },
    showModal(val) {
      this.$emit('input', val)
    }
  },
  mounted() {
    if (this.value) {
      this.showModal = true;
    }
  }
}

这样就能使用value来保存 v-model 的值,从而进行双向绑定。

在MacOS 上打包 Win32 软件包

在 electron-vue 文档中有这么一句话:

If you are wanting to build for Windows with a custom icon using a non-Windows platform, you must have wine installed.

那么我们就来安装wine。首先确保你的 Mac 已经安装 homebrew,运行 brew install wine 来安装wine。

接下来,会出现一个错误提示,提示我们需要安装 Xquartz,按照错误提示给的下载网址下载即可。

再次运行 brew install wine

安装成功后在项目目录下运行 npm run build:win32 就可以打包成Win32 安装包了

求一份工作~

2019年毕业生求带走

我的简历

相关推荐