转:https://www.cnblogs.com/VoiceOfDreams/p/11442650.html
前言:使用vue cli2 搭建前端项目而整理的一份文档
1、node安装
安装检查:
命令:
node -v
npm -v注:若需更改node模块(node_modules)的安装目录自行百度,由于创建的Vue项目中node模块是安装在项目文件夹下就不做更改了。
若使用淘宝npm镜像(cnpm)通过以下命令安装:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org2、Vue-Cli安装
1)、vue-cli@2.X版本
注:使用的一些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 版本
安装命令:
$ 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:github.com/standard/st…
Airbnb:github.com/airbnb/java…
安装完成后运行上述命令:
$ 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项目结构:panjiachen.gitee.io/vue-element…
|-- 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 lint2、UI组件安装
1)、PC端(element-ui)
官方文档:element.eleme.cn/#/zh-CN/com…
npm安装:
$ npm i element-ui -SElement完整引入
在 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文档:doc.vux.li/zh-CN/
Mint UI文档:mint-ui.github.io/docs/#/zh-c…
3、css预处理器安装(less/sass/stylus)
本项目安装sass预处理器
Sass文档:www.sass.hk/docs/
安装:
$ npm install node-sass --save-dev
$ npm install sass-loader --save-dev4、axios配置
文档:www.kancloud.cn/yunye/axios…
1)、npm安装:
$ npm install axios2)、请求拦截配置
于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 axios3)、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配置文件修改
文档:router.vuejs.org/zh/installa…
|-- src
…
| |-- layout
| | `-- index.vue
…
| |-- router
| | |-- index.js
| | `-- modules
| | `-- userCenter.jsimport 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配置
1)、Vuex安装
$ npm install vuex --save2)、vuex-persistedstate安装
vuex-persistedstate是一个将vuex持久化的插件
$ npm install --save vuex-persistedstate3)、配置
于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 store4)、组件中使用
使用方式就不一一列举了,以下仅列举其中一种,其他的可以去看官方文档。
访问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、多环境打包配置
一)、配置方式一:
二)、配置方式二:
注:由于我之前写文档一的配置方式稍显繁琐,现将文档一的配置进行简化。此次文档就只配置开发、测试、生产三个环境,添加其他环境的配置方式一样。
1、安装依赖:cross-env
$ npm i --save-dev cross-env2、修改项目 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.js1)、修改 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