前端开发规范

写在前面

  1. 开发规范是为了作用于团队,保证团队的高效协同工作
  2. 规范的最好维护原则即团队每个成员的严格执行,以及客观的错误总结、完善
  3. 规范不是为了抹灭开发过程中的自由度等,只是避免过度个性化,降低沟通成本
  4. 代码的质量并不由代码规范所保证,质量在于切实提高稳定性,减少踩坑可能性,避免踩同一个坑,小心过早优化等
  5. 代码规范需要配套的检测工具,不要信任人的自觉性
  6. 必要的代码设计与文档沉淀

    代码规范参考Code Guide,并在此基础上有所改动,部分示例可以参考

统一规范

  1. 缩进:采用4空格缩进,使用tab
  2. 编码:UTF-8
  3. 文件顶部、类、接口声明作者邮箱和时间

    1
    2
    3
    4
    5
    /**
    * Author: xxxx@mail.com
    * Date: 2018-03-04
    * Desc: 可省略,选择性填写项
    */
    1
    2
    3
    <!--Author: xxx@mail.com
    Date: 2019-03-04
    Desc: 可省略,选择性填写项-->
  4. 换行符统一使用’LF’(Unix格式)

  5. 行尾不要有空白字符
  6. tab和space不能混用
  7. 代码中不能提交debug, console.error
  8. 注释需要和代码保持同步,禁止修改代码后对注释一直不改动
  9. 单行代码不超过80字符

命名规范

含义与功能匹配的全英文、国际通用的拼音(例如:hangzhou)、常见英文缩写

  1. 【强制】 项目命名: 小写,尽量保持一个单词,多个单词以下划线’_’分隔,例如 my_project
  2. 目录命名: 小写,英文复数形式,例如 images, utils, data_models
  3. js文件、less文件、HTML文件、资源文件等,与项目命名规则相同
  4. Vue文件名:UpperCamelCase风格,例如 MultiSelect.vue,使用时采用<multi-select></multi-select>方式
  5. class命名:小写单词加中划线’-‘分隔或者lowerCamelCase风格,例如 page-edit-link, pageEditLink
  6. id命名、less中的变量、函数等:lowerCamelCase风格
  7. 编程变量命名:
    • 普通变量(成员变量、局部变量)、方法名、参数等使用lowerCamelCase风格, 私有属性、方法以下划线开头,例如 _getTypes
    • 常量全大写加下划线’_’分隔,例如 MAX_LIMIT
    • 类名使用UpperCamelCase风格,抽象类以Abstract或者Base开头,测试类以Test结束,异常类使用Exception结尾,类名若涉及设计模式,将设计模式体现在命名中,例如 QueryProxy
    • 不使用魔法数字或魔法字符串
    • ‘ID’在变量名中全大写
    • ‘URL’在变量名中全大写
    • ‘Android’在变量名中大写第一个字母
    • ‘iOS’在变量名中小写第一个,大写后两个字母
    • jquery对象必须以’$’开头命名

HTML

  1. 启用标准模式,<!DOCTYPE html>
  2. 引号:属性值使用双引号, <img src="images/company_logo.png" alt="Company">
  3. 注释:使用<!-- html 注释 -->
  4. 尽量避免使用内联样式
  5. 区分开行内元素及块级元素, 不建议使用行内元素包裹块级元素的做法,然后使用display进行更改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!-- not good -->
    <style>
    .article {
    display: block;
    }
    </style>
    <span class="article">
    <p>这里是内容</p>
    </span>

    <!-- good -->
    <article>
    <p>这里是内容</p>
    </article>
  6. 单标签不需要封口,类似于img,br,link…之类的标签不需要进行封口

  7. 属性顺序

    1
    2
    3
    4
    5
    class
    id
    src等原生属性 for, type, href, value, max-length, max, min, pattern
    placeholder, title, alt
    aria-*, role, required, readonly, disabled

    如果可以做一个温暖的开发者,多给点时间给aria-*和role

  8. 多使用H5语义化标签
    1
    2
    3
    4
    5
    6
    <section>
    <nav>
    <article>
    <aside>
    <header>
    <main>

更多新标签可参考H5标签列表

CSS

  1. 避免!important的使用
  2. 避免通配符*的使用
  3. 小数点前的0省略, font-size: .4rem;
  4. 属性值0后的单位省略,margin: 0 auto;
  5. 字体系列名称中必须含有通用族,且禁止重复字体系列
  6. 颜色值使用十六进制小写,且使用短模式
  7. 禁止重复规则和空规则
  8. 空格

    • 需要空格的地方

      • 冒号后,逗号后 : ,
      • 选择器> , + , ~前后
      • 属性前
      • 大括号前后{
      • 注释之间,/* css 注释 */
    • 不需要空格的地方

      • 小括号前后
  9. 分号:每个属性声明末尾都要使用分号
  10. 引号:单引号, background-image: url('../logo.png');
  11. 注释,只在特殊情况处添加注释,其他时候避免注释,注释之前建议空行
  12. 属性简写
    属性简写需要你非常清楚属性值的正确顺序,而且在大多数情况下并不需要设置属性简写中包含的所有值,所以建议尽量分开声明会更加清晰;
    其中 margin 和 padding 相反,需要使用简写,减少浏览器的重排
    常见简写属性:font, background, transform, transition, animation, margin, padding
  13. 属性书写顺序

    常见属性书写顺序,分组见添加空行,完整版请戳css属性推荐书写顺序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    .declaration-order {
    display: block;
    float: right;

    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 100;

    border: 1px solid #e5e5e5;
    border-radius: 3px;
    width: 100px;
    height: 100px;

    font: normal 13px "Helvetica Neue", sans-serif;
    line-height: 1.5;
    text-align: center;

    color: #333;
    background-color: #f5f5f5;

    opacity: 1;
    }

JavaScript

  1. 空格

    • 需要空格的地方

      • 二元和三元运算符前后
      • 代码块{
      • 模块引入import值之间,例如import { users } from './login';
      • 属性名的冒号后
      • 大括号前{
      • 部分关键词后:if, else, for, while, do, switch, case, try, catch, finally, with, return, typeof
      • 函数的入参之间
      • 函数声明或函数表达式的{
      • for循环条件中的分号和逗号后
      • 单行注释//后,行内单行注释前,多行注释的星号后
    • 不需要空格的地方

      • 一元运算符前后,++i
      • 对象属性名后
      • 函数声明或函数表达式的(
      • 运算符的(后和)
      • 对象的{后和}
      • 数组的[后和]
  2. 分号
    以下情况必须使用分号

    1
    2
    3
    4
    5
    6
    7
    8
    变量声明
    表达式
    import
    return
    throw
    break
    continue
    do-while
  3. 引号,使用单引号,使用模板字符串(template string)代替双引号的使用场景

  4. switch的falling through和default以及if等控制语句必须添加注释
  5. 如果出现对上下文this的引用,统一使用’self’代替,多使用箭头函数避免引用的场景
  6. 用’===’, ‘!==’代替’==’, ‘!=’
  7. 避免var的使用,变量声明紧跟在变量的使用处
  8. 使用构造函数后需要赋值给某个变量
  9. 不使用未声明变量
  10. 变量声明后必须使用
  11. 缩短变量的生命周期,减少全局变量的使用
  12. 做好异常的分类处理,避免一把抓的catch;对外部数据保持怀疑,必须做好数据验证以及容错处理
  13. 函数保持功能的单一性,一个函数只做负责一个功能
  14. 函数入参不能超过3个,超出考虑声明一个类或者使用对象
  15. 构造函数中不能加入业务逻辑
  16. 注释
    工具、类、接口、全局变量、枚举变量等必须有注释,逻辑转折处必须有注释,特殊逻辑或者难以理解代码必须有注释
    注释只在必要处出现,且保证注释的准确和精简,过多或错误的注释只会造成开发阻碍,一旦代码逻辑或者类型更改,记得及时更新注释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    if (condition) {
    // if you made it here, then all security checks passed
    callback();
    }

    const user = {
    name: 'youzi', // one space after code
    age: 18,
    };

    /**
    * @let {object}
    * @property {string} a - 属性a
    * @property {string} b - 属性b
    */
    let foo = {
    a: 'a',
    b: 'b'
    }

    /**
    * @func foo
    * @desc 一个带参数的函数
    * @param {string} a - 参数a
    * @param {number} b=1 - 参数b默认值为1
    * @param {string} c=1 - 参数c有两种支持的取值</br>1—表示x</br>2—表示xx
    * @param {object} d - 参数d为一个对象
    * @param {string} d.e - 参数d的e属性
    * @param {string} d.f - 参数d的f属性
    * @param {object[]} g - 参数g为一个对象数组
    * @param {string} g.h - 参数g数组中一项的h属性
    * @param {string} g.i - 参数g数组中一项的i属性
    * @param {string} [j] - 参数j是一个可选参数
    */
    function foo(a, b, c, d, g, j) {}

    /**
    * @func
    * @desc 一个带若干参数的函数
    * @param {...string} a - 参数a
    */
    function bar(a) {}

    其他更详细注释标准参考JSDoc Guide

Vue

  1. 自定义组件命名需要两个单词以上
  2. props原子化,尽量只使用原始类型,避免对象类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!-- good -->
    <range-slider
    :values="[10, 20]"
    :min="0"
    :max="100"
    :step="5"
    @on-slide="updateInputs"
    @on-end="updateResults">
    </range-slider>

    <!-- not good -->
    <range-slider :config="complexConfigObject"></range-slider>
  3. 验证组件的props,且props必须提供默认值、声明类型和必要的注释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <template>
    <input type="range" v-model="value" :max="max" :min="min">
    </template>
    <script type="text/javascript">
    export default {
    props: {
    max: {
    type: Number, // 这里添加了数字类型的校验
    default() { return 10; },
    },
    min: {
    type: Number,
    default() { return 0; },
    },
    value: {
    type: Number,
    default() { return 4; },
    },
    },
    };
    </script>
  4. 模块化组件需要提供API文档和demo

    更多建议参考vue组件规范

更多建议杂项

  1. 不在视图模板中添加复杂逻辑处理
  2. 条件判断如果有复杂逻辑,提前赋值给有意义的布尔变量,提高可读性
  3. 对于类的属性和方法确认好访问权限,全面开放状态不利于后期的重构
  4. 用户个人页面或功能都进行权限校验
  5. 用户的敏感数据不直接展示
  6. 用户请求的任何参数都要做有效性校验
  7. 禁止对HTML页面输出未经转义或安全过滤的用户数据
  8. 对用户操作做好防重复措施或平衡高频操作,例如发送验证码,即时通信等
  9. 防止NPE(空指针异常)场景,常见场景:网络请求返回空对象直接使用;链式操作等
  10. 异常捕获后必须处理,保证程序的正常运行
  11. 异常操作不要置于流程、条件控制或循环中
  12. 谨慎记录日志,日志要确保必需性与全面性
  13. 谨慎删除代码,但也需要及时清理垃圾代码
  14. 坚持注释的准确和同步的特点;避免注释的滥用,合理的命名和代码结构是会说话的,当你需要大篇幅的注释时可以考虑如何优化你的代码了
  15. 合理利用// TODO并及时完成,TODO信息中必须留下作者、时间以及待办事项、原因、初步方案等
  16. 系统设计时尽量依赖抽象类和接口,对扩展开放,对修改闭合,底层设计需要评审通过后沉淀为文档