今年年初由于工作调动,从 Vue 转到了 React,由于对其深深的眷念,抽空总结下从 2016 年到现在基于 Vue 的实际项目在开发中的必备点。
I love Vue and use react just for work
Vue 官方配套文档很全,建议细读;同时建议使用 Vue CLI,不建议自行写
Webpack等配置文件,若需要复写配置可使用 vue.config.js
起手式
Node 版本要求
Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 最新)。你可以使用 nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本。
安装:
npm install -g @vue/cli
# OR
yarn global add @vue/cli
创建一个项目:
vue create my-project
# OR
vue ui
创建新项目的原型的过程不再赘述,根据实际需要选择即可。项目结构、文件信息这里不细说,根据命名即可知道代表的意思,下面说下在实际项目中需要额外添加的或注意的点。
常用点
Mock、环境区分、网络请求、骨架屏
Mock
实际开发中为提升开发效率、解决对 API 的依赖或实现离线开发,这些均会使用到 Mock。实现 Mock 的方式有很多,如:Webpack Server (拦截器/路由)、Mock.js、使用外部的 Mock Serve ,如 SSR、JSON Server 等。这里介绍基于 Webpack Server (拦截器/路由) 的实现方式。
新建 mock 目录
// mock/a.js
module.exports = {
// 地址
api: '/a',
// 返回数据
response: function(req, res, fs) {
res.json({ data: '这是mock数据' })
}
}
// vue.config.js
const path = require('path')
const fs = require('fs')
const mockDirPath = path.resolve(__dirname, './mock')
function mockProxy(app, mockDir) {
fs.readdirSync(mockDir).forEach(function(file) {
let filePath = path.resolve(mockDir, file)
if (fs.statSync(filePath).isDirectory()) {
mockProxy(app, filePath)
} else {
let mock = require(filePath)
app.all(mock.api, (req, res) => {
mock.response(req, res)
})
}
})
}
module.exports = {
devServer: {
open: true,
before: function(app) {
mockProxy(app, mockDirPath)
}
}
}
原理:对 express 使用一个类似于拦截器的方式,对网络请求进行处理。 缺点:mock 文件无法热加载
环境区分
实际项目的环境不仅仅只是简单的 development、production,还存在前后端对接联调阶段(前后端并行开发)、E2E 环境、测试环境等。可参考环境变量和模式
结合前面的 Mock ,假设需要 开发环境(mock) 和 联调环境(dev 下直接调用 API,假设地址为 http://localhost:8080/),实现方式如下:
修改package.json
<!-- package.json -->
"scripts": {
...
"dev": "vue-cli-service serve --mode mock",
"sys": "vue-cli-service serve"
...
}
新增 .env.mock文件
VUE_APP_MOCK=true
修改vue.config.js
// vue.config.js
const path = require('path')
const fs = require('fs')
const mockDirPath = path.resolve(__dirname, './mock')
function mockProxy(app, mockDir) {
fs.readdirSync(mockDir).forEach(function(file) {
let filePath = path.resolve(mockDir, file)
if (fs.statSync(filePath).isDirectory()) {
mockProxy(app, filePath)
} else {
let mock = require(filePath)
app.all(mock.api, (req, res) => {
mock.response(req, res)
})
}
})
}
const isMock = process.env.VUE_APP_MOCK
const isDev = process.env.NODE_ENV === 'development'
if (isDev) {
if (isMock) {
console.log(
'\x1B[33m%s\x1b[0m',
'===================== development mock ==================='
)
} else {
console.log(
'\x1B[33m%s\x1b[0m',
'===================== development joint debugging ==================='
)
}
}
// API 地址
const configProxy = 'http://localhost:8080/'
module.exports = {
devServer: {
open: true,
port: 9000,
before: function(app) {
if (process.env.VUE_APP_MOCK) {
mockProxy(app, mockDirPath)
}
},
proxy: isDev && !isMock ? configProxy : ''
}
}
若需要其它区分环境,可参考实现
网络请求
这里简单讲下官方推荐使用的 Axios,其它库的封装大同小异。以下方式仅供参考。
-
自行封装处理,添加个性化配置(如全局 Loading、异常拦截等)
新建
http.js,封装 Axios// http.js import Axios from 'axios' const install = Vue => { if (install.installed) { return } Axios.defaults.headers = { 'Content-Type': 'application/json; charset=utf-8' } // Axios.defaults.timeout = 20000 // 添加一个请求拦截器 Axios.interceptors.request.use( config => { return config }, error => { return Promise.reject(error) } ) // 添加一个响应拦截器 Axios.interceptors.response.use( response => { return response.data }, error => { return Promise.reject(error) } ) Vue.http = Axios Vue.prototype.$http = Axios } // auto install if (typeof window !== 'undefined' && window.Vue) { install(window.Vue) } export default install是否将
http实现为 插件 自行决定。可在
interceptors里添加 Loading 动画,这样虽可一劳永逸,但若出现短时间内发起连续的网络请求(如实现某个操作需要发起多次请求)会出现闪烁情况。可在
response里进行全局的简单异常处理,如根据返回错误码进行提示或跳转在
src/main.js引入// src/main.js ... import http from './http' Vue.use(http) ... -
使用第三方
如使用
vue-axiosimport Vue from 'vue' import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)// 使用方式 Vue.axios.get(api).then(response => { console.log(response.data) }) this.axios.get(api).then(response => { console.log(response.data) }) this.$http.get(api).then(response => { console.log(response.data) })
骨架屏
引入骨架屏避免首屏长时间白屏现象,原理是先在 html 模板的 <div id="app"></div> 中插入骨架,当首屏的 js 文件加载完成,会被替换为实际内容。此处使用 vue-skeleton-webpack-plugin 实现。
新增 Skeleton.vue 文件
<!-- src/Skeleton.vue -->
<template>
<div class="skeleton-wrapper">
<header class="skeleton-header"></header>
<div>
<div class="skeleton-body"></div>
<div class="skeleton-footer"></div>
</div>
</div>
</template>
<script>
export default {
name: 'skeleton'
}
</script>
<style scoped>
.skeleton-header {
height: 52px;
background: #3a89c9;
width: 100%;
}
.skeleton-body {
background: #f6f6f6;
margin: 20px 0 20px 0;
height: 15vh;
border-radius: 10px;
}
.skeleton-footer {
border-radius: 10px;
background: #f6f6f6;
min-height: 60vh;
}
</style>
新增 skeleton.js 文件
// src/skeleton.js
import Vue from 'vue'
import Skeleton from './Skeleton.vue'
export default new Vue({
components: {
Skeleton
},
render: h => h(Skeleton)
})
修改 vue.config.js 文件
// vue.config.js
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')
module.exports = {
chainWebpack: config => {
config.when(!isDev, config => {
config.plugin('skeleton').use(SkeletonWebpackPlugin, [
{
webpackConfig: {
entry: {
app: path.join(__dirname, './src/skeleton.js')
}
},
minimize: true,
quiet: true
}
])
})
}
}
若出现 vue-server-renderer(
vue-skeleton-webpack-plugin中使用了) 与项目中 Vue 版本不匹配 可自行安装vue-server-renderer进行版本覆盖