开发规范
本文档主要包括以下是三个部分
vue 框架构建及开发规范
webpack 打包优化
前端错误日志收集
文章目录
- 开发规范
- 前言
- 1、vue 框架构建及开发规范
- 1.1 规范目的
- 1.2 vue 项目框架搭建
- 1.3 axios 请求
- 1.4 工具类函数封装
- 1.5 命名规范
- 1.6 编码规范
- 1.7组件规范
- 1.7.1组件名为多个单词。
- 1.7.2组件文件名为pascal-case格式
- 1.7.3基础组件文件名为 base 开头,使用完整单词而不是缩写。
- 1.7.4和父组件紧密耦合的子组件应该以父组件名作为前缀命名
- 1.7.5在 Template 模版中使用组件,应使用 PascalCase 模式,并且使用自闭合组件。
- 1.7.6Prop 定义应该尽量详细
- 1.7.7如果特性元素较多,应该主动换行。
- 1.7.8 模板中使用简单的表达式
- 1.7.9 指令都使用缩写形式
- 1.7.10标签顺序保持一致
- 1.7.11 必须为 v-for 设置键值 key
- 1.7.12 v-show 与 v-if 选择
- 1.7.13 script 标签内部结构顺序
- 1.7.14 Vue Router 规范
- 2、webpack 打包优化
- 总结
前言
暂无
1、vue 框架构建及开发规范
1.1 规范目的
-
统一编码风格,规范,提高团队协作效率
-
在团队协作中输出可读性强,易维护,风格一致的代码
1.2 vue 项目框架搭建
1.2.1 脚手架构建
// 1.安装 vue-cli 脚手架构建工具
npm install --global vue-cli
// 2.构建于 webpack 模板的一个新项目,填写相关项目信息
vue init webpack my-project
// 3.安装项目依赖
npm install
1.2.2 项目目录
按如下文件目录搭建项目框架
src 主要源码目录
|-- assets 静态资源,统一管理
|-- components 公用组件,全局组件
|-- javascript JS相关操作处理
|-- ajax axios封装的请求拦截
|-- filters 全局过滤器
|-- utils 全局封装的工具类
|-- datas 模拟数据,临时存放
|-- router 路由,统一管理
|-- store vuex, 统一管理
|-- views 视图目录
|-- order 视图模块名
|-- |-- orderList.vue 模块入口页面
|-- |-- orderDetail.vue 模块入口页面
|-- |-- components 模块通用组件文件夹
1.2.3 UI框架选择
- pc端:依次推荐使用antdesign,elementui,iview
- 移动端/小程序/APP:uni-app
1.2.4 css预处理器
推荐使用less,可在global.less设置全局样式,如
- 常用样式设置原子类名
- 主题颜色, UI 设计规范等样式
- 全局组件公共样式
.colorTheme {
color: #40a9ff !important;
}
.fl {
float: left;
}
.fr {
float: right;
}
.clearfix:after {
clear: both;
content: '';
display: block;
width: 0;
height: 0;
visibility: hidden;
}
1.3 axios 请求
1.3.1 设置请求拦截和响应拦截
请求拦截
// request interceptor
request.interceptors.request.use(config => {
const token = storage.get(ACCESS_TOKEN)
// 如果 token 存在
// 让每个请求携带自定义 token 请根据实际情况自行修改
if (token) {
config.headers['Access-Token'] = token
}
return config
}, errorHandler)
响应拦截
// response interceptor
let isRefreshing = false
request.interceptors.response.use((response) => {
if (response.data.resCode === 200) {
} else {
}
}, errorHandler)
1.4 工具类函数封装
1.4.1 添加方法到vue实例的原型链上
export default {
install (Vue, options) {
Vue.prototype.util = {
method1(val) {
...
},
method2 (val) {
...
},
}
}
1.4.2 在main.js通过vue.use()注册
import utils from './js/utils'
Vue.use(utils)
1.5 命名规范
代码规范
- 文件夹和文件命名以业务或者模块名字为主,驼峰式命名。
- 组件命名遵循以下原则,使用驼峰命名(
carLib
)进行组件声明,使用短横线分隔命名(<car-lib></car-lib>
)进行使用。 - 当项目中需要自定义比较多的基础组件的时候,比如一些
button
,input
,icon
,建议以一个统一的前缀如Base
开头,这样做的目的是为了方便查找。 method
方法命名使用驼峰式,动词+名词,如 getData, submitForm- 变量命遵循语义化原则,使用驼峰式。
1.5.1 项目命名
全部采用小写方式,以中划线分割。
正例:mall-management-system
反例:mall_management-system / mallManagementSystem
1.5.2 目录命名
全部采用小写方式, 以中划线分隔,有复数结构时,要采用复数命名法, 缩写不用复数
正例:scripts / styles / components / images / utils / layouts / demo-styles / demo-scripts / img / doc
反例:script / style / demo_scripts / demoStyles / imgs / docs
【特殊】VUE 的项目中的组件目录,使用 kebab-case 命名
正例:head-search / page-loading / authorized / notice-icon
反例:HeadSearch / PageLoading
1.5.3 JS、CSS、SCSS、HTML、PNG 文件命名
全部采用小写方式, 以中划线分隔
正例:render-dom.js / signup.css / index.html / company-logo.png
反例:renderDom.js / UserManagement.html
1.6 编码规范
1.6.1 vue风格推荐
Prop
定义详细
// bad
props: ['status']
// good
props: {
status: String
}
// better
props: {
status: {
type: String,
required: true,
validator: function (value) {
return ['syncing','synced','version-conflict','error'].indexOf(value) !== -1
}
}
}
使用 v-for
必须加上 key
值
<!-- bad -->
<ul>
<li v-for="todo in todos">{{ todo.text }}</li>
</ul>
<!-- good -->
<ul>
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
组件的 data
必须是一个函数
// bad
Vue.component('some-comp', {
data: {
foo: 'bar'
}
})
// good
Vue.component('some-comp', {
data: function() {
return {
foo: 'bar'
}
}
})
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
// bad
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
// good
// 在模板中
{{ normalizedFullName }}
// 复杂表达式已经移入一个计算属性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
指令缩写
<!-- bad -->
<input v-bind:value="newTodoText" :placeholder="newTodoInstructions" v-on:input="onInput" />
<!-- good -->
<input :value="newTodoText" :placeholder="newTodoInstructions" @input="onInput" />
1.6.2 关于组件内样式
为组件样式设置作用域
/* bad */
<style>
.btn-close {
background-color: red;
}
</style>
/* good */
<style scoped>
.button-close {
background-color: red;
}
</style>
若要改变第三方组件库的样式,需要加上顶级作用域。
/* bad */
.ivu-input {
width: 254px !important;
}
/* good */
.customerForm .ivu-input {
width: 254px !important;
}
/* .customerForm为当前组件的顶级dom */
1.6.3 关于组件结构
组件结构遵循从上往下 template,script,style 的结构。
<template>
<div></div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped></style>
script 部分各方法成员遵循以下顺序放置。
- name
- components
- props
- data
- methods
- computed
- watch
- created
- mounted
- update
1.6.4 关于注释规范
以下情况需要加注释,以方便代码维护和他人理解
- 公共组件使用说明
- 各组件中重要函数或者类说明
- 复杂的业务逻辑处理说明
- 特殊情况的代码处理说明,对于代码中特殊用途的变量、存在临界值、函数中使用的 hack、使用了某种算法或思路等需要进行注释描述。
- 多重 if 判断语句
1.6.5 缩进
缩进使用 2 个空格(一个 tab)
嵌套的节点应该缩进。
1.6.6 css规范
1.6.6.1 css尽量使用缩写属性
不推荐:
border-top-style: none;
font-family: palatino, georgia, serif;
font-size: 100%;
line-height: 1.6;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;
推荐:
border-top: 0;
font: 100%/1.6 palatino, georgia, serif;
padding: 0 1em 2em;
1.6.6.2 选择器
- css 选择器中避免使用标签名(从结构、表现、行为分离的原则来看,应该尽量避免 css 中出现 HTML 标签,并且在 css 选择器中出现标签名会存在潜在的问题。)
- 直接子选择器的使用(注:直接子选择器和后代选择器的区别)。有时,这可能会导致疼痛的设计问题并且有时候可能会很耗性能。然而,在任何情况下,这是一个非常不好的做法。如果你不写很通用的,需要匹配到 DOM 末端的选择器, 你应该总是考虑直接子选择器。
不推荐:
.content .title {
font-size: 2rem;
}
推荐:
.content > .title {
font-size: 2rem;
}
1.6.6.3 省略0后面的单位
不推荐:
div{
padding-bottom: 0px;
margin: 0em;
}
推荐:
div{
padding-bottom: 0;
margin: 0;
}
1.6.7 javascript 规范
1.6.7.1 命名
- 采用小写驼峰命名 lowerCamelCase,代码中的命名均不能以下划线,也不能以下划线或美元符号结束
反例:_name / name_ / name$
- 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
正例:localValue / getHttpMessage() / inputUserId
其中 method 方法命名必须是 动词 或者 动词+名词 形式
正例:saveShopCarData /openShopCarInfoDialog
反例:save / open / show / go
特此说明,增删查改,详情统一使用如下 5 个单词,不得使用其他(目的是为了统一各个端)
add / update / delete / detail / get
附: 函数方法常用的动词:
get 获取/set 设置,
add 增加/remove 删除
create 创建/destory 移除
start 启动/stop 停止
open 打开/close 关闭,
read 读取/write 写入
load 载入/save 保存,
create 创建/destroy 销毁
begin 开始/end 结束,
backup 备份/restore 恢复
import 导入/export 导出,
split 分割/merge 合并
inject 注入/extract 提取,
attach 附着/detach 脱离
bind 绑定/separate 分离,
view 查看/browse 浏览
edit 编辑/modify 修改,
select 选取/mark 标记
copy 复制/paste 粘贴,
undo 撤销/redo 重做
insert 插入/delete 移除,
add 加入/append 添加
clean 清理/clear 清除,
index 索引/sort 排序
find 查找/search 搜索,
increase 增加/decrease 减少
play 播放/pause 暂停,
launch 启动/run 运行
compile 编译/execute 执行,
debug 调试/trace 跟踪
observe 观察/listen 监听,
build 构建/publish 发布
input 输入/output 输出,
encode 编码/decode 解码
encrypt 加密/decrypt 解密,
compress 压缩/decompress 解压缩
pack 打包/unpack 解包,
parse 解析/emit 生成
connect 连接/disconnect 断开,
send 发送/receive 接收
download 下载/upload 上传,
refresh 刷新/synchronize 同步
update 更新/revert 复原,
lock 锁定/unlock 解锁
check out 签出/check in 签入,
submit 提交/commit 交付
push 推/pull 拉,
expand 展开/collapse 折叠
begin 起始/end 结束,
start 开始/finish 完成
enter 进入/exit 退出,
abort 放弃/quit 离开
obsolete 废弃/depreciate 废旧,
collect 收集/aggregate 聚集
1.6.7.2 代码格式
- 使用2个空格进行缩进
- 不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。
1.6.7.3 字符串
统一使用单引号(‘),不使用双引号(“)
正例:
let str = 'foo';
let testDiv = '<div id="test"></div>';
反例:
let str = 'foo';
let testDiv = "<div id='test'></div>";
1.6.7.4 使用ES6,7
必须优先使用 ES6,7 中新增的语法糖和函数。这将简化你的程序,并让你的代码更加灵活和可复用。
必须强制使用 ES6, ES7 的新语法,比如箭头函数、await/async , 解构, let , for…of 等等
1.6.7.5 undefined判断
不要直接使用undefined进行变量判断;使用typeof
和字符串undefined
对变量进行判断
正例:
if (typeof person === 'undefined') {
...
}
反例:
if (person === undefined) {
...
}
1.6.7.6条件判断和循环最多三层
条件判断能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是谨记不要写太长的三目运算符。如果超过 3 层请抽成函数,并写清楚注释。
1.6.7.7 this的转换命名
对上下文this
的引用只能使用_this
来命名
1.6.7.8 console.log
生产环境去掉
1.6.7.9 建议不再使用双引号,静态字符串使用单引号,动态字符串使用反引号衔接。
// bad
const foo = 'jack'
const bar = foo + ',前端工程师'
// good
const foo = 'jack'
const bar = `${foo},前端工程师`
1.6.7.10使用数组展开操作符 … 复制数组。
// bad
const len = items.length
const itemsCopy = []
let i
for (i = 0; i < len; i += 1) {
itemsCopy[i] = items[i]
}
// good
const itemsCopy = [...items]
1.6.7.11使用数组对象解构赋值
const arr = [1, 2, 3, 4]
// bad
const first = arr[0]
const second = arr[1]
// good
const [first, second] = arr
1.6.7.12使用对象属性速记语法
const name = 'Luke'
const age = 20
// bad
const obj = {
name: name,
age: age
}
// good
const obj = {
name,
age
}
1.7组件规范
1.7.1组件名为多个单词。
组件名应该始终是多个单词组成(大于等于 2),且命名规范为KebabCase
格式。
这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
正例:
export default {
name: 'TodoItem'
// ...
};
反例:
export default {
name: 'Todo',
// ...
}
export default {
name: 'todo-item',
// ...
}
1.7.2组件文件名为pascal-case格式
正例:
components/
|- my-component.vue
反例:
components/
|- myComponent.vue
|- MyComponent.vue
1.7.3基础组件文件名为 base 开头,使用完整单词而不是缩写。
正例:
components/
|- base-button.vue
|- base-table.vue
|- base-icon.vue
反例:
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
1.7.4和父组件紧密耦合的子组件应该以父组件名作为前缀命名
正例:
components/
|- todo-list.vue
|- todo-list-item.vue
|- todo-list-item-button.vue
|- user-profile-options.vue (完整单词)
反例:
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
|- UProfOpts.vue (使用了缩写)
1.7.5在 Template 模版中使用组件,应使用 PascalCase 模式,并且使用自闭合组件。
正例:
<!-- 在单文件组件、字符串模板和 JSX 中 -->
<MyComponent />
<Row><table :column="data"/></Row>
反例:
<my-component /> <row><table :column="data"/></row>
1.7.6Prop 定义应该尽量详细
- 必须使用 camelCase 驼峰命名
- 必须指定类型
- 必须加上注释,表明其含义
- 如果有业务需要,必须加上 validator 验证
正例:
props: {
// 组件状态,用于控制组件的颜色
status: {
type: String,
required: true,
validator: function (value) {
return [
'succ',
'info',
'error'
].indexOf(value) !== -1
}
},
// 用户级别,用于显示皇冠个数
userLevel:{
type: String,
required: true
}
}
1.7.7如果特性元素较多,应该主动换行。
正例:
<MyComponent foo="a" bar="b" baz="c"
foo="a" bar="b" baz="c"
foo="a" bar="b" baz="c"
/>
反例:
<MyComponent foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c"/>
1.7.8 模板中使用简单的表达式
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
正例:
<template>
<p>{{ normalizedFullName }}</p>
</template>
// 复杂表达式已经移入一个计算属性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
反例:
<template>
<p>
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
</p>
</template>
1.7.9 指令都使用缩写形式
指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:)
正例:
<input
@input="onInput"
@focus="onFocus"
>
反例:
<input
v-on:input="onInput"
@focus="onFocus"
>
1.7.10标签顺序保持一致
单文件组件应该总是让标签顺序保持为:
正例:
<template>...</template>
<script>...</script>
<style>...</style>
反例:
<template>...</template>
<style>...</style>
<script>...</script>
1.7.11 必须为 v-for 设置键值 key
1.7.12 v-show 与 v-if 选择
如果运行时,需要非常频繁地切换,使用 v-show ;如果在运行时,条件很少改变,使用 v-if。
1.7.13 script 标签内部结构顺序
components > props > data > computed > watch > filter > 钩子函数(钩子函数按其执行顺序) > methods
1.7.14 Vue Router 规范
1.7.14.1页面跳转数据传递使用路由参数
页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,而不是将需要传递的数据保存 vuex,然后在 B 页面取出 vuex 的数据,因为如果在 B 页面刷新会导致 vuex 数据丢失,导致 B 页面无法正常显示数据。
正例:
let id = ' 123';
this.$router.push({ name: 'userCenter', query: { id: id } });
1.7.14.2 使用路由懒加载(延迟加载)机制
{
path: '/uploadAttachment',
name: 'uploadAttachment',
meta: {
title: '上传附件'
},
component: () => import('@/view/components/uploadAttachment/index.vue')
}
2、webpack 打包优化
为什么要优化打包?
- 项目越做越大,依赖包越来越多,打包文件太大
- 单页面应用首页白屏时间长,用户体验差
我们的目的 - 减小打包后的文件大小
- 首页按需引入文件
- 优化 webpack 打包时间
2.1 按需加载
2.1.1 路由组件按需加载
const router = [
{
path: '/index',
component: resolve => require.ensure([], () => resolve(require('@/components/index')))
},
{
path: '/about',
component: resolve => require.ensure([], () => resolve(require('@/components/about')))
}
]
2.1.2 第三方组件和插件。按需加载需引入第三方组件
// 引入全部组件
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
// 按需引入组件
import { Button } from 'element-ui'
Vue.component(Button.name, Button)
2.1.3 对于一些插件,如果只是在个别组件中用的到,也可以不要在 main.js 里面引入,而是在组件中按需引入
// 在main.js引入
import Vue from vue
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
// 按组件按需引入
import { Vuelidate } from 'vuelidate'
总结
暂且就这些,持续完善~~~