# 前端开发规范

开发规范的制定,可以降低新成员的融入成本,提高团队协作效率和开发效率,降低沟通成本。实现高度统一的代码风格,也有利于提高代码的可维护性。后面还要在实践中提高各种开发逻辑,业务处理方式的规范,制定标准的、模块化的知识输出点,快速的拿来即用,加强团队的知识沉淀。

本组前端团队主要是以 Vue2 技术栈为基础,其他还涉及到小程序、移动端页面、uniApp 等技术,以及以 Vue 为基础的 UI 框架,像 Element UI、Ant Design UI 这些,所以小程序和这些常见的 UI 框架基础的知识点都要有所掌握,并在开发中进行熟练的使用。有时候在拓展新的业务还要对一些新的技术进行尝试,所以在保证基础的知识熟练后,还要积极涉猎新技术拓宽自己的技术栈。

下面是本团队成员要遵守的一些规范,这些规范可能会和你平时的习惯有所不同,请仔细阅读该规范,严格遵守,快速熟悉融入到团队之间的协作中。

# 一、HTML 规范

基础的 HTML 语法规范几乎是所有前端都要熟知的,下面列出几点,其他不做赘述。

  • 标签必须合法且闭合、嵌套正确,标签名需小写
  • 标签语法无错误,优先使用语义化标签
  • 除非有特定的功能、组件要求等,禁止随意使用 id 来定义元素样式
  • a 标签和 img 标签最好加上 title 和 alt 进行说明

# 二、CSS 规范

请仔细阅读该规范

CSS 书写规范

# 三、图片规范

  • 图片名称使用 kebab-case 规范命名,禁止使用特殊字符、中文
  • 图片大小最好 不超过 300kb
  • 命名需要能体现图片的大概用途 示例:
 bg.jpg          //背景图片
 banner.jpg      //banner 图
 sprites.png     //精灵图
 btn-icon.jpg    // 按钮图标
 avatar-badge.png // 头像徽标

# 四、Javascript 规范

# 1、命名规范

变量命名

全局变量、局部变量、参数名、统一采用 kebabCase 小驼峰格式命名变量。

不要使用下划线和特殊字符。

命名变量时前面可以加一些前缀来进行区别,比如 is/has/can 等。

常见的表示进行中、状态类的变量:

{
  "isShow": "是否显示",
  "isRunning": "正在运行中",
  "hasUser": "是否包含用户",
  "canRead": "是否可读"
}

其他常见属性状态类:

{
  disabled: '是否禁用',
  editable: '是否可编辑',
  clearable: '是否可清除',
  readonly: '只读',
  expandable: '是否可展开',
  checked: '是否选中',
  enumberable: '是否可枚举',
  iterable: '是否可迭代',
  clickable: '是否可点击',
  draggable: '是否可拖拽'
}

函数命名

函数命名也使用 kebabCase 小驼峰写法。

必须采用 动词+名词 来进行命名,比如:getUserList、setUserName。

常见的增删改查统一使用 add/ delete / update / get 这几个单词。

常量命名

常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。

const MAX_STOCK_COUNT = 10;
const BASE_URL = "http://www.baidu.com";

# 2、书写规范

1、优先使用 ES6 中新增的语法糖和函数。

2、在 js 中统一使用单引号,不要使用双引号。

3、在进行比较判断时尽量使用全等 === 来进行判断。

4、当有使用对象的对象参数多余 2 个时使用解构赋值来取值。

const { name, age, sex } = userInfo;

5、条件判断 能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是不要写太长的三目运算符。如果超过 3 层请使用 switch/case 或者抽成函数。

如果单条 if 判断可以直接省略大括号。

if (str === "test") isShow = true;

6、改变 this 指向转换命名只能使用 that

const that = this;

7、不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。

# 五、Vue 项目规范

vue 代码使用 Eslint 和 prettierrc 进行代码格式检查和格式化,请严格遵守该规范。

# 1、项目构建

构建 vue 项目使用 vue-cli3 来初始化项目,如果使用 Element 或者 Ant UI 插件的后台模板的话也基本上是 vue-cli3 搭建的。

# 2、项目目录

在自己搭建 vue 项目时,按照下面基础目录格式进行搭建,如果有额外的目录在进行讨论使用什么目录来进行存放。

  • 所有的静态资源,比如图片,字体包、公共样式文件都放在 assets 文件夹下面,避免在 views 的每个目录中放图片。
  • api 目录存放每个业务页面对应的 api 请求接口。
  • utils 用来放一些工具类、轮子等 js 文件,比如常用的公共函数,时间过滤、正则验证、axios 封装、地址数据等。
  • components 只存放项目公共组件,业务页面自己的组件放在其对应的 components 文件夹下。
  • layouts 下存放页面基础的布局。
  • 如果要单独拆分业务页面的 js、css,要创建和 views 里一 一 对应的文件目录,文件命名也一样,避免都放在一起混淆。
├── public
│   └── logo.png             # LOGO
|   └── index.html           # Vue 入口模板
├── src
│   ├── api                  # Api ajax 等
│   ├── assets               # 本地静态资源
│   │   ├── images           # 项目图片
│   │   ├── css              # reset、common样式
│   │   ├── font             # 字体库、iconfont库
│   │   └── less/sass        # 公共less/sass文件
│   ├── components           # 业务公共组件
│   ├── layouts              # 基础布局
│   ├── router               # Vue-Router
│   ├── store                # Vuex
│   ├── utils                # 工具库
│   ├── views                # 业务页面入口和常用模板
│   ├── App.vue              # Vue 模板入口
│   └── main.js              # Vue 入口 JS
├── tests                    # 测试工具
├── README.md
└── package.json

# 3、文件、组件规范

在目录文件中文件夹以 kebab-case 格式命名,除了 index.vue 文件外其他 vue 组件均以 KebabCase 格式命名。

每个业务页面使用一个单独的文件(根据项目规模,如果后续规模大,模块多,每个业务页面统一放在一个大模块下)。

每个业务页面文件里是当前页面的 index.vue 文件和抽出来的组件,提取的组件放在当前文件下的 components 目录里。

组件命名最好不低于两个单词,防止和 HTML 标签混淆。

多于两个地方使用的组件,提取出来封装成公共组件放在公共的 components 文件里。

公共组件全部使用 KebabCase 大驼峰来命名,单词开头字母全部大写。

注意:特殊要求

引入组件时也全部使用大写,不要使用默认的 kebab-case 方法自动生成。

参考:Vue 风格指南 (opens new window)

# 4、组件选项顺序

export default {
  name: '', // 组件名要大写
  components: {},
  directives: {},
  mixins: [],
  props: {}
  data () { return {} },
  computed: {},
  watch: {},
  created () {},
  beforeDestroy () {},
  methods: {},
}

# 5、属性排列顺序

在 HTML 标签上属性要按照一定顺序排列,class 类名要放最前面,双向绑定 v-model 和 v-if 也放前面,事件@放在最后面。

class
ref
v-model
v-if、v-show
is
v-for
key
v-bind
v-html、v-text
v-on

# 6、props 传值

声明 props 传值要尽量详细

- 必须使用 camelCase 小驼峰命名,模板中始终使用 kebab-case
- 必须加上注释,表明其含义
- 必须指定类型
- 必须加上 required 或者 default,两者二选其一
<baseUser user-id="12"></baseUser>

<script>
  props: {
    // 用户id 进行获取用户列表
    userId: {
      type: Number,
      required: true,
    }
  }
</script>

# 7、自定义事件约束

使用自定义事件在子组件向父组件传递或者中央事件主线进行传递时,自定义事件命名统一使用全部大写+下划线进行连接,命名和普通函数一样,但要以 _EVENT 来结尾,以区分普通函数。事件传值如果是多个值统一放在一个对象进行传递。

// 子组件 baseUser
const params = {
  name: 'zhangsan',
  age: 18
}
this.$emit('GET_CUSTOM_USER_EVENT', params)

// 父组件
<baseUser @GET_CUSTOM_USER_EVENT="getCustomUser"></baseUser>

getCustomUser (user) {
  console.log(user)
}

使用中央事件进行事件传递时,接收到事件,在组件销毁时需要进行清除。

// 组件baseA
this.$bus.$emit('LISTEN_NAV_ENVET')
// 组件baseB
this.$bus.$on('LISTEN_NAV_ENVET', () => {})
// 组件销毁时进行清除
destroyed() {
  this.$bus.$off('LISTEN_NAV_ENVET')
},

# 8、样式

vue 一般使用预编译 less 或 sass,公共样式单独提取出来然后直接在 css 中进行混入引用。要给每个组件设置作用域 scoped,更改 UI 组件默认样式使用 deep。

# 9、声明周期

获取数据都在 created 周期函数中获取。

# 10、属性换行

属性换行,一般不建议换行,除非属性特别多行特别长才考虑换行。换行要使用缩进进行对齐。

# 11、vuex 使用

store 要按照不同业务进行拆分不同的模块。

主要使用 mutation,在 mutation 只进行对 state 数据的更新,不做其他业务的处理。

action 涉及到异步数据处理,除处理登录权限使用外,其他模块尽量不使用。

在组件中使用都要通过辅助函数 mapState/mapMutations/mapGetters/mapActions 来获取和设置。

其他暂不做过多要求。

├── index.js
├── modules
│   ├── user.js                 # 用户模块
│   └── product.js              # 商品模块
// index.js
import Vue from "vue";
import Vuex from "vuex";

import user from "./modules/app";
import product from "./modules/product";

export default new Vuex.Store({
  modules: {
    user,
    product,
  },
});
/**
 * @name 用户管理
 * @author changz
 */
const user = {
  state: {
    userId: "", // 用户id
  },
  mutations: {
    // 设置用户id
    getUserId(state, userId) {
      state.userId = userId;
    },
  },
  actions: {},
  getters: {},
};

export default user;

# 12、路由使用

路由配置

  • path 使用kebab-case命名规范进行命名,不要出现大写命名
  • name 和 component 使用 KebabCase 命名规范命名,和组件内 name 相对应
  • 添加路由使用懒加载机制
// 先引入组件
const Home = () => import(/* webpackChunkName: "home" */ "@/views/home");
const Shop = () => import(/* webpackChunkName: "shop" */ "@/views/shop");
const ShopDetail = () =>
  import(/* webpackChunkName: "shop-detail" */ "@/views/shop-detail");

// 路由配置
routes: [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: "/shop",
    name: "Shop",
    component: Shop,
  },
  {
    path: "/shop/:id",
    name: "ShopDetail",
    component: ShopDetail,
  },
];

页面跳转统一使用 name 进行跳转,传参使用 params 和 query 进行传参

this.$router.push({
  name: "Shop",
  query: {
    shopId: shopId,
  },
});
// 动态路由
this.$router.push({
  name: "ShopDetail",
  params: id,
});

#

# 13、注释

必须要加注释的地方

- 所有的文件必须加注释说明用意
- store 中的 state, mutation, action 等必须加注释
- vue 文件中的 template 必须加注释,若文件较大添加 start end 注释
- vue 文件的 methods,每个 method 必须添加注释
- vue 文件的 data, 非常见单词要加注释
- 公共组件使用说明

文件注释:

每个文件都要注释是干什么的,使用多行注释,js 文件在最上面注释,.vue 文件放在 script 里进行注释。

/**
 * @desc 员工详情
 * @author changz
 * */

变量和函数注释:

每个变量都要注释,每个函数也要加注释,函数注释可以使用单行注释和多行注释。

export default {
  name: 'User',
  components: {},
  data() {
    return {
      // 筛选信息
      filterInfo: {
        title: '', // 标题
        id: '', // 用户id
      }
      name: '', // 姓名

    }
  },
  methods: {
      // 添加用户
      addUser() {},
      /**
       * @desc 删除用户
       * @param id 用户id
       * @author changz
       * */
      deleteUser(id) {}
  }
}

组件注释:

公共用的组件要封装成公共组件,组件名称单词要大写开头,注释要写详细,每个出入的参数都要注明意思和使用说明,使人一眼就能明白该组件是干什么的,是如何用的。

/**
 * 组件名称
 * @desc 组件描述
 * @author 组件作者
 * @param {Object} [title] - 参数说明
 * @param {String} [columns] - 参数说明
 * @example 调用示例
 * <hbTable :title="title" :columns="columns" :table-data="tableData"></hbTable>
 */

# 六、Vue 编码规范

常见的 js 编码规范:JavaScript Standard Style (opens new window)Airbnb JavaScript Style Guide (opens new window)

在 vue 中实现这些规范,没什么不好,能更简洁和快速的进行开发,并让代码有一个良好的统一格式。所以我们在 vue 中统一使用这些规范。

vue 创建项目会有默认的 Eslint 选项,我们选择 Eslint + standard 进行规范编码格式。格式化文档可以创建.prettierrc 文件来配置,配置出符合 Eslint + standard 的风格。

格式注意:

  • 使用 2 个空格进行缩进
  • 字符串统一使用单引号 'abc'
  • 无分号
  • 关键字后加空格(if else)
  • 函数名后加空格
  • 字符串拼接操作符之间要留空格
  • 各种操作符之间要留有空格
  • 逗号后面加空格(对象,数组,参数,解构)
  • 不允许有多余的行末逗号
  • 键值对当中冒号与值之间要留空白
  • 单行注释首尾留空格
data() {
  name: 'zhangsan', // 姓名
  userList: ['zhangsan', 'lisi', 'wangwu'],
  userInfo: {
    name: '',
    id: 18
  },
  grade: { a: 12, b: 13 }
}
created() {

},
methods: {
  getUser(userId, userName) {
    const { name, id } = this.userInfo
    if (userName === 'lisi' || userId === id) {
      console.log(111)
    } else {
      console.log(222)
    }
  }
}

配置 Eslint: 代码检查中不是所有的都是我们需要的,可以通过配置.eslintrc.js 文件来去除不需要的代码检查。参考链接:Eslint (opens new window)

// .eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: ["plugin:vue/essential", "@vue/standard"],
  parserOptions: {
    parser: "@babel/eslint-parser",
  },
  rules: {
    "vue/multi-word-component-names": ["off"], // 是否强制组件名称多单词
    camelcase: "off", // 是否强制使用驼峰拼写法命名规定
    "space-before-function-paren": "off", // 是否强制方法圆括号左边空格
    "no-multiple-empty-lines": "off", // 不允许多个空行
    "new-cap": "off", // 构造函数名首字母大写
    "eol-last": "off", // 要求或禁止文件末尾存在空行
    "dot-notation": "off", // 允许不使用点表示写法
    "vue/no-mutating-props": ["off"], // 关闭Vue不能修改props警告
    "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
    "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
  },
};

配置代码格式化:

使用 prettier 来格式我们的代码,配置符合 Eslint + standard 风格的代码,如果项目中有.prettierrc 文件,则格式化先以项目中的该文件为准。

参考链接:Prettier (opens new window)

在项目中创建.prettierrc 文件配置参数。

// .prettierrc
{
  "semi": false, // 结尾无分号
  "printWidth": 180, // 超过n个字符换行
  "singleQuote": true, // 使用单引号
  "quoteProps": "preserve",
  "trailingComma": "none", // 无尾随逗号
  "arrowParens": "avoid" // 箭头函数单个参数不加分号
}

# 七、Git 开发规范

仓库管理地址:http://git.vuln.yunsee.cn/ (opens new window) 要先配置 hosts 才能访问。

管理员统一分配账号,获取账号进行登录,查看自己的项目。

熟悉下面 Git 开发规范执行流程并严格执行。

Git 开发规范

# 附:函数方法常用动词

get 获取/set 设置,
add 增加/remove 删除,
create 创建/destory 移除,
format 格式化/query 查询
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 聚集