---
|
description:
|
globs:
|
alwaysApply: true
|
---
|
|
# 开发规范
|
|
## 开发规范宗旨
|
|
**代码首先是给人读的,其次才是给机器运行**,所以让代码容易阅读是你应尽的责任
|
包括但不限于以下内容:
|
- 给变量、函数命名时,需要具有实义
|
- 避免使用难懂的语法或设计,用最简单的方式解决问题
|
- 避免单块代码过长,拆分为多个更简短的函数或方法
|
- 避免代码重复,通过封装函数、类或模块进行复用,封装遵守单一职责原则
|
- 写注释应解释 "为什么" 而不仅仅是 "做什么"
|
|
### 命名需要具有实义
|
|
命名的原则是名称中有具体实体含义的词汇
|
|
比如没有实义的
|
|
```js
|
const onClick = () => null; // 不好的命名
|
```
|
|
因为 `click` 可以发生在任何元素上,从这个名称上无法分辨业务种类,所以我们认为这个函数名没有实义,需要改进一下:
|
|
```js
|
const onProductSelected = () => null; // 良好的命名
|
```
|
|
改进后,从函数名一看便知,这是商品被选中了以后的需要进行的操作,又因为具备了在同一个页面的唯一性,能帮我们快速获取信息,知道这是哪个业务的哪个环节,大幅提高阅读效率,这就是实义
|
|
## 常见命名要求
|
|
### JS 变量和属性的命名
|
|
使用小驼峰,注意不能以动词开头
|
|
```js
|
// 变量
|
const name = '';
|
const orderList = '';
|
// 属性
|
const user = {
|
name: '',
|
lastOrder: '',
|
};
|
```
|
|
#### 变量命名的特别约定
|
|
**变量名允许 is 开头**
|
变量名不能用动词开头,但是允许 is 作为特例
|
|
```js
|
// 允许 is 开头的变量名
|
let isOpened = false;
|
// 更好的命名
|
let selectorOpened = false;
|
```
|
|
**事件变量用 evt**
|
事件 event 的简写,必须是 evt(不能用单字母 e )
|
|
```html
|
<view @tap="evt => onOrderClick(evt)"></view>
|
<CMenu :onClick="evt => onMenuItemClick(evt)" />
|
```
|
|
**报错信息用 err**
|
报错 error 的简写,必须是 err(不能用单字母 e )
|
|
```js
|
Taro.request({
|
fail: err => {},
|
});
|
```
|
|
**后端数据 res**
|
后端返回数据,优先采用 resource 的简写 res
|
|
```js
|
$fetch.getEquipments().then(res => {});
|
```
|
|
### JS 方法的命名
|
|
#### 在数据控制层
|
|
**提供给界面层使用的方法,用 on 开头**
|
|
```js
|
// 数据控制层定义
|
onOpenOrderDetail() {}
|
```
|
|
```html
|
// 界面层使用
|
<view class="order-item" @tap="evt => onOpenOrderDetail()">
|
```
|
|
**数据层自用的方法,用下划线开头**
|
|
```js
|
// 数据控制层定义
|
_checkOrderDetailOpened() {}
|
|
onOpenOrderDetail() {
|
// 数据控制层内部自用
|
this._checkOrderDetailOpened();
|
}
|
```
|
|
#### 在组件内
|
|
**接收父级方法的时候,用 on 开头**
|
|
```js
|
export default {
|
props: {
|
// 选择会员后的回调
|
onUserSelected: Function,
|
},
|
}
|
```
|
|
**组件自身模版绑定的时候,用 handle 开头**
|
|
```js
|
export default {
|
methods: {
|
// 组件层定义
|
handleUserSelected() {}
|
}
|
}
|
```
|
|
```html
|
// 组件层自身模板绑定
|
<view class="user-item" @tap="evt => handleUserSelected()">
|
```
|
|
**函数相互调用的时候,用下划线开头**
|
|
```js
|
export default {
|
methods: {
|
// 组件层定义
|
_checkUser() {},
|
handleUserSelected() {
|
// 组件层内部自用
|
this._checkUser()
|
}
|
}
|
}
|
```
|
|
**给父级ref的引用进行调用的方法,使用 $ 开头**
|
|
```js
|
export default {
|
methods: {
|
// 组件层定义
|
$close() {}
|
}
|
}
|
```
|
|
父级
|
|
```html
|
<CUserDetail ref="userDetail">
|
```
|
|
```js
|
onCloseAll() {
|
// 父级 ref 调用
|
this.$refs.userDetail.$close()
|
}
|
```
|
|
### 样式命名
|
|
样式名的命名,采用横杠连接
|
|
```css
|
.page-name {}
|
```
|
|
#### 界面样式
|
|
任何一个界面必定包含众多样式,所以:
|
|
* 最父级样式名固定,与界面名称一直
|
* 中间层,需要以父级为前缀,接板块说明
|
* 末端则可单名,且尽量不含实义
|
|
```css
|
/** 在界面 userList.vue 中,最父级样式名名称固定 **/
|
.user-list {
|
|
/** 中间多层,以父级为前缀 **/
|
.user-list-title {
|
|
/** 末端可单名,尽量非实义 **/
|
.left,
|
.text,
|
.icon,
|
.sub,
|
.close {}
|
}
|
}
|
```
|
|
#### 组件样式
|
|
组件样式名必须已 `c-` 开头,最父级样式名必须与组件名挂钩
|
|
例如,组件 CMenu.vue 中,最父级样式名必须是:
|
|
```css
|
.c-menu {}
|
```
|
|
|
### 文件命名
|
|
常用文件命名约定
|
|
#### 界面层文件
|
|
界面层文件(.vue、.scss),采用小驼峰命名
|
|
```
|
index.vue
|
index.scss
|
```
|
|
#### 数据控制层文件
|
|
数据控制器文件(.js),以固定前缀 P 开头,再接大驼峰
|
|
```
|
PIndex.js
|
```
|
|
数据层代码定义的名称,需要和文件名一致
|
|
```js
|
export class PIndex extends Pilot {}
|
```
|
|
#### 组件文件
|
|
不论是公共组件还是页面子组件(.vue、.scss),都以固定前缀 C 开头,再接大驼峰
|
|
```
|
CMenu.vue
|
CMenu.scss
|
```
|
|
组件代码定义的名称,需要和文件名一致
|
|
```js
|
// CMenu.vue 的组件名,必须是 CMenu
|
export default {
|
name: 'CMenu',
|
}
|
```
|
|
#### 请求文件
|
|
请求层文件(.js),以固定前缀 F 开头,再接大驼峰
|
|
```
|
FCommon.js
|
```
|
|
请求集合的代码定义名称,需要和文件名一致
|
|
```js
|
// FCommon.js 的类名称,必须是 FCommon
|
class FCommon extends Fetcher {}
|
|
// FCommon.js 代表的类的实例名称,则是 $fetchCommon
|
export const $fetchCommon = new FCommon();
|
```
|
|
## 常见书写要求
|
|
### 基础书写要求
|
|
例如:
|
- 使用四个空格代替 tab 进行缩进(包括代码和文档)
|
- 单行代码宽度最多100个字符
|
- js 代码使用单引号
|
|
更多规则请参考根目录 `.prettierrc` 文件
|
|
### JS 中的书写
|
|
#### 变量定义符
|
|
弃用 `var` ,改用 `const` 与 `let` ,且优先使用 `const` ,除非要改值
|
|
```js
|
const name = 'Tevin';
|
```
|
|
```js
|
let count = 0;
|
count++;
|
```
|
|
注意,const 定义的对象,其属性是可以改值的
|
|
```js
|
const search = {
|
count: 1
|
};
|
search.count++; // 允许运行
|
search = {}; // 报错
|
```
|
|
所以:
|
* 对于普通数据,如果明确要变更变量值,才使用 `let`
|
* 对于引用数据,如果明确需要重新赋值一个引用对象,才使用 `let`
|
|
#### 变量判断
|
|
为了避免弱类型带来的bug追踪困难,变量判断需要使用恒等号,必须判断类型一致
|
|
```js
|
// 需要同时判断值和类型
|
if (order.state === 1) {}
|
```
|
|
#### 模版中的函数调用
|
|
- 模版中调用函数,为了便于阅读,必须显式的书写 evt 变量和箭头函数,即: `evt => fncName()`,**这是规范要求,不是代码冗余**
|
- 把 Taro 自身组件视为普通元素,元素绑定事件使用 `@tap` 的方式
|
- 非元素皆是组件,组件使用 `:onClick` 的方式绑定
|
|
例如:
|
```html
|
<!-- 元素绑定事件使用 -->
|
<view @tap="() => onOpenOrderDetail()"></view>
|
<!-- 组件绑定事件使用 -->
|
<CMenu :onItemClick="evt => onMenuItemClick(evt)" />
|
```
|
|
#### 以 JSDoc 格式写方法注释
|
|
公共代码中的方法都需要以 JSDoc 的格式写注释
|
|
```js
|
export class Tools {
|
/**
|
* 显示消息提示框
|
* @param {string} msg - 提示的消息内容
|
* @param {number} [duration=2000] - 提示框显示时长(毫秒)
|
* @param {boolean} [mask=false] - 是否显示透明蒙层,防止触摸穿透
|
*/
|
static toast(msg, duration = 2000, mask = false) {
|
}
|
}
|
```
|
|
### CSS 属性顺序
|
|
为了避免 css 属性写重复,请按如下顺序书写:
|
|
* **文档流属性**
|
display, position, float, clear, visibility, table-layout 等
|
|
* **大小属性**
|
width, height, margin, padding 等
|
|
* **文字排版属性**
|
font, line-height, text-align, text-indent, vertical-align 等
|
|
* **装饰性属性**
|
color, background, border, opacity, shadow, cursor 等
|
|
* **生成内容属性**
|
content, list-style, quotes 等
|
|
* **二次渲染属性**
|
zoom, transform 等
|
|
* **动画属性**
|
transition, animation 等
|