yliu

时来天地皆同力,运去英雄不自由

团队规范系列之命名规范


bg

最近一周的工作重心就是在梳理团队规范,在写的过程也查缺补漏了不少知识,剔除掉关于公司场景的部分就有了这一系列的文章,预计写四部分:

  1. git 规范
  2. 工程规范
  3. 用户体验规范
  4. 命名规范

命名规范

命名规范请结合团队情况来进行制定,如果想更进阶一些可以配合 git 钩子写校验工具,配合规范食用

代码命名规范

避免用一个字母命名

// bad
function q() {
  // ...
}

// good
function query() {
  // ...
}

用小驼峰命名法来命名你的对象、函数、实例

// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}

用大驼峰命名法来命名类

// bad
function user(options) {
  this.name = options.name;
}

const bad = new user({
  name: 'nope',
});

// good
class User {
  constructor(options) {
    this.name = options.name;
  }
}

const good = new User({
  name: 'yup',
});

不要用前置或后置下划线

JavaScript 没有私有属性或私有方法的概念。尽管前置下划线通常的概念上意味着私有,事实上,这些属性是完全公有的,因此这部分也是你的 API 的内容。这一概念可能会导致开发者误以为更改这个不会导致崩溃或者不需要测试。如果你想要什么东西变成私有,那就不要让它在这里出现。

// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';

// good
this.firstName = 'Panda';

export

export-default 导出名称与 import 引用名称保持一致

例如:export-default 模块 A,则这个文件名也叫 A, import 时候的参数也叫 A。 大小写完全一致。

// file 1 contents
class CheckBox {
  // ...
}
export default CheckBox;

// file 2 contents
export default function fortyTwo() { return 42; }

// file 3 contents
export default function insideDirectory() {}

// in some other file
// bad
import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export

// bad
import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
import forty_two from './forty_two'; // snake_case import/filename, camelCase export
import inside_directory from './inside_directory'; // snake_case import, camelCase export
import index from './inside_directory/index'; // requiring the index file explicitly
import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly

// good
import CheckBox from './CheckBox'; // PascalCase export/import/filename
import fortyTwo from './fortyTwo'; // camelCase export/import/filename
import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
// ^ supports both insideDirectory.js and insideDirectory/index.js

export-default 一个函数时,函数名用小驼峰,文件名需要和函数名一致

function makeStyleGuide() {
  // ...
}

export default makeStyleGuide;

export 一个结构体/类/单例/函数库/对象 时用大驼峰

const AirbnbStyleGuide = {
  es6: {},
};

export default AirbnbStyleGuide;

简称和缩写应该全部大写或全部小写

// bad
import SmsContainer from './containers/SmsContainer';

// bad
const HttpRequests = [
  // ...
];

// good
import SMSContainer from './containers/SMSContainer';

// good
const HTTPRequests = [
  // ...
];

// also good
const httpRequests = [
  // ...
];

// best
import TextMessageContainer from './containers/TextMessageContainer';

// best
const requests = [
  // ...
];

导出静态变量

如果导出静态变量,它需要以下条件:

  • 确保被导出
  • 尽量全部大写
  • const 定义的,保证不能被改变
  • 如果导出对象,这个变量是可信的,他的子属性都是不能被改变的
// bad
const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
// bad
export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
// bad
export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
// 允许但不够语义化
export const apiKey = 'SOMEKEY';
// 更好的
export const API_KEY = 'SOMEKEY';

// bad 不必要的大写键,没有增加任何语义
export const MAPPING = {
  KEY: 'value',
};
// good
export const MAPPING = {
  key: 'value',
};

CSS 命名规范

css 命名规范有很多方案,这里采用BEM作为规范,之所以采用 BEM 是因为它让你的前端代码更容易阅读和理解,更容易协作,更容易控制,更加健壮和明确,而且更加严密。

下面介绍一些相关的概念,以及如何书写

什么是 BEM 命名规范

Bem 是块(block)、元素(element)、修饰符(modifier)的简写,由 Yandex 团队提出的一种前端 CSS 命名方法论。

  • 中划线 :仅作为连字符使用,表示某个块或者某个子元素的多单词之间的连接记号。

  • 双下划线:双下划线用来连接块和块的子元素

  • 单下划线:单下划线用来描述一个块或者块的子元素的一种状态

BEM 命名模式

根据上面条件,下面写一个示例

.block {
}

.block__element {
}

.block--modifier {
}

仔细观察上面结构可以得到三个信息:

  • 每一个块(block)名应该有一个命名空间(前缀)
  • block__element 代表 .block 的后代,用于形成一个完整的 .block 的整体
  • block--modifier 代表 .block 的不同状态或不同版本

使用两个连字符和下划线而不是一个,是为了让你自己的块可以用单个连字符来界定。如:

.sub-block__element {
}

.sub-block--modifier {
}

什么时候使用 BEM 命名

  • 你要知道什么时候哪些东西是应该写成 BEM 格式的

或者说你要事先知道效果图或者 dom 结构应当是一个什么样子的

  • 只有模块或者组件有关联的时候才使用 BEM 格式

  • 单独的样式,没有必要使用 BEM 命名

.hide {
  display: none !important;
}

与预处理器结合

BEM 写起来可能会存在命名很长,但是如果有 less 之类的预处理器就能节省我们很多时间,下面以 less 为例

.article {
  max-width: 1200px;
  &__body {
    padding: 20px;
  }
  &__button {
    padding: 5px 8px;
    &--primary {
      background: blue;
    }
    &--success {
      background: green;
    }
  }
}

在 Vue 中使用

Vue 为了简便开发提供了 scope 的 css 语法糖,但是在 BEM 中并不推荐,因为使用scope的目的就是避免样式冲突,而 BEM 本身就已经可以做到了。

<template>
  <form class="form form--theme-xmas form--simple">
    <input class="form__input" type="text" />
    <input class="form__submit form__submit--disabled" type="submit" />
  </form>
</template>

<script lang="css">
.form { }
.form--theme-xmas { }
.form--simple { }
.form__input { }
.form__submit { }
.form__submit--disabled { }
</script>

组件命名规范

文件名应始终单词大写开头或横线连接

单词大写开头对于代码编辑器的自动补全最为友好,因为这使得我们在 JS(X) 和模板中引用组件的方式尽可能的一致。然而,混用文件命名方式有的时候会导致大小写不敏感的文件系统的问题,这也是横线连接命名同样完全可取的原因。

# bad
components/
|- mycomponent.vue
components/
|- myComponent.vue
# good
components/
|- TodoList.js
|- TodoItem.js
# good
components/
|- TodoList.vue
|- TodoItem.vue

基础组件以一个特定的前缀开头

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

# bad
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
# good
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
# or
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
# or
components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue

一次性组件命名

单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。

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

# bad
components/
|- Heading.vue
|- MySidebar.vue
# good
components/
|- TheHeading.vue
|- TheSidebar.vue

组件命名请保持关联

和父组件紧密耦合的子组件应该以父组件名作为前缀命名。

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

# bad
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
# good
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue