WebApp【公共组件库】@前端(For Git Submodule)
Tevin
2025-03-24 5ea25b0da2dd63f88e4cb277028b4a0f10a478d5
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
---
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 等