CRMEB Java外贸版开发规范

前端开发规范

命名规范

项目命名

全部采用小写方式, 以下划线分隔。
例:my_project_name

目录命名

参照项目命名规则;
有复数结构时,要采用复数命名法。
例:scripts,styles,images,data_models
vue的项目中,components下的组件目录名,使用大驼峰命令
例:LeftBar

JS文件命名

参照项目命名规则。
例:account_model.js

CSS, SCSS文件命名

参照项目命名规则。
例:retina_sprites.css

HTML文件命名

参照项目命名规则。
例:error_log.html

HTML 规范

语法:
  1. 缩进使用 tab(2 个空格);
  2. 嵌套的节点应该缩进;
  3. 在属性上,使用双引号,不要使用单引号;
  4. 属性名全小写,用中划线(-)做分隔符;
  5. 要在自动闭合标签结尾处使用斜线;

     
      
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <title>Page title</title>
    5. </head>
    6. <body>
    7. <img src="images/company_logo.png" alt="Company" />
    8. <!-- 属性名全小写,用中划线(-)做分隔符 -->
    9. <h1 class="hello-world">Hello, world!</h1>
    10. </body>
    11. </html>
    标准模式

    在开头规定 doctype,来启动标准模式,doctype 要大写。

     
      
    1. <!DOCTYPE html>
    2. <html>
    3. ...
    4. </html>
    规定字符编码

    通过声明一个明确的字符编码,让浏览器轻松、快速的确定适合网页内容的渲染方式,通常指定为’UTF-8’。

     
      
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8" />
    5. </head>
    6. ...
    7. </html>
    IE 兼容模式

    用 meta 标签指定页面应该使用什么版本的 IE 来渲染。

     
      
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    5. </head>
    6. ...
    7. </html>
    减少标签数量

    在编写 HTML 代码时,需要尽量避免多余的父节点;

 
  1. <!-- bad -->
  2. <span class="avatar">
  3. <img src="..." />
  4. </span>
  5. <!-- good -->
  6. <img class="avatar" src="..." />
语义化标签

html 的标签能使用语义化的,尽量使用语义化标签,避免一个页面都是 div 或者 p 标签

 
  1. <!-- bad -->
  2. <div>
  3. <p></p>
  4. </div>
  5. <!-- good -->
  6. <header></header>
  7. <footer></footer>

CSS 规范

缩进

使用 tab 缩进(2 个空格)

 
  1. .element {
  2. border-radius: 10px;
  3. width: 50px;
  4. height: 50px;
  5. }
分号

每个声明结束都要加分号

 
  1. .element {
  2. border-radius: 10px;
  3. width: 50px;
  4. height: 50px;
  5. }
注释

注释统一使用 / /

 
  1. .element {
  2. /* border-radius: 10px; */
  3. width: 50px;
  4. height: 50px;
  5. }
引号
  1. url 的内容要用引号
  2. 属性选择器中的属性值需要引号
 
  1. .element:after {
  2. content: "";
  3. background-image: url("logo.png");
  4. }
  5. li[data-type="single"] {
  6. ...;
  7. }
命名
  1. 类名使用小写字母,以中划线分隔
  2. id 采用驼峰式命名
  3. scss 中的变量、函数、混合、placeholder 采用驼峰式命名
 
  1. /* class */
  2. .element-content {
  3. ...;
  4. }
  5. /* id */
  6. #myDialog {
  7. ...;
  8. }
  9. /* 变量 */
  10. $colorBlack: #000;
  11. /* 混合 */
  12. @mixin centerBlock {
  13. ...;
  14. }

JavaScript 规范

缩进

使用 tab 缩进(2 个空格)

 
  1. if (x < y) {
  2. x += 10;
  3. } else {
  4. x += 1;
  5. }
变量命名
  1. 标准变量采用驼峰式命名
  2. ‘Android’在变量名中大写第一个字母
  3. ‘iOS’在变量名中小写第一个,大写后两个字母
  4. 常量全大写,用下划线连接
  5. 构造函数,大写第一个字母
  6. jquery 对象必须以’$’开头命名
 
  1. var thisIsMyName;
  2. var AndroidVersion;
  3. var iOSVersion;
  4. var MAX_COUNT = 10;
  5. function Person(name) {
  6. this.name = name;
  7. }
  8. // not good
  9. var body = $("body");
  10. // good
  11. var $body = $("body");
变量声明

一个函数作用域中所有的变量声明尽量提到函数首部。如果可以使用 let 和 const 的,要使用 let 和 const。

 
  1. function doSomethingWithItems(items) {
  2. // use one var
  3. let value = 10,
  4. result = value + 10,
  5. i,
  6. len;
  7. for (i = 0, len = items.length; i < len; i++) {
  8. result += 10;
  9. }
  10. }
单行长度

不要超过 100,但如果编辑器开启 word wrap 可以不考虑单行长度。

分号

统一要加分号。

空格

以下几种情况不用写空格:

  1. 对象的属性名后
  2. 函数调用括号前
  3. 无论是函数声明还是函数表达式,’(‘前不要空格
  4. 数组的’[‘后和’]’前
  5. 运算符’(‘后和’)’前

以下几种情况一定要写空格:

  1. 三元运算符’?:’前后
  2. 逗号后必须要有空格
  3. 代码块’{‘前
  4. 下列关键字前:else, while, catch, finally
  5. 下列关键字后:if, else, for, while, do, switch, case, try,catch, finally, with, return, typeof
  6. 单行注释’//‘后(若单行注释和代码同行,则’//‘前也需要),多行注释’*’后
  7. 对象的属性值前
  8. for 循环,分号后留有一个空格,前置条件如果有多个,逗号后留一个空格
  9. 无论是函数声明还是函数表达式,’{‘前一定要有空格
  10. 函数的参数之间

这些后续会用 eslint 和 prettier 进行格式化
例:

 
  1. // not good
  2. var a = {
  3. b : 1
  4. };
  5. // good
  6. var a = {
  7. b: 1
  8. };
  9. // not good
  10. ++x;
  11. y++;
  12. z = x ? 1:2;
  13. // good
  14. ++x;
  15. y++;
  16. z = x ? 1 : 2;
  17. // not good
  18. var a = [ 1, 2 ];
  19. // good
  20. var a = [1, 2];
  21. // good
  22. var doSomething = function(a, b, c) {
  23. // do something
  24. };
  25. // good
  26. doSomething(item);
  27. // not good
  28. for (let i = 0;i < 6;i++) {
  29. x++;
  30. }
  31. // good
  32. for (let i = 0; i < 6; i++) {
  33. x++;
  34. }
空行

以下几种情况一定要有空行

  1. 变量声明后(当变量声明在代码块的最后一行时,则无需空行)
  2. 注释前(当注释在代码块的第一行时,则无需空行)
  3. 文件最后保留一个空行
 
  1. var x = 1;
  2. // 注释前要有空行
  3. if (x >= 1) {
  4. var y = x + 1;
  5. }
换行

换行的地方,行末必须有’,’或者运算符;
以下几种情况不需要换行:

  1. 下列关键字后:else, catch, finally
  2. 代码块’{‘前

以下几种情况需要换行:

  1. 代码块’{‘后和’}’前
  2. 变量赋值后
 
  1. // not good
  2. var a = {
  3. b: 1
  4. , c: 2
  5. };
  6. x = y
  7. ? 1 : 2;
  8. // good
  9. var a = {
  10. b: 1,
  11. c: 2
  12. };
  13. x = y ? 1 : 2;
  14. // good
  15. if (condition) {
  16. ...
  17. } else {
  18. ...
  19. }
  20. try {
  21. ...
  22. } catch (e) {
  23. ...
  24. } finally {
  25. ...
  26. }
  27. // not good
  28. function test()
  29. {
  30. ...
  31. }
  32. // good
  33. function test() {
  34. ...
  35. }
  36. // not good
  37. var a, foo = 7, b,
  38. c, bar = 8;
  39. // good
  40. var a,
  41. foo = 7,
  42. b, c, bar = 8;
注释
单行注释
  1. 注释单独一行的情况下,注释的//后面要跟一个空格
  2. 注释如果和代码同一行,代码分号结束后,要跟一个空格,注释的//后也要跟一个空格

例:

 
  1. // 调用函数
  2. foo();
  3. var maxCount = 10; // 这是一个变量
多行注释

多行注释使用下面这种形式:

 
  1. /**
  2. * 代码注释1
  3. * 代码注释2
  4. */

多行注释建议在以下几种情况使用:

  1. 难于理解的代码段
  2. 可能存在错误的代码段
  3. 浏览器特殊的 HACK 代码
  4. 业务逻辑强相关的代码
函数注释

复杂的函数,所有类,都必须进行函数注释,函数注释使用业界统一的规范,方便后续使用 jsdoc 生成文档。
例:

 
  1. /**
  2. * 获取任务的名称
  3. * @param id {Number} 传入需要获取名称的人物id
  4. * @return {String} 返回的姓名
  5. * @author shi 2015/07/21 可以不写
  6. * @version 1.1.0 可以不写
  7. * @example 示例代码,可以不写
  8. */
  9. function getTaskName(id) {
  10. let name = "test";
  11. return name;
  12. }
引号

最外层统一使用单引号,除非字符串嵌套的情况。

 
  1. // not good
  2. var x = "test";
  3. // good
  4. var y = 'foo',
  5. z = '<div id="test"></div>';
对象,数组
  1. 对象属性名不需要加引号,如对象属性名是中划线命名的需要加引号(eslint 的 rules)
  2. 对象以缩进的形式书写,不要写在一行(单个属性可以写一行,es6 导入方法时可以使用单行);
  3. 数组、对象最后不要有逗号。
 
  1. // good
  2. var a = {
  3. b: 1,
  4. c: 2
  5. };
括号

下列关键字后必须有大括号(即使代码块的内容只有一行):if, else, for, while, do, switch, try, catch, finally, with。

 
  1. // not good
  2. if (condition) doSomething();
  3. // good
  4. if (condition) {
  5. doSomething();
  6. }
undefined

永远不要直接使用 undefined 进行变量判断;
使用 typeof 和字符串’undefined’对变量进行判断。

 
  1. // not good
  2. if (person === undefined) {
  3. ...
  4. }
  5. // good
  6. if (typeof person === 'undefined') {
  7. ...
  8. }
不允许存在多层嵌套的条件判断和循环(最多三层)

条件判断能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是谨记不要写太长的三目运算符。
例:

 
  1. // bad
  2. if (x === 10) {
  3. return 'valid';
  4. } else {
  5. return 'invalid';
  6. }
  7. // good
  8. return x === 10 ? 'valid' : 'invalid';
  9. // bad
  10. if (!x) {
  11. if (!y) {
  12. x = 1;
  13. } else {
  14. x = y;
  15. }
  16. }
  17. // good
  18. x = x || y || 1;

简单解释一下逻辑运算符,逻辑运算符主要有两种,一个是 || 逻辑或,一个是 && 逻辑与。

  • 逻辑或 ||:当前一个为真时,返回前一个值,前一个为假时返回后一个值。
 
  1. var x = 1;
  2. console.log(x || 2); // 1
  3. var y = 0;
  4. console.log(y || 2); // 2
  • 逻辑与 &&:当前一个为真时,返回后一个值,前一个为假时返回前一个值。
 
  1. var x = 1;
  2. console.log(x && 2); // 2
  3. var y = 0;
  4. console.log(y && 2); // 0
其他 ESlint
  • for-in 里一定要有 hasOwnProperty 的判断;
  • 不要在内置对象的原型上添加方法,如 Array, Date;
  • 变量不要先使用后声明;
  • 不要在一句代码中单单使用构造函数,记得将其赋值给某个变量;
  • 不要在同个作用域下声明同名变量;
  • 不要在一些不需要的地方加括号,例:delete(a.b);
  • 不要使用未声明的变量;
  • debugger 不要出现在提交的代码里;
  • 数组中不要存在空元素;
  • 不要在循环内部声明函数;
  • 不要直接 new 使用构造函数(new Vue() 除外);
  • 不要声明了变量却不使用;

这些都可以参考 eslint-config-alloy,有详细的 JS、TS、React、Vue 的规范,我们后续配置 eslint 时也是引入腾讯的 eslint 规范。

 
  1. // good
  2. for (key in obj) {
  3. if (obj.hasOwnProperty(key)) {
  4. // be sure that obj[key] belongs to the object and was not inherited
  5. console.log(obj[key]);
  6. }
  7. }
  8. // not good
  9. Array.prototype.count = function(value) {
  10. return 4;
  11. };
  12. // not good
  13. function test() {
  14. console.log(x);
  15. var x = 1;
  16. }
  17. // not good
  18. new Person();
  19. // good
  20. var person = new Person();
  21. // not good
  22. delete (obj.attr);
  23. // good
  24. delete obj.attr;
  25. // not good
  26. var a = [1, , , 2, 3];
  27. // not good
  28. var nums = [];
  29. // not good
  30. for (var i = 0; i < 10; i++) {
  31. (function(i) {
  32. nums[i] = function(j) {
  33. return i + j;
  34. };
  35. })(i);
  36. }
其他
  • 换行符统一用’LF’;
  • 对上下文 this 的引用只能使用’_this’, ‘that’, ‘self’其中一个来命名;
  • 行尾不要有空白字符;
  • 不允许有空的代码块(如果实在需要,可以在代码块中写注释)。
 
  1. // not good
  2. function Person() {
  3. // not good
  4. var me = this;
  5. // good
  6. var _this = this;
  7. // good
  8. var that = this;
  9. // good
  10. var self = this;
  11. }
  12. if (condition) {
  13. }

Vue开发规范

强制

1. 组件名为多个单词

组件名应该始终是多个单词的,根组件 App 除外。

正例:

 
  1. export default {
  2. name: 'TodoItem',
  3. // ...
  4. }

反例:

 
  1. export default {
  2. name: 'Todo',
  3. // ...
  4. }
2. 组件数据

组件的 data 必须是一个函数。
当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。

正例:

 
  1. // In a .vue file
  2. export default {
  3. data () {
  4. return {
  5. foo: 'bar'
  6. }
  7. }
  8. }
  9. // 在一个 Vue 的根实例上直接使用对象是可以的,
  10. // 因为只存在一个这样的实例。
  11. new Vue({
  12. data: {
  13. foo: 'bar'
  14. }
  15. })

反例:

 
  1. export default {
  2. data: {
  3. foo: 'bar'
  4. }
  5. }
3. Prop定义

Prop 定义应该尽量详细。
在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。

正例:

 
  1. props: {
  2. status: String
  3. }
  4. // 更好的做法!
  5. props: {
  6. status: {
  7. type: String,
  8. required: true,
  9. validator: function (value) {
  10. return [
  11. 'syncing',
  12. 'synced',
  13. 'version-conflict',
  14. 'error'
  15. ].indexOf(value) !== -1
  16. }
  17. }
  18. }

反例:

 
  1. // 这样做只有开发原型系统时可以接受
  2. props: ['status']
4. 为v-for设置键值

总是用 key 配合 v-for。
在组件上总是必须用 key 配合 v-for,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。

正例:

 
  1. <ul>
  2. <li
  3. v-for="todo in todos"
  4. :key="todo.id"
  5. >
  6. {{ todo.text }}
  7. </li>
  8. </ul>

反例:

 
  1. <ul>
  2. <li v-for="todo in todos">
  3. {{ todo.text }}
  4. </li>
  5. </ul>
5.避免 v-if 和 v-for 用在一起

永远不要把 v-if 和 v-for 同时用在同一个元素上。
一般我们在两种常见的情况下会倾向于这样做:

  • 为了过滤一个列表中的项目 (比如 v-for=”user in users” v-if=”user.isActive”)。在这种情形下,请将 users 替换为一个计算属性 (比如 activeUsers),让其返回过滤后的列表。
  • 为了避免渲染本应该被隐藏的列表 (比如 v-for=”user in users” v-if=”shouldShowUsers”)。这种情形下,请将 v-if 移动至容器元素上 (比如 ul, ol)。

正例:

 
  1. <ul v-if="shouldShowUsers">
  2. <li
  3. v-for="user in users"
  4. :key="user.id"
  5. >
  6. {{ user.name }}
  7. </li>
  8. </ul>
  9. </ul>

反例:

 
  1. <ul>
  2. <li
  3. v-for="user in users"
  4. v-if="shouldShowUsers"
  5. :key="user.id"
  6. >
  7. {{ user.name }}
  8. </li>
  9. </ul>
6. 为组件样式设置作用域

对于应用来说,顶级 App 组件和布局组件中的样式可以是全局的,但是其它所有组件都应该是有作用域的。
这条规则只和单文件组件有关。你不一定要使用 scoped 特性。设置作用域也可以通过 CSS Modules,那是一个基于 class 的类似 BEM 的策略,当然你也可以使用其它的库或约定。
不管怎样,对于组件库,我们应该更倾向于选用基于 class 的策略而不是 scoped 特性。
这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有太高的选择器优先级,而且不太会导致冲突。

正例:

 
  1. <template>
  2. <button class="c-Button c-Button--close">X</button>
  3. </template>
  4. <!-- 使用 BEM 约定 -->
  5. <style>
  6. .c-Button {
  7. border: none;
  8. border-radius: 2px;
  9. }
  10. .c-Button--close {
  11. background-color: red;
  12. }
  13. </style>

反例:

 
  1. <template>
  2. <button class="btn btn-close">X</button>
  3. </template>
  4. <style>
  5. .btn-close {
  6. background-color: red;
  7. }
  8. </style>
  9. <template>
  10. <button class="button button-close">X</button>
  11. </template>
  12. <!-- 使用 `scoped` 特性 -->
  13. <style scoped>
  14. .button {
  15. border: none;
  16. border-radius: 2px;
  17. }
  18. .button-close {
  19. background-color: red;
  20. }
  21. </style>

二、强烈推荐(增强可读性)

. 组件文件

只要有能够拼接文件的构建系统,就把每个组件单独分成文件。
当你需要编辑一个组件或查阅一个组件的用法时,可以更快速的找到它。

正例:

 
  1. components/
  2. |- TodoList.vue
  3. |- TodoItem.vue

反例:

 
  1. Vue.component('TodoList', {
  2. // ...
  3. })
  4. Vue.component('TodoItem', {
  5. // ...
  6. })
2. 单文件组件文件的大小写

单文件组件的文件名应该要么始终是单词大写开头 (PascalCase)

正例:

 
  1. components/
  2. |- MyComponent.vue

反例:

 
  1. components/
  2. |- myComponent.vue
  3. |- mycomponent.vue
3. 基础组件名

应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V。

正例:

 
  1. components/
  2. |- BaseButton.vue
  3. |- BaseTable.vue
  4. |- BaseIcon.vue

反例:

 
  1. components/
  2. |- MyButton.vue
  3. |- VueTable.vue
  4. |- Icon.vue
4. 单例组件名

只应该拥有单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。
这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。

正例:

 
  1. components/
  2. |- TheHeading.vue
  3. |- TheSidebar.vue

反例:

 
  1. components/
  2. |- Heading.vue
  3. |- MySidebar.vue
5. 紧密耦合的组件名

和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。

正例:

 
  1. components/
  2. |- TodoList.vue
  3. |- TodoListItem.vue
  4. |- TodoListItemButton.vue
  5. components/
  6. |- SearchSidebar.vue
  7. |- SearchSidebarNavigation.vue

反例:

 
  1. components/
  2. |- SearchSidebar.vue
  3. |- NavigationForSearchSidebar.vue
6. 组件名中的单词顺序

组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。

正例:

 
  1. components/
  2. |- SearchButtonClear.vue
  3. |- SearchButtonRun.vue
  4. |- SearchInputQuery.vue
  5. |- SearchInputExcludeGlob.vue
  6. |- SettingsCheckboxTerms.vue
  7. |- SettingsCheckboxLaunchOnStartup.vue

反例:

 
  1. components/
  2. |- ClearSearchButton.vue
  3. |- ExcludeFromSearchInput.vue
  4. |- LaunchOnStartupCheckbox.vue
  5. |- RunSearchButton.vue
  6. |- SearchInput.vue
  7. |- TermsCheckbox.vue
7. 模板中的组件名大小写

总是 PascalCase 的

正例:

 
  1. <!-- 在单文件组件和字符串模板中 -->
  2. <MyComponent/>

反例:

 
  1. <!-- 在单文件组件和字符串模板中 -->
  2. <mycomponent/>
  3. <!-- 在单文件组件和字符串模板中 -->
  4. <myComponent/>
8. 完整单词的组件名

组件名应该倾向于完整单词而不是缩写。

正例:

 
  1. components/
  2. |- StudentDashboardSettings.vue
  3. |- UserProfileOptions.vue

反例:

 
  1. components/
  2. |- SdSettings.vue
  3. |- UProfOpts.vue
9. 多个特性的元素

多个特性的元素应该分多行撰写,每个特性一行。

正例:

 
  1. <img
  2. src="https://vuejs.org/images/logo.png"
  3. alt="Vue Logo"
  4. >
  5. <MyComponent
  6. foo="a"
  7. bar="b"
  8. baz="c"
  9. />

反例:

 
  1. <img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
  2. <MyComponent foo="a" bar="b" baz="c"/>
10. 模板中简单的表达式

组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。

正例:

 
  1. <!-- 在模板中 -->
  2. {{ normalizedFullName }}
  3. // 复杂表达式已经移入一个计算属性
  4. computed: {
  5. normalizedFullName: function () {
  6. return this.fullName.split(' ').map(function (word) {
  7. return word[0].toUpperCase() + word.slice(1)
  8. }).join(' ')
  9. }
  10. }

反例:

 
  1. {{
  2. fullName.split(' ').map(function (word) {
  3. return word[0].toUpperCase() + word.slice(1)
  4. }).join(' ')
  5. }}
11. 简单的计算属性

正例:

 
  1. computed: {
  2. basePrice: function () {
  3. return this.manufactureCost / (1 - this.profitMargin)
  4. },
  5. discount: function () {
  6. return this.basePrice * (this.discountPercent || 0)
  7. },
  8. finalPrice: function () {
  9. return this.basePrice - this.discount
  10. }
  11. }

反例:

 
  1. computed: {
  2. price: function () {
  3. var basePrice = this.manufactureCost / (1 - this.profitMargin)
  4. return (
  5. basePrice -
  6. basePrice * (this.discountPercent || 0)
  7. )
  8. }
  9. }
12. 带引号的特性值

非空 HTML 特性值应该始终带引号 (单引号或双引号,选你 JS 里不用的那个)。
在 HTML 中不带空格的特性值是可以没有引号的,但这样做常常导致带空格的特征值被回避,导致其可读性变差。

正例:

 
  1. <AppSidebar :style="{ width: sidebarWidth + 'px' }">

反例:

 
  1. <AppSidebar :style={width:sidebarWidth+'px'}>
13. 指令缩写

都用指令缩写 (用 : 表示 v-bind: 和用 @ 表示 v-on:)

正例:

 
  1. <input
  2. @input="onInput"
  3. @focus="onFocus"
  4. >

反例:

 
  1. <input
  2. v-bind:value="newTodoText"
  3. :placeholder="newTodoInstructions"
  4. >

推荐

1. 单文件组件的顶级元素的顺序

单文件组件应该总是让<script>、<template> 和 <style> 标签的顺序保持一致。且 <style> 要放在最后,因为另外两个标签至少要有一个。

正例:

 
  1. <!-- ComponentA.vue -->
  2. <template>...</template>
  3. <script>/* ... */</script>
  4. <style>/* ... */</style>

谨慎使用 (有潜在危险的模式)

1. 没有在 v-if/v-if-else/v-else 中使用 key

如果一组 v-if + v-else 的元素类型相同,最好使用 key (比如两个

元素)。

正例:

 
  1. <div
  2. v-if="error"
  3. key="search-status"
  4. >
  5. 错误:{{ error }}
  6. </div>
  7. <div
  8. v-else
  9. key="search-results"
  10. >
  11. {{ results }}
  12. </div>

反例:

 
  1. <div v-if="error">
  2. 错误:{{ error }}
  3. </div>
  4. <div v-else>
  5. {{ results }}
  6. </div>
2. scoped 中的元素选择器

元素选择器应该避免在 scoped 中出现。
在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的。

正例:

 
  1. <template>
  2. <button class="btn btn-close">X</button>
  3. </template>
  4. <style scoped>
  5. .btn-close {
  6. background-color: red;
  7. }
  8. </style>

反例:

 
  1. <template>
  2. <button>X</button>
  3. </template>
  4. <style scoped>
  5. button {
  6. background-color: red;
  7. }
  8. </style>
3. 隐性的父子组件通信

应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或改变 prop。

正例:

 
  1. Vue.component('TodoItem', {
  2. props: {
  3. todo: {
  4. type: Object,
  5. required: true
  6. }
  7. },
  8. template: `
  9. <input
  10. :value="todo.text"
  11. @input="$emit('input', $event.target.value)"
  12. >
  13. `
  14. })

反例:

 
  1. Vue.component('TodoItem', {
  2. props: {
  3. todo: {
  4. type: Object,
  5. required: true
  6. }
  7. },
  8. methods: {
  9. removeTodo () {
  10. var vm = this
  11. vm.$parent.todos = vm.$parent.todos.filter(function (todo) {
  12. return todo.id !== vm.todo.id
  13. })
  14. }
  15. },
  16. template: `
  17. <span>
  18. {{ todo.text }}
  19. <button @click="removeTodo">
  20. X
  21. </button>
  22. </span>
  23. `
  24. })
4. 非 Flux 的全局状态管理

应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。

正例:

 
  1. // store/modules/todos.js
  2. export default {
  3. state: {
  4. list: []
  5. },
  6. mutations: {
  7. REMOVE_TODO (state, todoId) {
  8. state.list = state.list.filter(todo => todo.id !== todoId)
  9. }
  10. },
  11. actions: {
  12. removeTodo ({ commit, state }, todo) {
  13. commit('REMOVE_TODO', todo.id)
  14. }
  15. }
  16. }
  17. <!-- TodoItem.vue -->
  18. <template>
  19. <span>
  20. {{ todo.text }}
  21. <button @click="removeTodo(todo)">
  22. X
  23. </button>
  24. </span>
  25. </template>
  26. <script>
  27. import { mapActions } from 'vuex'
  28. export default {
  29. props: {
  30. todo: {
  31. type: Object,
  32. required: true
  33. }
  34. },
  35. methods: mapActions(['removeTodo'])
  36. }
  37. </script>

反例:

 
  1. // main.js
  2. new Vue({
  3. data: {
  4. todos: []
  5. },
  6. created: function () {
  7. this.$on('remove-todo', this.removeTodo)
  8. },
  9. methods: {
  10. removeTodo: function (todo) {
  11. var todoIdToRemove = todo.id
  12. this.todos = this.todos.filter(function (todo) {
  13. return todo.id !== todoIdToRemove
  14. })
  15. }
  16. }
  17. })

附录

1. 推荐使用vs code进行前端编码,规定Tab大小为2个空格
  1. vs code配置
 
  1. {
  2. "editor.tabSize": 2,
  3. "workbench.startupEditor": "newUntitledFile",
  4. "workbench.iconTheme": "vscode-icons",
  5. // 以下为stylus配置
  6. "stylusSupremacy.insertColons": false, // 是否插入冒号
  7. "stylusSupremacy.insertSemicolons": false, // 是否插入分好
  8. "stylusSupremacy.insertBraces": false, // 是否插入大括号
  9. "stylusSupremacy.insertNewLineAroundImports": false, // import之后是否换行
  10. "stylusSupremacy.insertNewLineAroundBlocks": false, // 两个选择器中是否换行
  11. "vetur.format.defaultFormatter.html": "js-beautify-html",
  12. "eslint.autoFixOnSave": true,
  13. "eslint.validate": [
  14. "javascript",
  15. {
  16. "language": "html",
  17. "autoFix": true
  18. },
  19. {
  20. "language": "vue",
  21. "autoFix": true
  22. },
  23. "javascriptreact",
  24. "html",
  25. "vue"
  26. ],
  27. "eslint.options": { "plugins": ["html"] },
  28. "prettier.singleQuote": true,
  29. "prettier.semi": false,
  30. "javascript.format.insertSpaceBeforeFunctionParenthesis": false,
  31. "vetur.format.js.InsertSpaceBeforeFunctionParenthesis": false,
  32. "vetur.format.defaultFormatter.js": "prettier",
  33. // "prettier.eslintIntegration": true
  34. }
  1. vs code 插件

Auto Close Tag
Path Intellisense
Prettier
Vetur
vscode-icons

JAVA开发规范

一、命名风格

1.【强制】类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO / DTO / VO / AO
正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion

2.【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从 驼峰形式。
正例: localValue / getHttpMessage() / inputUserId

3.【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例:MAX_STOCK_COUNT 反例:MAX_COUNT

4.【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。

5.【强制】Model 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是 isDeleted(),RPC框架在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

6.【强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。 正例:CacheManagerImpl 实现 CacheManager 接口。

7.【推荐】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达其意。
正例:从远程仓库拉取代码的类命名为PullCodeFromRemoteRepository
反例:变量int a;的随意命名方式。

8.【推荐】接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁 性,并加上有效 的Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。
正例:接口方法签名:void f(); 接口基础常量表示:String COMPANY = “alibaba”;
反例:接口方法定义:public abstract void f();
说明:JDK8 中接口允许有默认实现,那么这个default方法,是对所有实现类都有价值的默 认实现。

9.【参考】枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。
正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKOWN_REASON。

10.【参考】各层命名规约:
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save/insert 做前缀。
5) 删除的方法用 remove/delete 做前缀。
6) 修改的方法用 update 做前缀。

二、变量定义

1.【推荐】不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。 说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。

正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts 下。

三、代码格式

1.【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:
1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有 else 等代码则不换行 表示终止的右大括号后必须换行。
2.【强制】 左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格。
反例:if (空格a == b空格)
3.【强制】if/for/while/switch/do 等保留字与括号之间都必须加空格。
4.【强制】任何二目、三目运算符的左右两边都需要加一个空格。
说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
5.【强制】采用 4 个空格缩进,禁止使用 tab 字符。
说明:Vue工程采用2个空格缩进
6.【强制】注释的双斜线与注释内容之间有且仅有一个空格。
正例:// 注释内容,注意在//和注释内容之间有一个空格。
7.【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
正例:下例中实参的”a”,后边必须要有一个空格。method(“a”, “b”, “c”);
8.【强制】IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 Unix 格式,不要使用 Windows 格式。
9.【推荐】方法体内的执行语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义之间插入一个空行。相同业务逻辑和语义之间不需要插入空行。
说明:没有必要插入多个空行进行隔开。

四、OOP规约

1.【强制】所有的覆写方法,必须加@Override 注解。
2.【强制】不能使用过时的类或方法。
3.【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
正例:”test”.equals(object);
反例:object.equals(“test”);
4.【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑, 推荐使用 equals 方法进行判断。
5.【强制】RPC 方法的返回值和参数必须使用包装数据类型。
6.【强制】构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。
7.【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起, 便于阅读。
8.【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。 说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。
反例:

 
  1. String str = "start";
  2. for (int i = 0; i < 100; i++) {
  3. str = str + "hello";
  4. }

9.【推荐】慎用 Object 的 clone 方法来拷贝对象。 说明:对象的 clone 方法默认是浅拷贝,若想实现深拷贝需要重写 clone 方法实现属性对象 的拷贝。

五、集合处理

1.【强制】使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()。
说明:使用 toArray 带参方法,入参分配的数组空间不够大时,toArray 方法内部将重新分配 内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组 元素将被置为 null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素 个数一致。 正例:

 
  1. List<String> list = new ArrayList<String>(2);
  2. list.add("guan");
  3. list.add("bao");
  4. String[] array = new String[list.size()];
  5. array = list.toArray(array);

反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它 类型数组将出现 ClassCastException 错误。
2.【强制】不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。
正例:

 
  1. Iterator<String> iterator = list.iterator();
  2. while (iterator.hasNext()) {
  3. String item = iterator.next();
  4. if (删除元素的条件) {
  5. iterator.remove();
  6. }
  7. }

反例:

 
  1. List<String> list = new ArrayList<String>();
  2. list.add("1");
  3. list.add("2");
  4. for (String item : list) {
  5. if ("1".equals(item)) {
  6. list.remove(item);
  7. }
  8. }

3.【推荐】使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。

六、控制语句

1.【强制】在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且 放在最后,即使它什么代码也没有。
2.【强制】在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避 单行的编码方式:if (condition) statements;
3.【推荐】除常用方法(如 getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复 杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。 说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么 样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?
正例: // 伪代码如下

 
  1. final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);if (existed) {
  2. ...
  3. }

4.反例:

 
  1. if ((file.open(fileName, "w") != null) && (...) || (...)) {
  2. ...
  3. }

5.【推荐】循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、 获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。
6.【参考】下列情形,需要进行参数校验:
1) 调用频次低的方法。
2) 执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参 数错误导致中间执行回退,或者错误,那得不偿失。
3) 需要极高稳定性和可用性的方法。
4) 对外提供的开放接口,不管是 RPC/API/HTTP 接口。
5) 敏感权限入口。

七、注释规约

1.【强制】类、类属性、类方法的注释必须使用 Javadoc 规范,使用/*内容/ 格式,不得使用 // xxx 方式。
2.【强制】所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、 异常说明外,还必须指出该方法做什么事情,实现什么功能。 说明:对子类的实现要求,或者调用注意事项,请一并说明。
3.【强制】所有的类都必须添加创建者和创建日期。
4.【强制】方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释 使用/ /注释,注意与代码对齐。
5.【强制】所有的枚举类型字段必须要有注释,说明每个数据项的用途。
6.【推荐】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑 等的修改。 说明:代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后, 就失去了导航的意义。
7.【参考】谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。
8.【参考】对于注释的要求:第一、能够准确反应设计思想和代码逻辑;第二、能够描述业务含 义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同 天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路;注释也是给继任者看 的,使其能够快速接替自己的工作。
9.【参考】好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的 一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。

  1. 【参考】特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描, 经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
    1) 待办事宜(TODO):( 标记人,标记时间,[预计处理时间]) 表示需要实现,但目前还未实现的功能。这实际上是一个 Javadoc 的标签,目前的 Javadoc 还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。
    2) 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间]) 在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况。

八、其他

1.【强制】在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。 说明:不要在方法体内定义:Pattern pattern = Pattern.compile(规则);
2.【强制】注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x<1(能够 取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后 取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。
3.【强制】获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime();
4.【推荐】任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存。

九、异常处理

1.【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请 将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的 内容。

十、MySQL数据库

建立表规约

1.【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库 名、表名、字段名,都不允许出现任何大写字母,避免节外生枝。
正例:aliyunadmin,rdc_config,level3_name 反例:AliyunAdmin,rdcConfig,level_3_name
2.【强制】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。
3.【强制】主键索引名为 pk
字段名;唯一索引名为 uk字段名;普通索引名则为 idx字段名。 说明:pk 即 primary key;uk 即 unique key;idx_ 即 index 的简称。
4.【强制】小数类型为 decimal,禁止使用 float 和 double。
5.【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
6.【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text。
7.【强制】表必备三个字段:id,create_time, update_time, delete_flag
8.【强制】对于Boolean型的字段,采用decimal类型
9.【强制】表和字段都需要添加注释信息。
10.【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
11.【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检 索速度。

索引规约

1.【强制】业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。
说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明 显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必 然有脏数据产生。
2.【强制】超过三个表禁止 join。需要 join 的字段,数据类型必须绝对一致;多表关联查询时, 保证被关联的字段需要有索引。
说明:即使双表 join 也要注意表索引、SQL 性能。
3.【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可。
说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度 来确定。
4.【参考】创建索引时避免有如下极端误解:
1)宁滥勿缺。认为一个查询就需要建一个索引。
2)宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。
3)抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。

SQL语句

1.【强制】不要使用 count(列名)或 count(常量)来替代 count(),count()是 SQL92 定义的 标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
2.【强制】count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(di col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。
3.【强制】当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为NULL.
4.【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
5.【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
6.【推荐】in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控 制在 1000 个之内。
7.【参考】如果有全球化需要,所有的字符存储与表示,均以 utf-8 编码,注意字符 的区别。
说明: SELECT LENGTH(“轻松工作”); 返回为 12 SELECT CHARACTER_LENGTH(“轻松工作”); 返回为 4 如果需要存储表情,那么选择 utfmb4 来进行存储,注意它与 -8 编码的区别。
8.【强制】更新数据表记录时,必须同时更新记录对应的 update_time 字段值为当前时间。
9.【参考】@Transactional 事务不要滥用。事务会影响数据库的 QPS,另外使用事务的地方需 要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值