前端初学者的第一个Vue后台管理项目总结1:基础架构篇

1,904 阅读6分钟

系列文章:

  1. 登录与权限控制

Vue响应式原理系列(硬核)

  1. 基本原理
  2. 数组的处理
  3. 渲染watcher

最近终于完成了自己的第一个Vue项目,是一个简单的后台管理系统,业务模块很少,主要是实现了一些自己想做的功能。在做项目期间踩了很多坑,体会到了前端对于非科班转行同学深深的恶意,因此想把自己的经验总结为几篇文章,希望能够帮到和我一样的同学。

这是本系列的第一篇文章,主要介绍项目的基础结构(本项目采用vue-cli4.0

├── public                 
├── src                   
│   ├── api               
│   ├── assets            
│   ├── components        
│   ├── config   
│   ├── plugins   
│   ├── router            
│   ├── store                   
│   ├── utils                     
│   ├── views             
│   ├── App.vue           
│   ├── main.js           
│   └── permission.js     
├── package.json            
├── vue.config.js      
├── .env.development
└── .env.production

项目的整体结构和很多vue实战课程中的差不多,我将针对本项目中不同的地方,以及很多初学者比较困惑的点进行讲解

components

components
  ├── aaa.vue        
  ├── bbb 
  ├── ccc 
  ├── ddd
  └── index.js      

我们的components文件夹可能有很多模块,文件,可以使用一个index.js作为统一导入入口

export { default as AAAA } from './aaaa'

导入时就不需要指定文件夹了,只需要

import AAAA from 'src/components'

plugins

plugins
  ├── components           // 公共组件
  │	  ├── modules         
  │	  └── index.js         
  ├── directives           // 自定义全局指令
  │	  ├── directives.js
  │	  └── index.js
  ├── filters              // 自定义全局过滤器
  │	  ├── filters.js
  │	  └──index.js
  ├── mixins.js            // 自定义minxin
  └── index.js      

插件安装

// 以mixins.js为例
export default function(Vue) {
  Vue.mixin({
    // ...
  })
}

// plugins/index.js
import installDirectives from './directives'
import installFilters from './filters'
import installMixins from './mixins'
import registerComponents from './components'

export default {
  install (Vue) {
    installDirectives(Vue)
    installFilters(Vue)
    installMixins(Vue)
    registerComponents(Vue)
  }
}

自动化注册

自动化也是前端工程化的一部分,因此本项目plugins中的模块均采用了自动化组册的方式,无需手动引入,需要增加内容时只需要在注册表中添加即可

mixins比较简答,只需要像上面演示的写法即可

directives & filters

filters为例,目录结构如下

filters            
  ├── filters.js    // 注册表 
  └── index.js      // 注册器

filters.js是一张过滤器注册表,该文件需要导出一个对象

const filters = {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

export default filters

index.js是一个自动化的注册器

import filters from './filters' // 导入过滤器注册表

export default function (Vue) {
  // 过滤该注册表对象,并进行全局过滤器的注册
  Object.keys(filters).forEach(key => Vue.filter(key, filters[key]))
}

通过这种方式,当需要添加过滤器时,只需要在注册表filters.js中添加对应方法即可,自定义指令的注册方式与过滤器注册方式相同

components

目录结构如下

components            
  ├── modules       // 组件文件夹,公共组件放在这里
  └── index.js      // 注册器

全局组件的自动注册需要用到webpack提供的require.context这个api

import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

function installer (Vue) {
  // 获取目标文件夹下的所有 .vue 文件的路径
  const context = require.context(
    './modules',
    true,
    /\.vue$/
  )
  
  context.keys().forEach(filePath => {
    // 由文件路径获取组件对象
    const config = context(filePath)
    let componentName = filePath.replace(/^.*\/+(.*)\.vue/, '$1')
    componentName = upperFirst(camelCase(componentName))
    // 组件全局注册
    Vue.component(componentName, config.default || config)
  })
}

export default installer

通过这种方式,在增加全局的基础组件时只需要在src/plugins/components/modules下添加vue组件即可,并且可以嵌套多层文件夹

router

对于路由文件来说,同样可以使用自动注册全局组件的方式,这样可以将路由分为多个模块,减少路由文件的代码量,提高代码的可读性,添加页面时也比较方便。这样做有一个问题,就是根据路由生成菜单栏时会有一个顺序的问题,但是可以在meta中添加一个sort字段,来确定该路由在菜单栏的顺序,大家可以根据实际情况酌情选择。

多环境

相信很多前端新手和我一样,在遇到这部分内容时很头痛,不知道环境变量是什么意思,下面,我将讲解一下为什么采用环境变量,以及环境变量的配置方法

为什么要使用环境变量

简单来说,一个项目可以分为两个阶段:开发和上线。开发阶段和上线阶段会有不同的配置,举个简单的例子,比如开发阶段,我们可以使用mock来模拟数据,因此我们在使用axios发起请求时会使用mock的接口地址,而项目上线后会使用公司后台提供的实际接口,那么难道说我们的项目在上线前,还要修改代码中的接口地址吗?这显然是不现实的。因此,针对这个问题,我们可以采用不同的环境变量来标识项目所处的环境,比如production表示生产环境,development表示开发环境,test表示测试环境等等。我们通过环境变量来获取项目所处的环境,从而采用当前环境的接口地址等配置。

环境变量的设置

package.jsonscripts字段中,可能会有这段脚本代码

"scripts": {
    "dev": "vue-cli-service serve",
},

当我们使用npm run dev运行这段脚本时,我们的项目会运行在开发环境下,这是因为该脚本默认环境为开发环境,我们可以通过--mode来指定环境

"scripts": {
    "dev": "vue-cli-service serve --mode development",
},

同样,我们还可以定义其他环境的脚本

"scripts": {
    "dev": "vue-cli-service serve --mode development",
    "build": "vue-cli-service build --mode production"
},

现在,我们的项目能够运行在不同的环境下了,但是,我们如何在代码里获取环境变量呢?答案是process.env.NODE_ENV,通过这个api,我们就能得到项目所处的环境了。

问题又来了,我们虽然能知道项目所处环境了,但是我们如何根据运行环境来进行不同的配置呢?vue-cli为我们提供了一个方式,就是通过在项目根目录下放置.env文件。

├── public                 
├── src                      
├── package.json            
├── vue.config.js      
├── .env.development   // development 环境的配置
└── .env.production    // production 环境的配置

.env文件中,我们可以用key=value的方式来定义环境变量

NODE_ENV=development
Foo=bar

这里有一个点需要注意,在本地开发中,我们的代码是运行在nodejs环境下的,所以我们能用process.env来获取相应的变量,比如process.env.Foo。但是,我们的代码实际上是要跑在用户浏览器上的,而浏览器并没有process.env。针对这个问题,vue-cli为我们提供了解决方法,在变量前加上VUE_APP_前缀,这样,我们就可以在客户端代码中访问该变量了,比如

NODE_ENV=development
VUE_APP_BASE_URL=/dev-api
VUE_APP_TIMEOUT=1000
VUE_APP_TITLE=开发版

然后,我们就可以在config/index.js中引入对应的变量了

export const BASEURL = process.env.VUE_APP_BASE_URL
export const TIMEOUT = process.env.VUE_APP_TIMEOUT
export const TITLE = process.env.VUE_APP_TITLE

vue.config.js基础配置

跨域配置

跨域也是很多新手同学会比较头疼的一个问题,我们可以采用webpack-dev-server提供的代理解决跨域问题。

devServer: {
  host: 'localhost',
  port: 9999,
  proxy: {
    // 你的BASE_URL
    '/api': {
      // 你的接口地址
      target: 'xxxx',
      changeOrigin: true,
      pathRewrite: {
        '^./api': ''
      }
    }
  }

设置别名

可以使用chainWebpack来设置路径别名,提高开发效率:

chainWebpack: (config) => {
    config.resolve.alias
      // 可根据实际情况自行设置
      .set('@', path.resolve(__dirname, 'src'))
      .set('@assets', path.resolve(__dirname, 'src/assets'))