准备
- node & npm - 1 - $ brew install node 
- 检查 node & npm - 1 
 2- $ node -v 
 $ npm -v
- vue-cli - 1 - $ npm install -g vue-cli - 或 - 1 - $ npm install -g @vue/cli @vue/cli-init @vue/cli-service-global 
初始化
| 1 | $ vue init <template-name> <project-name> | 
举例
| 1 | vue init webpack vue-step-by-step | 
根据提示依次输入相关信息 ↓
最后出现finished安装完成 ↓
在终端中运行 ↓
| 1 | cd vue-step-by-step | 
即可查看初始化完成的效果
添加依赖
项目初始化完成后添加项目常用依赖包
| 1 | npm install --save vuex axios qs | 
包含vuex、axios、qs、sass、pug等,其他依赖包根据项目需求自己选择vue-router在脚手架 init 的时候会提示是否选择安装
完善项目结构
添加views文件夹
src 下添加 views 文件夹主要存放页面级的 vue 组件
src 下的 components 文件夹主要用于存放通用的组件
在 views 文件夹中创建Home.vue作为主页
删除App.vue中无用的内容,只保留router-view
| 1 | <template> | 
如果是移动端项目用 rem 作为单位,可以在src/main.js中添加如下代码做自适应 ↓
| 1 | if (window.addEventListener) { | 
调整router配置
更多路由相关使用方法请访问:https://router.vuejs.org/zh-cn/
目录结构 ↓
| 1 | router | 
修改路由主文件router/index.js
使用require.context实现路由去中心化
| 1 | import Vue from 'vue' | 
在 router 文件夹下添加 modules 文件夹
在 modules 文件夹下添加 home.js ,这个 home.js 对应首页业务模块,首页相关的路由页面都可以写到 home.js 文件里。
如果以后添加其他业务模块,只需要在 modules 文件夹添加相对应的业务模块文件,并在其中添加业务相关的路由页面。这样所有不同业务线的开发人员就可以互不干扰 ↓
| 1 | import Home from '../../views/Home' | 
对于不需要即时加载的非一级页面可以使用异步路由组件
| 1 | // region 异步组件 - 路由地址demo | 
添加store文件夹
src 下的 store 文件夹主要是存放 vuex 相关信息的
更多 vuex 相关使用方法请访问:https://vuex.vuejs.org/zh-cn/
在 store 文件夹下创建目录结构 ↓
| 1 | store | 
下面开始改造 store 文件夹 ↓
- 在 - mutation-types.js中添加一个常量- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95- export const BASE = { 
 setUserInfo: 'base/setUserInfo',
 }
 export function mutations (states) {
 addFirstUpperCaseToPrototype()
 addFlatToPrototype()
 return {
 // 单个state赋值 https://forum.vuejs.org/t/vuex-state/39459/5
 ...Object.keys(states).reduce(
 (obj, key) => ({
 ...obj,
 [`set${key.firstUpperCase()}`]: (state, payload) => (state[key] = payload)
 }),
 {}
 ),
 // 多个state批量赋值
 setData (state, payload) {
 // state = { ...state, ...payload } // eslint-disable-line
 Object.assign(state, payload)
 },
 // 深度合并赋值
 setDataDeep: mergeJSON,
 // 表格页码改变
 pageChange (state, payload) {
 const { list, total } = payload
 state.total = total
 list.forEach((el, index) => {
 el.key = index
 })
 state.list.splice(0, state.list.length, ...list)
 }
 }
 }
 // #region addFirstUpperCaseToPrototype - String原型链方法firstUpperCase
 /**
 * String原型链方法firstUpperCase
 * @export
 */
 export function addFirstUpperCaseToPrototype () {
 /* eslint-disable */
 String.prototype.firstUpperCase = function() {
 return (([first, ...rest]) => first.toUpperCase() + rest.join(''))(this) // return this.replace(/^\S/, s => s.toUpperCase())
 }
 /* eslint-enable */
 }
 // #endregion
 // #region addFlatToPrototype - Array原型链方法flat
 /**
 * Array原型链方法flat
 * @export
 */
 export function addFlatToPrototype () {
 /* eslint-disable */
 if (!Array.prototype.flat) {
 Array.prototype.flat = function(num = 1) {
 if (!Number(num) || Number(num) < 0) {
 return this
 }
 let arr = []
 this.forEach(item => {
 if (Array.isArray(item)) {
 arr = arr.concat(item.flat(--num))
 } else {
 arr.push(item)
 }
 })
 return arr
 }
 }
 /* eslint-enable */
 }
 // #endregion
 // #region mergeJSON - 合并JSON
 /**
 * 直接修改 main 将 minor 合并到 main
 * @export
 * @param {*} main
 * @param {*} minor
 */
 export function mergeJSON (main = {}, minor = {}) {
 Object.keys(minor).forEach((key) => {
 const type = Object.prototype.toString.call(minor[key])
 if (type === '[object Object]') {
 mergeJSON(main[key] || {}, minor[key] || {})
 } else {
 main[key] = type === '[object Null]' || type === '[object Undefined]' ? main[key] : minor[key]
 }
 })
 }
 // #endregion
- 在 - action-types.js中添加一个常量- 1 
 2
 3- export const BASE = { 
 login: 'base/login',
 }
- 修改 - modules/base.js- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44- import Vue from 'vue' 
 import { BASE, mutations } from '../mutation-types'
 import axios from 'axios'
 import qs from 'qs'
 const states = {
 version: '',
 token: null,
 user: {
 userID: '',
 userName: '',
 name: '',
 tel: '',
 email: '',
 head: '',
 },
 }
 export default {
 namespaced: true, // https://vuex.vuejs.org/zh/guide/modules.html#命名空间
 state: states,
 getters: {
 versionGetter(state, getters) {
 return state.version
 },
 },
 mutations: {
 ...mutations(states),
 setUserInfo(state, userInfo) {
 userInfo.userID && (state.user.userID = userInfo.userID)
 userInfo.USERNAME && (state.user.userName = userInfo.USERNAME)
 userInfo.NAME && (state.user.name = userInfo.NAME)
 userInfo.TEL && (state.user.tel = userInfo.TEL)
 userInfo.EMAIL && (state.user.email = userInfo.EMAIL)
 userInfo.HEAD && (state.user.head = userInfo.HEAD)
 },
 },
 actions: {
 async login({ commit, dispatch, state }, { userName, password }) {
 let userInfo = await axios.post('/api/login', qs.stringify({ userName, password }))
 commit(BASE.SET_USER_INFO, userInfo)
 },
 },
 }
- 修改 vuex 主文件 - index.js,组合所有状态模块- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- import Vue from 'vue' 
 import Vuex from 'vuex'
 import root from './root'
 import base from './modules/base'
 // import createLogger from 'vuex/dist/logger' //vuex内置的Logger日志插件
 const debug = process.env.NODE_ENV !== 'production' // 发布品种时需要用 Webpack 的 DefinePlugin 来转换 process.env.NODE_ENV !== 'production' 的值为 false
 Vue.use(Vuex)
 const state = {}
 export default new Vuex.Store({
 ...root
 modules: {
 base,
 // https://vuex.vuejs.org/zh/guide/modules.html#模块动态注册
 },
 strict: debug, // 开发阶段使用
 // plugins: debug ? [createLogger()] : []//vuex插件,https://vuex.vuejs.org/zh/guide/plugins.html
 })
- 修改 - main.js,引入 vuex- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- //... 
 import store from './store/index'
 //...
 new Vue({
 el: '#app',
 router,
 store,
 // components: { App },
 // template: '<App/>',
 render: h => h(App), // https://cn.vuejs.org/v2/guide/render-function.html#JSX
 })
https://juejin.im/post/5bcd967b6fb9a05d07197b1e
Vuex 实战:如何在大规模 Vue 应用中组织 Vuex 代码
super-vuex
添加mixins文件夹
目录结构 ↓
| 1 | mixins | 
添加filters文件夹
目录结构 ↓
| 1 | filters | 
添加utils文件夹
目录结构 ↓
| 1 | utils | 
src/main.js中添加全局引用 ↓
| 1 | import * as filters from './utils/filters' | 
封装 axios
| 1 | import Vue from 'vue' | 
config 配置
build 生成的文件路径使用相对路径
修改config/index.js文件中build节点的assetsPublicPath值
| 1 | module.exports = { | 
开发的的时候需要使用代理(proxy)跨域访问服务器接口
修改config/index.js文件中dev节点的proxyTable值
| 1 | module.exports = { | 
分离线上环境和本地环境的配置信息
修改config/dev.env.js与config/prod.env.js,为不同的环境配置文件添加与NODE_ENV同级的环境变量
| 1 | module.exports = { | 
通用样式(SCSS)
目录结构 ↓
| 1 | assets | 
base.scss
| 1 | @charset "utf-8"; | 
common.scss
| 1 | @charset "UTF-8"; | 
fun.scss
| 1 | @charset "UTF-8"; | 
mixin.scss
| 1 | @charset "UTF-8"; | 
variable.scss
| 1 | @charset "UTF-8"; | 
demo 地址:https://github.com/MrLeo/wedive
查缺补漏
我用了 axios , 为什么 IE 浏览器不识别(IE9+)
那是因为 IE 整个家族都不支持 promise, 解决方案:
| 1 | npm install es6-promise | 
| 1 | // 在 main.js 引入即可 |