前言:接下来会开启一个小程序最佳实践的知识小册,从小程序作为切入点,但绝不限于此。将涵盖几大篇章『命名篇』、『单测篇』、『代码风格篇』、『注释篇』、『安全生产篇』、『重构篇』、『代码设计篇』、『性能篇』、『国际化篇』和『Why 小程序开发最佳实践』。每一篇都会包含正面和反面示例以及详细的解释。
文中示例都是在 CR 过程中发现的一些典型的问题。希望大家能通过该知识小册提前规避此类问题,让我们的 CR 关注点更多聚焦在业务逻辑而非此类琐碎或基本理念的缺失上而最终形成高质量的 CR。
代码风格篇 💅🏻
代码风格至关重要,可以从视觉上将重点突出,改动不大但收益颇丰,可显著提升可读性。本文在基于已有的团队 eslint 之上,着重关注那些无法使用 lint 规范或需要重点关注的风格。
分块
逻辑不相干的代码应该用空行分开。让代码逻辑的解耦在视觉上也能显示体现出来:此处是一块,删除这一块不会影响前面一块,两块可独立理解,互不耦合,甚至后续重构独自抽离成函数都是 OK 的。其次 Vim 模式下,按 { 或 } 可分块移动,方便快速浏览代码逻辑较紧密的块。
💡 Tips: 符合原则『好的代码是易于删除的代码』。
推荐分块或分组规则:
- import(三方模块和本地模块亦可分组)
- 变量申明(const let 亦可分组)
- if while for 等 control flow
- return。因为 return 是影响代码执行和理解代码至关重要的关键字,通过空行可将其凸显
- 注释之前需加空行,注释和被注释的代码无需空行
- 不同功能块
- view 中组件与组件之间需分行
- css 中一整块样式与另一整块样式之间需分行
- 等等更多,欢迎补充
可通过 .eslintrc.js 强制团队成员执行。
{
rules: {
'padding-line-between-statements': [
'error',
{ blankLine: 'always', prev: '*', next: 'return' },
{ blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
{ blankLine: 'any', prev: ['const', 'let', 'var'], next: ['const', 'let', 'var'] },
{
blankLine: 'always',
prev: ['function', 'if', 'for', 'while', 'case', 'default', 'try', 'throw', 'class', 'do'],
next: '*',
},
{
blankLine: 'always',
prev: '*',
next: ['function', 'if', 'for', 'while', 'case', 'default', 'try', 'throw', 'class', 'do'],
},
],
},
};
Bad
三处处理不同问题的代码杂糅在一起。
function jump() {
spm.click(withdrawResultSpms.viewBill.click);
openPage(WITHDRAW_BILL_LIST_URL);
remoteConsole.info({ msg: 'go_billList', url: WITHDRAW_BILL_LIST_URL });
},
Good
埋点、跳转、打印流水日志逻辑分三块后更清晰。
function jump() {
spm.click(withdrawResultSpms.viewBill.click);
openPage(WITHDRAW_BILL_LIST_URL);
remoteConsole.info({ msg: 'go_billList', url: WITHDRAW_BILL_LIST_URL });
}
Good
变量申明、使用、日志上报视觉上的分开也让逻辑更清晰 👍
onRenderSuccess(res) {
const { detail } = res || {};
const height = detail.height || 0;
this.setData({ showCdpBanner: !!height });
rc.info({
msg: 'onRenderSuccess cdp spaceCode: XYZ',
response: res,
});
}
axml
属性分行
建议三个属性以上分行。好处是以后单独修改或添加某个属性 git diff 只会显示修改的一行,CR 时噪音更少。
属性顺序
html 属性参考业界属性顺序即可。axml 特有属性顺序规则如下:
1. 条件判断指令放首位
查看 axml 文件时,条件判断(a:if、a:else)须放到醒目位置,更直观,否则会增加阅读成本。
Bad
<view>
<view
data="{{ ... }}"
...
a:if="{{ visible }}"
onTap="onTap">
...
</view>
<view
data="{{ ... }}"
a:else
onTap="onTap">
...
</view>
</view>
在阅读代码时,可能看了很久才发现当前分析的元素在业务场景下是不展示
Good
直接跟在标签名下,是否展示的逻辑一目了然
<view>
<view
a:if="{{ visible }}"
data="{{ ... }}"
onTap="onTap"
>
...
</view>
<view
a:else
data="{{ ... }}"
onTap="onTap"
>
...
</view>
</view>