前端开发规范

开发规范

本文档主要包括以下是三个部分

vue 框架构建及开发规范

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>)进行使用。
  • 当项目中需要自定义比较多的基础组件的时候,比如一些 buttoninputicon,建议以一个统一的前缀如 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'

总结

暂且就这些,持续完善~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值