# 前端开发规范基础汇总

244 阅读26分钟

前端开发规范基础汇总

命名规范

常用的命名规范

  • camelCase(小驼峰式命名法 —— 首字小写)
  • PascalCase(大驼峰式命名法 —— 首字大写)
  • snake_case(下划线命名法)
  • kebab-case(短横线命名法)

项目文件命名

项目命名

全部采用小写方式,以短横线分隔。例:my-project-name

  • 全部小写,单词之间用中划线隔开
  • 不能以数字开头
  • 不能包含特殊字符(除了中划线)
目录命名

参照项目命名规则,有复数结构时,要采用复数命名法。例:docsassetscomponentsdirectivesmixinsutilsviews

图像文件命名

全部采用小写方式,优先选择单个单词命名,多单词名以短横线分隔。例:my-image-name.png

banner_sina.gif
menu_aboutus.gif
menutitle_news.gif
logo_police.gif
logo_national.gif
pic_people.jpg
pic_TV.jpg
HTML 文件命名

全部采用小写方式,优先选择单个单词命名,多单词名以短横线分隔。例:my-html-name.html

error_report.html
success_report.html
CSS 文件命名

全部采用小写方式,优先选择单个单词命名,多单词名以短横线分隔。例:my-css-name.css

normalize.less
base.less
date-picker.scss
input-number.scss
JavaScript 文件命名

全部采用小写方式,优先选择单个单词命名,多单词名以短横线分隔。例:my-js-name.js

app.js
utils.js
date-util.js
collapse-transition.js

Vue 组件命名

单文件组件名

文件扩展名为.vue的单文件。组件名应该始终是单词大写开头 (PascalCase)。

components/
|- MyComponent.vue
单例组件名

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

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

比如,头部侧边栏组件几乎在每个页面都会使用,不接受prop,该组件是专门为该应用所定制的。

components/
|- TheHeader.vue
|- TheSidebar.vue
基础组件名

不包含业务,独立、具体功能的基础组件.

比如日期选择器模态框等。这类组件作为项目的基础控件,会被大量使用,因此组件的API进行过高强度的抽象,可以通过不同配置实现不同的功能。

应用特定样式和约定的基础组件(也就是展示类的、无逻辑的或无状态、不掺杂业务逻辑的组件) 应该全部以一个特定的前缀开头 —— Base。基础组件在一个页面内可使用多次,在不同页面内也可复用,是高可复用组件。

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
业务组件

它不像基础组件只包含某个功能,而是在业务中被多个页面复用的(具有可复用性),它与基础组件的区别是,业务组件只在当前项目中会用到,不具有通用性,而且会包含一些业务,比如数据请求;而基础组件不含业务,在任何项目中都可以使用,功能单一,比如一个具有数据校验功能的输入框。

掺杂了复杂业务的组件(拥有自身 data、prop 的相关处理)即业务组件应该以Custom前缀命名。业务组件在一个页面内比如:某个页面内有一个卡片列表,而样式和逻辑跟业务紧密相关的卡片就是业务组件。

components/
|- CustomCard.vue
紧密耦合的组件名

和父组件紧密耦合的子组件应该以父组件名作为前缀命名。 因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
组件名中单词顺序

组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。 因为编辑器通常会按字母顺序组织文件,所以现在组件之间的重要关系一目了然。如下组件主要是用于搜索和设置功能。

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue

还有另一种多级目录的方式,把所有的搜索组件放到“search”目录,把所有的设置组件放到“settings”目录。

完整单词的组件名

组件名应该倾向于完整单词而不是缩写。编辑器中的自动补全已经让书写长命名的代价非常之低了,而其带来的明确性却是非常宝贵的。不常用的缩写尤其应该避免。

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue

变量和方法

变量命名

变量命名方法应遵循camelCase(小驼峰式命名法)。命名规范遵循:类型 + 对象描述或属性的方式

// bad
var getTitle = "LoginTable";

// good
let tableTitle = "LoginTable";
let mySchool = "我的学校";
常量命名

常量命名方法应遵循全部大写下划线分割。命名规范遵循:使用大写字母和下划线来组合命名,下划线用以分割单词。

const MAX_COUNT = 10
const URL = 'http://test.host.com'
方法命名

方法命名方法应遵循camelCase(小驼峰式命名法)。命名规范遵循:动词 或者 动词 + 名词的方式。

// 1、普通情况下,使用动词 + 名词形式
// bad
go、nextPage、show、open、login

// good
jumpPage、openCarInfoDialog

// 2、请求数据方法,以 data 结尾
// bad
takeData、confirmData、getList、postForm

// good
getListData、postFormData

// 3、单个动词的情况
init、refresh
动词含义返回值
can判断是否可执行某个动作 (权 )函数返回一个布尔值。true:可执行;false:不可执行;
has判断是否含有某个值函数返回一个布尔值。true:含有此值;false:不含有此值;
is判断是否为某个值函数返回一个布尔值。true:为某个值;false:不为某个值;
get获取某个值函数返回一个非布尔值
set设置某个值无返回值、返回是否设置成功或者返回链式对象
自定义事件

自定义事件应始终使用 kebab-case 的事件名,事件名应全部小写,且使用短横线命名。

this.$emit('my-event')

<MyComponent @my-event="handleDoSomething" />
  • 原生事件参考列表
<div
  @blur="toggleHeaderBlur"
  @focus="toggleHeaderFocus"
  @click="toggleMenu"
  @keydown.esc="handleKeydown"
  @keydown.enter="handleKeydown"
  @keydown.up.prevent="handleKeydown"
  @keydown.down.prevent="handleKeydown"
  @keydown.tab="handleKeydown"
  @keydown.delete="handleKeydown"
  @mouseenter="hasMouseHoverHead = true"
  @mouseleave="hasMouseHoverHead = false"
></div>

而为了区分原生事件和自定义事件在 Vue 中的使用,建议除了多单词事件名使用 kebab-case 的情况下,命名还需遵守为 on + 动词 的形式,如下:

<!-- 父组件 -->
<div
  @on-search="handleSearch"
  @on-clear="handleClear"
  @on-clickoutside="handleClickOutside"
></div>

// 子组件 export default { methods: { handleTriggerItem () {
this.$emit('on-clear') } } }
事件方法

事件方法命名应遵循camelCase(小驼峰式命名法)。命名规范遵循:handle + 名称(可选)+ 动词的方式。

<div
  @click.native.stop="handleItemClick()"
  @mouseenter.native.stop="handleItemHover()"
></div>

export default { methods: { handleItemClick () { // 业务逻辑... },
handleItemHover () { // 业务逻辑... } } }

编码规范

HTML/Template 编码规范

语法

1. 缩进使用两个空格代替 Tab

  • 前端代码层级较深,使用短缩进有利于利用屏幕空间,提升效率。
  • 使用两个空格代替 Tab 可以保证在所有环境下获得一致展现。
<!-- not good -->
<div>
  <div>bar</div>
</div>

<!-- good -->
<div>
  <div>bar</div>
</div>

2. 嵌套元素应当缩进一次(即两个空格),同层级缩进应保持一致

<!-- not good -->
<div>
  <div>bar</div>
  <div>bar</div>
</div>

<!-- good -->
<div>
  <div>bar</div>
  <div>bar</div>
</div>

3. 对于属性的定义,使用双引号,不要使用单引号

<!-- not good -->
<input class="a" type="text" />

<!-- good -->
<input class="a" type="text" />

4. 不要省略可选的结束标签(closing tag)(如 或 )

<!-- not good -->
<h1>
  h1 text
  <h2>
    h2 text

    <!-- good -->
    <h1>h1 text</h1>
    <h2>h2 text</h2>
  </h2>
</h1>

5. 特殊符号使用 HTML 字符实体(实体名称对大小写敏感),常用如下:

符号实体编码
空格&nbsp;
©&copy;
¥&yen;
®&reg;
&gt;
<&lt;
&&amp;

6. td / th 要在 tr 里面,li 要在 ul / ol 里面

<!-- not good -->
<table>
  <td>test</td>
</table>

<!-- good -->
<table>
  <tr>
    <td>test</td>
  </tr>
</table>

7. ul / ol 的直接子元素只能是 li,不能包含其他元素

<!-- not good -->
<ul>
  <span>123</span>
  <li>a</li>
  <li>b</li>
</ul>

8. 行内元素里面不可使用块级元素

a 标签是一个行内元素,行内元素里面套了一个 div 的标签,这样可能会导致 a 标签无法正常点击。

<!-- not good -->
<a href="../test">
  <div></div>
</a>

可以使用如下代码进行修复:

<a href="../test" style="display: block">
  <div></div>
</a>

9. 不使用重复属性,重复的属性只会取第一个

<!-- error -->
<input class="a" type="text" class="b" />

<!-- good -->
<input class="a b" type="text" />

10. 不要在自闭合(self-closing)元素的尾部添加斜线( HTML5 规范中说明这是可选的)

<!-- not good -->
<img src="logo.png" alt />

<!-- good -->
<img src="logo.png" alt />

11. 尽量不使用属性设置样式(img, table等元素)

<!-- not good -->
<img src="test.jpg" alt width="400" height="300" />

<!-- good -->
<img src="test.jpg" style="width:400px;height:300px;" />

11.自定义属性要以data-开头 自己添加的非标准的属性要以data-开头,否则w3c validator会认为是不规范的

<!-- not good -->
<div count="5"></div>

<!-- good -->
<div data-count="5"></div>
HTML5 doctype

为每个 HTML 页面添加标准模式(standard mode)的声明,确保在每个浏览器中拥有一致的展现。

<!DOCTYPE html>

<html>
  ...
</html>
语言属性

为每个 HTML 页面根元素添加 lang 属性。

根据 HTML5 规范:

强烈建议为 html 根元素指定 lang 属性,从而为文档设置正确的语言。这将有助于语音合成工具确定其所应该采用的发音,有助于翻译工具确定其翻译时所应遵守的规则等等。

<html lang="zh-CN">
  <!-- ... -->
</html>
字符编码

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

<html>
  <head>
    <meta charset="UTF-8">
  </head>
  ...
引入CSS和JavaScript文件

根据 HTML5 规范,在引入 CSS 和 JavaScript 文件时不需要指定 type 属性,因为 text/css 和 text/javascript 分别是它们的默认值。

<!-- External CSS -->
<link rel="stylesheet" href="code_guide.css" />

<!-- In-document CSS -->
<style>
  ...
</style>

<!-- External JS -->
<script src="code_guide.js"></script>

<!-- In-document JS -->
<script>
  ...
</script>
减少标签的数量

建议编写 HTML 代码时,条件满足的情况下尽量避免多余的层级。

<!-- not good -->
<span class="avatar">
  <img src="..." />
</span>

<!-- good -->
<img class="avatar" src="..." />
属性顺序

仅做参考:属性应该按照特定的顺序出现以保证易读性。

1. class
2. id
3. name
4. data-*
5. src, for, type, href, value , max-length, max, 7. min, pattern
8. placeholder, title, alt
9. aria-*, role
10. required, readonly, disabled
语义化

尽量遵循 HTML 标准和语义,但是不要以牺牲实用性为代价;任何时候都要尽量使用最少的标签并保持最小的复杂度。

CSS/Less编码规范

命名

1. 类名使用小写字母,以中划线分隔

<div class="user-info">
  <div class="user-info-name">
    <span>张三</span>
  </div>
</div>

2. id 采用驼峰式命名

<div id="userInfo">
  <div class="user-info-name">
    <span>张三</span>
  </div>
</div>

3. less 中的变量、函数、混合等采用驼峰式命名

@mainFontColor: #444;

#companyName,
.company-name {
  color: @mainFontColor;
}
语法

1. 所有声明语句都应当以分号结尾

最后一条声明语句后面的分号是可选的,但是,如果省略这个分号,你的代码可能更易出错

/* error */
.selector {
  font-size: 15px
  color: red
}

/* not good */
.selector {
  font-size: 15px;
  color: red
}

/* good */
.selector {
  font-size: 15px;
  color: red;
}

2. 避免为 0 值指定单位

例如:用 margin: 0; 代替 margin: 0px;

/* not good */
.selector {
  margin: 0px;
}

/* good */
.selector {
  margin: 0;
}

3. 为选择器中的属性添加双引号,例如,input[type="text"];

某些情况下是可选的,但是,为了代码的一致性,建议都加上双引号。

/* not good */
.selector[type="text"] {
  /* ... */
}

/* good */
.selector[type="text"] {
  /* ... */
}

4. 十六进制值应该全部小写

例如,#f3f6fa 而不是 #F3F6FA

/* not good */
.selector {
  color: #f3f6fa;
}

/* good */
.selector {
  color: #f3f6fa;
}

5. 不出现空的规则(声明块中没有声明语句)

/* not good */
.selector {
}

/* good */
.selector {
  color: #f3f6fa;
}

6. 不要设置太大的z-index

一个正常的系统的层级关系在 10 以内就能完成。

/* not good */
.selector {
  z-index: 9999;
}

/* good */
.selector {
  z-index: 10;
}

7. 多写注释,且多使用句子进行描述而不是词语

/* 为了去除输入框和表单点击时的灰色背景 */
input,
form {
  -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}

8. 非特殊情况下,不要使用*选择器

9. 适当使用:before和:after来画页面的一些视觉上的辅助性元素,如三角形、短的分隔线、短竖线等,可以减少页面上没有用的标签

10. 选择器不要超过4层(在 Less 中避免嵌套超过 4 层)

11. 用 border: 0; 代替 border: none;

/* not good */
.selector {
  border: none;
}

/* good */
.selector {
  border: 0;
}

12. 使用简写形式的十六进制值

例如:用 #fff 代替 #ffffff

13. 对于属性值或颜色参数,省略小于 1 的小数前面的 0

例如:.5 代替 0.5-.5px 代替 -0.5px

选择器权重

权重判断基本规则:

  1. 相同的权重:以后面出现的选择器为最后规则;
  2. 不同的权重,权重值高则生效;

设置规范:

  • 非通用样式使用嵌套方式进行编写,避免影响其他自己不了解样式,造成样式覆盖;
  • Vue 中样式合理使用scoped,会影响样式选择器性能,请使用第一点进行特有样式编写;
  • 样式需要修改时,尽量找到原样式声明进行修改;
  • 无法修改原样式声明时,应通过权重关系,编写权重更高的样式进行覆盖;
  • 不使用!important,除非原样式使用内联样式或!important且无法直接修改;
声明简写

1. 当你不确定自己写的属性会否影响到其他属性时,应避免使用简写

/* error */
.element {
  margin: 0 0 10px;
  background: red;
  background: url("image.jpg");
  border-radius: 3px 3px 0 0;
}

/* good */
.element {
  margin-bottom: 10px;
  background-color: red;
  background-image: url("image.jpg");
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}

2. 当你确定自己的声明不会影响到其他属性时,请使用简写提升代码简洁性

/* not good */
.element {
  padding-top: 10px;
  padding-right: 20px;
  padding-bottom: 15px;
  padding-left: 20px;
}

/* good */
.element {
  padding: 10px 20px 15px;
}

JavaScript编码规范

命名

1. 标准变量采用驼峰式命名

考虑与后台交换数据的情况,对象属性可灵活命名。

let userName = "张三";
let userAge = 18;

2.常量全大写,用下划线连接

const USER_NAME = "张三";
const USER_AGE = 18;

3. 变量名并非越短越好

变量名不应过短,要能准确完整地描述该变量所表述的事物。

不好的变量名好的变量名
inpinput, priceInput
day1, day2, param1today, tomorrow
iduserId, orderId
objorderData, houseInfos
tIdremoveMsgTimerId
handlersubmitHandler, searchHandler

4. 变量名不要使用计算机术语

texareaData,应该取和业务相关的名字,如 leaveMsg

5. 变量名的对仗要明确

up/downbegin/endopened/closedvisible/invisiblescource/target

6. 变量名使用正确的语法

不要使用中文拼音,如 shijianchuo 应改成 timestamp ; 如果是复数的话加 s,或者加上 List,如 orderListmenuItems; 而过去式的加上 ed,如 updated/found 等; 如果正在进行的加上 ing,如 calling

7.使用临时变量时请结合实际需要进行变量命名

有些喜欢取tempobj之类的变量,如果这种临时变量在两行代码内就用完了,接下来的代码就不会再用了,还是可以接受的,如交换数组的两个元素。但是有些人取了个temp,接下来十几行代码都用到了这个temp,这个就让人很困惑了。所以应该尽量少用temp类的变量。

// not good
let temp = 10;
let leftPosition = currentPosition + temp,
    topPosition = currentPosition - temp;

// good
let adjustSpace = 10;
let leftPosition = currentPosition + adjustSpace,
     topPosition = currentPosition - adjustSpace;
语法

1. 变量不要先使用后声明

a = 10;
let a;

2. 不要声明了变量却不使用

let a = 10;
let b;
a = 15;

3. 不要在同个作用域下声明同名变量

let a = 10;
let a = 15;

4. 一个函数作用域中所有的变量声明尽量提到函数首部,可根据代码进行分组,但不允许出现两个连续的变量声明

// not good
let registerForm = null;
let question = "";
let calculateResult = 0;

// good
let registerForm = null,
  question = "",
  calculateResult = 0;

5. 为了快速知晓变量类型,声明变量时要赋值

// not good
let registerForm, question, calculateResult;

// good
let registerForm = null,
  question = "",
  calculateResult = 0;

6. 单一函数的返回值类型要确定

如下无法确定该函数的最终返回类型:

// not good
function calculatePrice(seatCount) {
  if (seatCount <= 0) {
    return "";
  } else {
    return seatCount * 79;
  }
}

7. 建议使用===代替==!==代替!=

==会自动进行类型转换,可能会出现奇怪的结果。

null == undefined; //true
"" == "0"; //false
0 == ""; //true
0 == "0"; //true
" \t\r\n " == 0; //true
new String("abc") == "abc"; //true
new Boolean(true) == true; //true
true == 1; //true

8. 使用三目运算代替简单的 if-else

// not good
let seatDiscount = 100;
if (seat < 5) {
  seatDiscount = 90;
} else if (seat < 10) {
  seatDiscount = 80;
} else {
  seatDiscount = 70;
}

// good
let seatDiscount = seat < 5 ? 90 : seat < 10 ? 80 : 70;

9. 使用let定义变量,const定义常量

let userName = "张三";
const USER_NAME = "张三";

10. 使用箭头函数取代简单的函数

// not good
let _this = this;
setTimeout(function () {
  _this.foo = "bar";
}, 2000);

// good
setTimeout(() => (this.foo = "bar"), 2000);

11. 建议在必要的地方添加非空判断以提高代码的稳健性

12. 建议将复杂的函数分解成多个子函数,方便维护和复用

代码风格

该部分一般采用代码格式化工具进行统一维护,不再表述。

布局规范

整体布局结构

所有业务页面统一遵循结构:

容器(页面) - 筛选区 - 操作区 - 分页/底部

示例:

<template>
  <div class="page-container">
    <!-- 筛选区 -->
    <div class="page-filter"></div>

    <!-- 操作按钮区 -->
    <div class="page-operation"></div>

    <!-- 内容主体区 -->
    <div class="page-content"></div>

    <!-- 分页/底部 -->
    <div class="page-pagination"></div>
  </div>
</template>

布局类名规范(统一命名)

大布局一般为 “顶部标题区域 + 左侧菜单区域 + 右侧内容区域”。

右侧内容区域的布局为:

  • .page-container 页面最外层容器
  • .page-filter 筛选表单区域
  • .page-operation 新增 / 编辑 / 删除 / 导出等按钮
  • .page-content 表格 / 卡片 / 列表主体
  • .page-pagination 分页组件

好处: 全局统一,新人一看就懂。

注意:

  • 相同布局页面样式在系统内需保持一致;
  • class 命名可根据实际自定义,但尽量保持统一;
  • 若某页面需要单独定制样式,需在涉及页面单独处理,不得影响到全局样式;
  • 筛选区域、按钮区域、内容区域、页脚区域需设置必要间距,且边距统一,提高易读性,不可出现零散值;
  • 页面整体需进行可视化区域自动适配,保证在浏览器大小缩放时,页面布局不会撑出可视区域或压缩在某一区域;

CSS 布局规范

  1. 布局统一使用 Flex/Grid 布局,严禁使用大量float方式进行布局;
  2. 页面在无特殊情况下,严禁出现横向滚动条;
  3. 页面在无特殊情况下,严谨出现多条纵向滚动条;
  4. 页面在无特殊情况下,减少使用 position: absolute 进行定位;
  5. 页面整体样式需要与系统相统一;
  6. 页面在没有美工设计的前提下,必须保持页面的整体和谐;
  7. 禁止在页面内编写大量的行内样式style
  8. 禁止使用!important覆盖样式(除修改第三方组件样式外);
  9. 禁止页面嵌套超5层无用的div
  10. 禁止相似页面使用不同的页面布局结构;
  11. 禁止一个页面里面使用同一布局套娃;

内容布局

查询区域注意事项
  • 查询区域布局,需保持查询条件输入框、选择器、查询按钮等组件大小一致,严禁出现高度不一致、长短不一致情况发生;

  • 每个查询区域的标题长度需保持一致,并右对齐展示;

  • 输入框、选择器等输入组件在未输入内容时,需展示必须要占位信息;

  • 若查询区域存在多个查询条件造成多行显示,需要保持上下双行查询条件输入框长度对齐;

按钮区域注意事项
  • 按钮区域 新增、编辑、批量删除、导入、导出、查询、重置按钮等按钮组件大小一致,严禁出现高度不一致、按钮图标不统一等情况发生;

  • 在按钮点击有前置条件的情况下,在前置条件不满足的时候,需要设置按钮为不可用状态;

表格/内容区域注意事项
  • 内容区域需要根据页面大小进行适配,保证页面内容可以撑起整个可视区域;
  • 内容区域若是表格,则表格高度需要实现自适应,表格内容高度超出表格,则在表格内部实现纵向滚动,不能涉及整个页面的滚动;
  • 内容区域若是表格,标头必须固定在顶部不动,标题尽可能避免出现多行,内容在无特殊情况下需进行超出隐藏设置,并在鼠标悬浮时可展示完整信息;
  • 内容区域若是表格,存在操作栏,操作列固定于表格最右侧,操作栏按钮整体使用文本按钮;
  • 内容区域在查询过程中,需要提供必要的加载动画;
  • 内容区域在无数据时,不可展示空白页面,必须存在“暂无数据”等文案进行提示;
底部/分页注意事项
  • 若底部为分页,默认需要靠右显示;
  • 若为页脚,需要保持固定于页面底部显示;

组件开发注意事项

组件设计原则

  • 单一职责:一个组件只做一件事(如 Pagination 只处理分页,SearchInput 只处理搜索输入),避免「万能组件」。
  • 高内聚低耦合:组件内部逻辑闭环,对外只暴露必要的接口(props/emit/slot),不依赖外部上下文(如全局变量、路由)。
  • 可复用性:通用组件需考虑多场景适配(如按钮支持不同尺寸、状态),业务组件需解耦具体业务逻辑。
  • 可维护性:组件代码量控制在 500 行内,复杂逻辑拆分子组件或抽离工具函数。
  • 易用性:组件使用方式直观,props/emit 命名语义化,提供清晰注释和使用示例。

组件拆分要求

  • 弹窗区域,严禁与主页面写为一起,必须拆分为弹窗组件,弹窗数据独立维护;
  • 基础/业务通用组件需放置于独立文件夹,统一结构,方便维护和管理;
  • 页面子组件无需独立文件夹,和页面主组件同目录;
  • 组件内样式必须加scoped,避免样式污染;
  • 如需修改第三方组件样式,使用样式穿透 :deep()(避免全局样式);
  • 组件内涉及复杂逻辑(如数据处理、校验)抽离为组合式函数/工具函数;
  • 组件内涉及定时器/事件监听等,需在onUnmounted中清除,避免内存泄漏;
  • 组件内必须添加必要注释,解释函数作用、参数作用、变量作用等;

注意事项:

  • 禁止组件内直接修改 props(需通过 emit 通知父组件修改);
  • 禁止通用组件依赖全局状态(如 Pinia/Vuex,如需使用需通过 props 传入);
  • 禁止组件内写绝对路径(如 ../assets/images/btn.png,使用 @/assets/images/btn.png);
  • 禁止在组件内操作路由/浏览器API(如 window.location),如需操作通过 emit 交由父组件处理;
  • 禁止组件嵌套超过 3 层(复杂组件拆分子组件);

代码注释规范

通用注解原则

  • 简洁且有意义:避免无意义的注解(如// 声明变量a),只解释为什么这么做(而非 “做了什么”)。
  • 及时更新:代码修改后,必须同步更新注解,避免 “注解和代码不一致”。
  • 分层注解:按 “文件级 → 模块 / 组件级 → 函数 / 方法级 → 关键行级” 分层注解,覆盖核心逻辑。
  • 统一风格:团队内统一注解符号(如 JS 用//单行、/** */多行,CSS 用/* */)。

文件级注解(文件最顶部)

用于说明文件的用途、作者、更新时间、依赖等,推荐格式:

/**
 * @file 文件用途。如:用户信息相关工具函数(如登录态校验、用户信息格式化)
 * @author 作者信息。如:张三 <zhangsan@example.com>
 * @version 版本信息。如:1.0.0
 * @date 日期。如:2026-03-06
 * @description 描述信息。如:该文件包含用户登录态校验、用户信息格式化等工具函数。
 */

函数/方法级注解

覆盖参数、返回值、异常、备注等,是团队协作的核心:

/**
 * 格式化用户信息(脱敏+补全默认值)
 * @param {UserInfo} user - 原始用户信息对象
 * @param {boolean} [isHidePhone=true] - 是否隐藏手机号(默认true)
 * @returns {FormattedUserInfo} 格式化后的用户信息
 * @throws {Error} 当user为空时抛出异常
 * @example
 * // 调用示例
 * const formatted = formatUserInfo({ name: '张三', phone: '13800138000' });
 * console.log(formatted.phone); // 138****8000
 */

关键行级注解

仅标注 “非直观逻辑”“特殊处理”“临时兼容” 等场景:

// 兼容iOS 14以下的日期解析bug(2026-06-01后可移除)
const parseDate = (dateStr) => {
  return isIOS14Below
    ? new Date(dateStr.replace(/-/g, "/"))
    : new Date(dateStr);
};

Vue 文件注解规范案例

<template>
  <!-- 用户信息卡片:展示头像、名称、手机号,支持点击跳转详情 -->
  <div class="user-card" @click="goToDetail">
    <img :src="user.avatar" alt="用户头像" />
    <span class="user-name">{{ user.name }}</span>
  </div>
</template>

<script setup>
  /**
   * @component UserCard 【用户信息卡片组件】
   * @props {UserInfo} user - 必传,用户信息对象
   * @props {boolean} [showPhone=true] - 是否显示手机号
   * @emits {void} click - 点击卡片时触发
   * @example
   * <UserCard :user="userInfo" @click="handleClick" />
   */
  import { defineProps, defineEmits } from "vue";

  // 定义props(关键:和上方@props注解对应)
  const props = defineProps({
    user: {
      type: Object,
      required: true,
      description: "用户信息对象(包含name/phone/avatar)",
    },
    showPhone: {
      type: Boolean,
      default: true,
      description: "是否显示脱敏后的手机号",
    },
  });

  const emit = defineEmits(["click"]);
  const goToDetail = () => emit("click");
</script>

<style scoped>
  /* 用户卡片基础样式:适配移动端,默认居中 */
  .user-card {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
  }
  /* 用户名样式:区分管理员(红色)和普通用户(黑色) */
  .user-name {
    color: v-bind('user.role === "admin" ? "#f00" : "#333"');
  }
</style>

注解避坑指南

  • 避免过度注解:如// 定义变量(无意义)、// 循环遍历数组(代码本身已说明);
  • 避免注解矛盾:代码修改后未更注解(如函数参数名改了,注解还写旧名称);
  • 避免 “TODO” 泛滥:临时注解需标注截止时间,如 // TODO: 优化性能(2026-04-01前完成)
  • 避免中英混用:团队内统一用中文或英文(推荐中文,适配国内开发场景)。

代码提交规范

  • 代码提交前需要在本地进行代码检查,确保代码符合规范,在运行、打包过程中无错误,严禁将错误代码提交到仓库。

  • 代码提交时,需要将代码在调试过程中编入的打印语句(如 console.log)、测试代码等删除或注释,避免在生产环境中打印敏感信息,或团队开发过程中产生过多的无效的调试信息或产生无用代码。

  • 代码提交时,需要在注释中说明本次提交的内容,包括但不限于:新增功能、修复bug、优化性能、代码重构等。

  • 项目开发过程中,当某功能或模块的代码量较大,建议分多次提交,每次提交只包含该功能或模块的相关代码,避免一次提交包含过多的代码。

  • 项目开发过程中,按时提交代码,建议每完成一个功能或模块,就提交一次代码,减少代码冲突几率,切勿一次提交包含多个功能或模块的代码。

  • 每天工作结束后,必须将当前开发完毕的代码提交到版本控制仓库(如Git),并添加有意义的提交注释。

  • 每天工作开始前,必须从版本控制仓库(如Git)拉取最新代码,确保本地代码与仓库代码一致。

提交信息(Commit Message)规范

业界最主流的是 Conventional Commits(约定式提交) 规范,格式统一且易解析,核心结构如下:

<类型>[可选作用域]: <描述>

[可选正文]

[可选脚注]
各部分详解
类型(Type):必填,标识提交的核心目的
类型说明适用场景
feat新增功能新增组件、新增接口、新增页面
fix修复 Bug修复功能异常、兼容问题、逻辑错误
docs仅文档修改注释更新、README 调整、接口文档修改
style仅格式修改(不影响代码逻辑)缩进、空格、换行、代码格式化
refactor重构(既不是新增功能也不是修复 Bug)代码结构优化、变量名调整、逻辑拆分
perf性能优化减少渲染次数、优化循环、减小包体积
test新增 / 修改测试代码单元测试、集成测试补充
build构建相关修改依赖版本调整、webpack 配置修改、打包脚本
ciCI/CD 配置修改GitHub Actions、Jenkins 配置调整
chore其他不影响源码 / 测试的修改清理无用文件、配置文件修改、脚本调整
revert回滚某次提交恢复到上一个稳定版本
作用域(Scope)

可选,标识提交影响的模块 / 文件

作用域需贴合项目结构,让读者快速定位影响范围,示例:

  • 前端:user(用户模块)、cart(购物车)、button(按钮组件)、api(接口层)
  • 通用:global(全局)、utils(工具函数)、router(路由)
描述(Description)

必填,简洁说明提交内容

  • 首字母小写,结尾不加标点
  • 长度控制在 50 字符内,只说 “做了什么”,不展开细节
  • 用祈使句(如 add 而非 added,fix 而非 fixed)
正文(Body)

可选,详细说明提交背景 / 原因

  • 换行后编写,可分段,解释 “为什么这么改”“改了哪些细节”
  • 如需列出修改点,用短横线 - 分隔
脚注(Footer)

可选,标注特殊信息

  • 关联 Issue:Closes #123(关闭 Issue 123)、Related to #456(关联 Issue 456)
  • 不兼容变更:BREAKING CHANGE: 重构用户信息格式化函数,入参结构调整
  • 回滚说明:Reverts commit 1234567,原因:修复逻辑引入新 Bug
示例
# 基础示例(新增功能)
feat(user): 新增用户头像裁剪功能

# 带作用域+正文+脚注(修复 Bug)
fix(cart): 修复购物车数量为0时结算按钮仍可点击的问题

- 增加数量校验逻辑
- 禁用结算按钮的样式优化

Closes #89

# 重构示例
refactor(utils): 优化日期格式化函数结构

- 拆分通用逻辑和业务逻辑
- 增加参数校验,避免空值报错

# 回滚示例
revert: feat(user): 新增用户头像裁剪功能

Reverts commit 789abc,原因:裁剪逻辑与第三方头像组件冲突
提交步骤示例
# 1. 查看修改文件
git status

# 2. 添加需要提交的文件(避免 git add . 全量添加)
git add src/views/user/avatar.vue src/utils/crop.js

# 3. 提交(使用 -m 写简短描述,复杂提交用 git commit 进入编辑器写完整信息)
git commit -m "feat(user): 新增用户头像裁剪功能"

# 4. 推送分支到远程
git push origin feature/user-avatar