一. 项目目录结构
|-- build 项目构建(webpack相关代码)
| |-- build.js 生成环境构建代码
| |-- check_version.js 检查node、npm等版本
| |-- utils.js 构建工具
| |-- vue-loader.conf.js webpack loader配置
| |-- webpack.base.conf.js webpack基础配置
| |-- webpack.dev.conf.js webpack开发环境配置,构建开发本地服务器
| |-- webpack.prod.conf.js webpack生成环境配置
|-- config 项目开发环境配置
| |-- dev.env.js 开发环境变量
| |-- index.js 项目一些配置变量
| |-- prod.env.js 生成环境变量
|-- src 源码目录
| |-- components vue公共组件
| |-- router vue路由管理
| |-- App.vue 页面入口文件
| |-- main.js 程序入口文件,加载各种公共组件
|-- static 统一放置项目所需的静态资源文件
|-- .gitignore git上传需要忽略的文件格式
|-- README.md 项目说明
|-- index.html 入口文件
|-- package.json 项目基本信息,包依赖信息等
所有业务代码统一放在src目录下,对于项目层级的划分可以:
- 抽离所有的api接口统一管理,每个模块的api也单独管理
- 所有单页早src下新建views管理所有页面
- 项目使用的所有公共方法,以及相关的工具,统一在src下新建utils文件夹管理
- 项目所需要用到的字体统一在src下新建fonts管理
- 项目所需要的主题统一在src下新建theme管理
- 公共css文件在src下新建style管理
二、代码基本规范
<script>
export default {
//组件名称,可以不写
name: 'name',
//引入组件,需要引入子组件时使用
components: {},
//接受父组件传递的数据
props: {},
//过滤器
filter: {},
//混入
mixins: [],
//组件实例数据
data() {
return {
}
},
//计算属性,可以不写
computed: {},
//监听属性变化 执行异步或者是开销比较大的操作
watch: {},
//渲染函数jsx
render(h) => {},
//页面初始化方法,在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图
created(){},
//页面初始化方法,在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图
mounted() {},
//实例方法集合
methods: {},
}
</script>
生命周期钩子 | 组件状态 |
beforeCreate | 实例初始化之后,this指向创建的实例,不能访问到data、computed、watch、methods上的方法和数据 |
created | 实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到$el属性,$ref属性内容为空数组 |
beforeMount | 在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数 |
mounted | 实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问 |
beforeupdate | 响应式数据更新时调用,发生在虚拟DOM打补丁之前 |
updated | 虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作 |
beforeDestroy | 实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例 |
destroyed | 实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁 |
beforeCreate 创建之前:已经完成了 初始化事件和生命周期
created 创建完成:已经完成了 初始化注册和响应
beforeMount 挂载之前:已经完成了模板渲染
mounted :挂载之后:已完成HTML虚拟化,创建了el节点 可以操作DOM了
beforeDestroy :摧毁之前:整个vue都处在实时监控空渲染和更新
destroyed: 已摧毁,已经摧毁了观察者,子元素和事件监听
三、组件设计原则
- 容错处理, 这个要做好, 极端场景要考虑到, 不能我传错了一个参数你就原地爆炸;
- 缺省值(默认值)要有, 一般把应用较多的设为缺省值;
- 颗粒化, 把组件拆分出来;
- 一切皆可配置, 如有必要, 组件里面使用中文标点符号, 还是英文的标点符号, 都要考虑到;
- 场景化, 如一个dialog弹出, 还需要根据不同的状态封装成success, waring等;
- 有详细的文档/注释和变更历史, 能查到来龙去脉, 新版本加了什么功能是因为什么;
- 组件名称, 参数prop, emit, 名称设计要通俗易懂, 最好能做到代码即注释这种程度;
- 可拓展性, 前期可能不需要这个功能, 但是后期可能会用上, 要预留什么, 要注意什么, 心里要有逼数;
- 规范化,我这个input组件, 叫on-change, 我另外一个select组件叫change, 信不信老子捶死你;
四、请求Axios
import axios from 'axios';
import { Message } from 'element-ui';
// 请求Url
let proEnv = require("@/config/prod.env");
let devEnv = require("@/config/dev.env");
//dev.env.js代码
//module.export = {
// NODE_ENV: '"development"',
// API_ROOT: 'http://localhost',
//}
const env = process.env.NODE_ENV;
let target = "";
if(env === 'production'){
target = proEnv.API_ROOT;
} else if(env === 'dev'){
target = devEnv.API_ROOT;
}
// 设定超时
axios.default.timeout = 10000;
// 请求拦截器 对request
axios.interceptors.request.use(config => {
// 设置请求后台接口路径
config.baseURL = target;
// 发起请求之前判断假设token存在localStorage中
// 如果token存在,在每次得请求header上带上token
// token存在,但是token已经过期,在响应拦截器中对返回得状态进行判断
const token = window.localStorage.token;
token && (config.headers = {
'Authorization': token,
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
});
return config;
}, err => {
return Promise.reject(err);
});
// 请求拦截器 对response
axios.interceptors.response.use(response => {
if(response.status === 200){
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
}, err => {
if(err.response){
let status = err.response.status;
switch(status) {
// 401未登陆则跳转到登陆页面,并且携带当前页面得path
// 登陆成功后 返回当前页面
case 401:
router.replace({
path: '/login',
query: {
redirect: router.currentRouter.fullPath
}
});
break;
// 403 token过期,对用户进行提示
case 403:
Message({
message : '登陆过期,请重新登陆',
type: 'error',
duration: 2000
})
break;
case 404:
Message({
message: '网络请求不存在',
type: 'error',
duration: 2000
})
break;
//其他错误统一抛出,如果要对其中得返回码进行其他操作,在视情况在加case 进行操作
default:
Message({
message: error.response.message,
type: 'error',
durantion: 2000
})
}
}
return Promise.reject(err);
})
/**
* GET
* @param url
* @param data
* @return { Promise }
*/
export function get(url, params = {}) {
return new Promise((resolve, reject) => {
axios.get(url, {
params: params
})
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
}
/**
* POST
* @param url
* @param data
* @return { Promise }
*
*/
export function post(url, params = {}) {
return new Promise((resolve, reject) => {
axios.post(url, params)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
}
/**
* PATCH
* @param url
* @param data
* @returns { Promise }
*
*/
export function patch(url, params = {}) {
return new Promise((resolve, reject) => {
axios.patch(url, params)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
}
/**
* put
* @param url
* @param data
* @returns { Promise }
*
*/
export function put(url, params = {}) {
return new Promise((resolve, reject) => {
axios.put(url, params)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
}
/**
* deltet
* @param url
* @param data
* @returns { Promise }
*
*/
export function delete(url, params = {}) {
return new Promise((resolve, reject) => {
axios.delete(url, params)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
}
参考资料