Vue项目的搭建(vue cli2)

前言:使用vue cli2 搭建前端项目而整理的一份文档

一、项目环境

1、node安装

下载地址:http://nodejs.cn/download/

安装检查:

命令:
node -v
npm -v

注:若需更改node模块(node_modules)的安装目录自行百度,由于创建的Vue项目中node模块是安装在项目文件夹下就不做更改了。

 若使用淘宝npm镜像(cnpm)通过以下命令安装:

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

2、Vue-Cli安装

1)、vue-cli@2.X版本

官方文档:https://github.com/vuejs/vue-cli/tree/v2#vue-cli--

注:使用的一些UI组件不适配vue-cli@3.x,所以需要安装vue-cli@2.x

比如VUX

安装命令:

$ npm install -g vue-cli

查看版本:

$ vue –version
使用:
$ vue init <template-name> <project-name>

例如:
$ vue init webpack my-project

将从vuejs-templates/webpack中提取模板信息,根据此模板信息生成项目(./my-project/)

 2)、@vue/cli 3.x 版本

官方文档:https://cli.vuejs.org/zh/guide/

安装命令:

$ npm install -g @vue/cli

查看版本:

$ vue --version

使用:

$ vue create <project-name>

二、项目创建

本项目使用的vue-cli版本:2.9.6

1、创建本地项目

在本地/d/Projects目录下创建名为project-demo的项目

Vue build

第一个选项可以不基于.vue文件开发,在运行时会进行编译

第二个选项基于.vue文件开发,比第一个选项小6KB

使用vue-router

使用ESLint进行代码检测(ESLint 是一个语法规则和代码风格的检查工具,可以用来保证写出语法正确、风格统一的代码。)

ESLint代码检测规则(本项目使用Standard),官方文档连接:

Standard:https://github.com/standard/standard/blob/master/docs/README-zhcn.md

Airbnb:https://github.com/airbnb/javascript

安装完成后运行上述命令:

$ cd project-demo
$ npm run dev

根据运行成功后的地址在浏览器进行访问

2、目录结构如下:

.
|-- README.md
|-- build
|   |-- build.js
|   |-- check-versions.js
|   |-- logo.png
|   |-- utils.js
|   |-- vue-loader.conf.js
|   |-- webpack.base.conf.js
|   |-- webpack.dev.conf.js
|   `-- webpack.prod.conf.js
|-- config
|   |-- dev.env.js
|   |-- index.js
|   `-- prod.env.js
|-- index.html
|-- package-lock.json
|-- package.json
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- HelloWorld.vue
|   |-- main.js
|   `-- router
|       `-- index.js
`-- static

3、将本地仓库与线上仓库关联:

$ cd /project-demo
$ git init
$ git remote add origin <线上git仓库地址(SHH)>
$ git add .
$ git commit
$ git push -u origin master

三、项目初始化配置

附:使用Visual Studio Code推荐安装以下扩展程序

1)    Vetur
2)    ESLint
3)    Beautify
4)    GitLens — Git supercharged
5)    Git History
6)    HTML CSS Support
7)    HTML Snippets
8)    Vue 2 Snippets
9)    Debugger for Chrome

附:目录结构

项目结构多采用vue-element-admin项目结构:https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/

|-- README.md
|-- build                            # 项目打包配置
|-- config                           # 项目配置
|-- index.html                       # html模板
|-- package-lock.json                # postcss 配置
|-- package.json                     # package.json
|-- src                              # 源代码
|   |-- App.vue                      # 入口页面
|   |-- api                          # 所有请求
|   |-- assets                       # 主题 字体等静态资源
|   |-- axios                        # axios通用配置
|   |-- components                   # 全局公用组件
|   |-- directive                    # 全局指令
|   |-- filters                      # 全局 filter
|   |-- layout                       # 全局 layout
|   |-- main.js                      # 入口文件 加载组件 初始化等
|   |-- router                       # 路由
|   |-- store                        # vuex配置,全局 store管理
|   |-- styles                       # 全局样式、自定义主题等
|   |-- utils                        # 全局公用方法
|   `-- views                        # 所有页面
`-- static

1、ESLint规则配置

修改.eslintrc.js文件配置,在rules对象中添加以下配置(其他配置默认):

// 在函数括号之前不允许空格
'space-before-function-paren': ['error', 'never']

修改package.json文件配置:

添加后运行以下命令可以快速修复ESLint报错:

$ npm run lint

2、UI组件安装

1)、PC端(element-ui)

官方文档https://element.eleme.cn/#/zh-CN/component/installation

npm安装:

$ npm i element-ui -S

Element完整引入

main.js 中写入以下内容:

import Vue from 'vue'

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

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

Vue.config.productionTip = false

Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  render: h => h(App)
})

2)、移动端(VUX/Mint UI)

VUX文档https://doc.vux.li/zh-CN/

Mint UI文档https://mint-ui.github.io/docs/#/zh-cn2

3、css预处理器安装(less/sass/stylus)

本项目安装sass预处理器

Sass文档:https://www.sass.hk/docs/

安装:

$ npm install node-sass --save-dev
$ npm install sass-loader --save-dev

4、axios配置

文档https://www.kancloud.cn/yunye/axios/234845

1)、npm安装:

$ npm install axios

2)、请求拦截配置

src目录下创建axios文件夹,并于其中创建index.js文件,内容如下(PC端配置了element-ui的一个加载组件):

import axios from 'axios'
import { Notification, Loading } from 'element-ui'

// 根据环境设置请求baseURL
axios.defaults.baseURL = process.env.API_ROOT
// 请求超时时间
axios.defaults.timeout = 6000
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8'

let loading
// 请求拦截器
axios.interceptors.request.use(
  config => {
    // 加载提示
    loading = Loading.service({
      lock: true,
      text: '拼命加载中',
      spinner: 'el-icon-loading',
      background: 'rgba(0, 0, 0, 0.7)'
      // background: 'rgba(255, 255, 255, 0)'
    })
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
axios.interceptors.response.use(
  response => {
    // 关闭加载提示
    loading.close()
    return response
  },
  error => {
    // 关闭加载提示
    loading.close()
    if (error && error.response) {
      switch (error.response.status) {
        case 400:
          Notification.error({
            message: '请求错误'
          })
          break

        case 403:
          Notification.error({
            message: '拒绝访问'
          })
          break

        case 404:
          Notification.error({
            message: '请求地址出错'
          })
          break

        case 408:
          Notification.error({
            message: '请求超时'
          })
          break

        case 500:
          Notification.error({
            message: '服务出错'
          })
          break

        case 501:
          Notification.error({
            message: '网络未实现'
          })
          break

        case 502:
          Notification.error({
            message: '网络错误'
          })
          break

        case 503:
          Notification.error({
            message: '服务不可用'
          })
          break

        case 504:
          Notification.error({
            message: '网络超时'
          })
          break

        default:
      }
    } else if (error.message === 'Network Error') {
      Notification.error({
        message: '网络错误'
      })
    } else if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) {
      Notification.error({
        message: '请求超时,请重试'
      })
    }

    return Promise.reject(error)
  }
)

export default axios

3)、API请求管理

src目录下新建api文件夹,文件夹中根据API类型新建对应的js文件模块以便管理。

例如用户信息请求API新建userApi.js文件

文件内容格式如下:

import request from '@/axios'

/**
 * 用户登录
 * @param {Object} data 用户账号信息对象
 */
export function login(data) {
  return request({
    url: '/user/login',
    method: 'post',
    data
  })
}

/**
 * 获取用户信息
 * @param {String} token token
 */
export function getInfo(token) {
  return request({
    url: '/user/info',
    method: 'get',
    params: { token }
  })
}

4)、js中调用

//script标签内进行导入
import * as userApi from '@/api/userApi'

//使用:
userApi.login({username: '张三', password: '123456'})
    .then(res => {
        const { data } = res
        console.log(data)
})

5、Vue Router配置

1)、router/index.js配置文件修改

文档https://router.vuejs.org/zh/installation.html

|-- src
…
|   |-- layout
|   |   `-- index.vue
…
|   |-- router
|   |   |-- index.js
|   |   `-- modules
|   |       `-- userCenter.js
import Vue from 'vue'
import Router from 'vue-router'

import Layout from '@/layout'

/* Router Modules */
import userRouter from './modules/userCenter'

Vue.use(Router)

const router = new Router({
  // 路由跳转后重新定位到顶部
  scrollBehavior: () => ({ y: 0 }),
  routes: [
    userRouter,
    {
      path: '/',
      name: 'Layout',
      component: Layout,
      meta: {title: '主页'}
    },
    { path: '*', component: () => import('@/components/404') }
  ]
})

export default router

可以根据项目需要可配置导航守卫、路由模块等相关配置

2)、全局layout

src目录下新建layout文件夹,其中新建index.vue文件

<template>
  <div>
    Layout
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'Layout'
}
</script>

<style lang="scss" scoped>

</style>

6、Vuex配置

文档:https://vuex.vuejs.org/zh/

1)、Vuex安装

$ npm install vuex --save

2)、vuex-persistedstate安装

文档:https://github.com/robinvdvleuten/vuex-persistedstate

vuex-persistedstate是一个将vuex持久化的插件

$ npm install --save vuex-persistedstate

3)、配置

src目录下新建store文件夹,其下新建index.js、mutation-types.js文件modules文件夹

-- store
   |   |-- index.js
   |   |-- modules
   |   |   `-- user.js
   |   `-- mutation-types.js

store 分割成模块(module),每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

使用常量替代 mutation 事件类型(使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名),把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然。

新建mutation-types.js文件存放常量,例如:

// mutation-types.js
// user modules
export const SET_USER_NAME = 'SET_USER_NAME'
// user.js
import * as types from '../mutation-types'

const state = {
  userName: ''
}

const mutations = {
  [types.SET_USER_NAME](state, str) {
    state.userName = str
  }
}

const actions = {
  saveUserName({ commit }, str) {
    commit(types.SET_USER_NAME, str)
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

index.js配置如下:

vuex-persistedstate插件仅将需要持久化的状态值进行持久化。

import Vue from 'vue'
import Vuex from 'vuex'
import CreatePersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

// webpack v4.35.2 依赖管理
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', false, /.js$/)

// 自动请求modules目录下的模块文件
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // 模块名为modules目录下的js文件名
  const moduleName = modulePath.replace(/^./(.*).w+$/, '$1')

  // value 为请求到的模块文件内容 {default:{state:{...},mutations:{...},actions:{...}}, __esModule: true}
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const vuexPersisted = new CreatePersistedState({
  key: 'VuexPersisted',
  storage: window.localStorage,
  reducer: state => ({
    user: {
      userName: state.user.userName
    }
  })
})

const store = new Vuex.Store({
  modules,
  plugins: [vuexPersisted]
})

export default store

4)、组件中使用

使用方式就不一一列举了,以下仅列举其中一种,其他的可以去看官方文档。

访问state值时,使用对象展开运算符将此对象混入到局部计算属性中。

import { mapState } from 'vuex'

export default {
    computed: {
        ...mapState('user', ['userName'])
    },

      mounted() {
        console.log(this.userName)
}
}

访问actions,使用对象展开运算符将此对象混入到局部 methods 中。

import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions('user', ['saveUserName']),

    // 登录时存储用户名
    login() {
      this.saveUserName('80xxxxx06@qq.com')
    }
  }
}

7、自定义样式/主题配置

src目录下新建styles文件夹

|-- src
…
|   |-- styles
|   |   |-- border.css                  #app一像素边框解决
|   |   |-- element-ui.scss             #自定义的element-ui组件样式
|   |   |-- element-variables.scss      #通过element-ui样式变量修改通用主题
|   |   |-- index.scss                  #全局通用样式引入/定义
|   |   |-- mixin.scss                  #自定义的scss混合指令
|   |   |-- reset.css                   #css样式重置文件
|   |   |-- transition.scss             #自定义过渡样式
|   |   `-- variables.scss              #自定义样式变量

main.js中引入

import '@/styles/index.scss' // 全局 css 样式

8、打包相关配置修改

1)、config/index.js文件修改

将文件中build对象中assetsPublicPath值改为’./’

assetsPublicPath: './',

2)、build/utils.js文件修改

if (options.extract) {
return ExtractTextPlugin.extract({
       use: loaders,
       publicPath: '../../',
       fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}

以上配置中添加了 publicPath 配置 ’../../’

此配置解决打包后图片读取路径错误问题

9、多环境打包配置

一)、配置方式一:

https://www.cnblogs.com/VoiceOfDreams/p/11052447.html

二)、配置方式二:

注:由于我之前写文档一的配置方式稍显繁琐,现将文档一的配置进行简化。此次文档就只配置开发、测试、生产三个环境,添加其他环境的配置方式一样。

1、安装依赖:cross-env

$ npm i --save-dev cross-env

2、修改项目 package.json 文件

"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --fix --ext .js,.vue src",
    "build:dev": "cross-env NODE_ENV=production ENV_CONFIG=dev node build/build.js",
    "build:test": "cross-env NODE_ENV=production ENV_CONFIG=test node build/build.js",
    "build:prod": "cross-env NODE_ENV=production ENV_CONFIG=prod node build/build.js"
},

3、修改项目 config 配置文件

目录结构
|-- config
|   |-- dev.env.js
|   |-- index.js
|   |-- prod.env.js
|   `-- test.env.js
1)、修改 dev.env.js 文件
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

const env = process.env.NODE_ENV

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  ENV_CONFIG: '"dev"',
  API_ROOT: env === 'production' ? '"http://(线上开发环境请求地址)"' : '"/apis"'
})
2)、添加 test.env.js 文件
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"testing"',
  ENV_CONFIG: '"test"',
  API_ROOT: '"http://(线上测试环境请求地址)"'
})
3)、修改 prod.env.js 文件
'use strict'
module.exports = {
  NODE_ENV: '"production"',
  ENV_CONFIG: '"prod"',
  API_ROOT: '"http://(线上生产环境请求地址)"'
}
4)、修改 index.js 文件

解决本地开发启动后浏览器跨域问题,在此处配置服务代理。

dev对象参数下修改如下配置:

proxyTable: {
  '/apis': {
        target: 'http://(本地开发环境请求地址)',
       changeOrigin: true, // 是否允许跨域
       pathRewrite: {
         '^/apis': '' // 重写
       }
    },
},

build 对象参数下添加如下参数

devEnv: require('./dev.env'),
testEnv: require('./test.env'),
prodEnv: require('./prod.env'),

4、修改 build.js 文件

// process.env.NODE_ENV = 'production'  // 将此行代码注释

// const spinner = ora('building for production...')
const spinner = ora('building for ' + process.env.NODE_ENV + ' of ' + process.env.ENV_CONFIG + ' production...')

 

5、修改 webpack.prod.conf.js 文件

原代码
const env = require('../config/prod.env')


修改后
const env = config.build[process.env.ENV_CONFIG+'Env']

三)、项目中 HTTP 请求设置

配置文档一中是在 API 文件中获取配置的请求地址,也可以在 axios 配置中设置统一的默认请求地址

详见 axios 配置中,axios 文件夹下的 index.js 配置文件

// 根据环境设置请求baseURL
axios.defaults.baseURL = process.env.API_ROOT
原文地址:https://www.cnblogs.com/VoiceOfDreams/p/11442650.html