Appearance
小程序端
本篇以微信小程序为主要参考,其他平台小程序(支付宝、百度、抖音等)可参考相应平台文档
技术选型
小程序开发主要有以下几种方式:
- 原生开发:使用微信官方提供的开发工具和 API,适合简单项目
- uni-app:跨平台方案,一套代码多端运行,详见 uni-app 规范
- Taro:京东开源的跨端框架,支持 React/Vue 语法开发小程序
- mpvue / WePY:早期方案,已逐渐不推荐使用
推荐
团队统一使用 uni-app 进行跨端小程序开发,除非有特殊需求需要原生开发
项目目录结构
以微信原生小程序为例,推荐目录结构如下:
├── components 公共组件
│ └── comp-name
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── pages 页面文件
│ └── index
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── styles 公共样式
│ ├── reset.wxss
│ └── global.wxss
├── utils 工具类
│ ├── request.js 请求封装
│ ├── util.js 通用工具
│ └── auth.js 登录鉴权
├── api 接口管理
│ └── 业务模块.js
├── config 配置文件
│ └── index.js
├── static 静态资源
│ └── images
├── app.js 小程序入口文件
├── app.json 小程序全局配置
├── app.wxss 全局样式
├── project.config.json 项目配置文件
└── sitemap.json 小程序索引配置页面与组件规范
页面规范
- 每个页面放在
pages目录下独立文件夹中,文件夹以页面功能命名 - 页面路径使用小写字母和连字符,如
pages/user-center/index - 页面文件包含
.js、.json、.wxml、.wxss四个文件,统一命名为index
组件规范
- 公共组件放在
components目录下,业务组件放在对应页面目录下 - 组件命名采用小写字母和连字符,如
search-bar - 组件需要在
json文件中声明"component": true
json
{
"component": true,
"usingComponents": {}
}WXML 模板规范
- 缩进:使用 2 个空格缩进
- 属性顺序:
class>id>wx:if/wx:for> 数据绑定属性 > 事件绑定 - 列表渲染:
wx:for必须添加wx:key
html
<!-- 推荐 -->
<view class="user-list" wx:for="{{userList}}" wx:key="id">
<text class="user-name">{{item.name}}</text>
</view>
<!-- 不推荐 -->
<view wx:for="{{userList}}" class="user-list">
<text>{{item.name}}</text>
</view>- 条件渲染:频繁切换使用
hidden,不频繁切换使用wx:if
html
<!-- 频繁切换 -->
<view hidden="{{!isShow}}">频繁切换的内容</view>
<!-- 不频繁切换 -->
<view wx:if="{{isLogin}}">已登录内容</view>
<view wx:else>未登录内容</view>WXSS 样式规范
- 使用
rpx作为布局单位,适配不同屏幕(750rpx = 设计稿宽度) - 避免使用 ID 选择器和标签选择器,统一使用 class 选择器
- 全局样式放在
app.wxss,页面样式使用 scoped(小程序天然隔离) - 公共样式抽离到
styles目录,通过@import引入
css
/* styles/global.wxss */
.container {
padding: 20rpx 30rpx;
box-sizing: border-box;
}
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}css
/* 页面中引入 */
@import "../../styles/global.wxss";JS 逻辑规范
请求封装
统一封装网络请求,便于统一管理 baseURL、请求拦截、响应处理和错误处理:
js
// utils/request.js
const BASE_URL = "https://api.example.com";
const request = (options) => {
return new Promise((resolve, reject) => {
const token = wx.getStorageSync("token");
wx.request({
url: BASE_URL + options.url,
method: options.method || "GET",
data: options.data || {},
header: {
"Content-Type": "application/json",
Authorization: token ? `Bearer ${token}` : "",
...options.header,
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else if (res.statusCode === 401) {
// token 过期,跳转登录
wx.navigateTo({ url: "/pages/login/index" });
reject(res);
} else {
wx.showToast({ title: "请求失败", icon: "none" });
reject(res);
}
},
fail: (err) => {
wx.showToast({ title: "网络异常", icon: "none" });
reject(err);
},
});
});
};
module.exports = { request };数据管理
- 页面数据使用
data存储,通过setData更新 - 避免频繁调用
setData,合并数据更新 - 全局数据使用
app.globalData或状态管理库
js
// 推荐:合并 setData
this.setData({
userInfo: res.userInfo,
isLogin: true,
});
// 不推荐:多次 setData
this.setData({ userInfo: res.userInfo });
this.setData({ isLogin: true });性能优化
图片优化:
- 使用网络图片代替本地图片,减少包体积
- 图片懒加载:
<image lazy-load /> - 使用合适的图片尺寸和格式(WebP 优先)
分包加载:
- 将非首屏页面放入分包,减少主包体积
- 主包体积不超过 2MB,总包不超过 20MB
json
{
"pages": ["pages/index/index", "pages/user/index"],
"subPackages": [
{
"root": "packageA",
"pages": ["pages/detail/index", "pages/list/index"]
}
]
}- 数据预拉取:利用
onLoad生命周期提前请求数据 - 骨架屏:使用骨架屏提升用户加载体验
- 避免不当使用
setData:- 不传输大量数据
- 不频繁调用
- 只更新变化的字段
发布与审核
- 版本管理:遵循语义化版本号(SemVer),如
1.0.0 - 体验版:提交前先发布体验版,团队内部充分测试
- 审核要点:
- 确保无违规内容和功能
- 检查隐私协议和用户授权流程
- 测试各场景下的异常处理
- 灰度发布:利用平台灰度发布功能,逐步放量
