Files
Neo-ZQYY/_DEL/wechat-miniprogram/steering/best-practices.md
2026-03-15 10:15:02 +08:00

305 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发最佳实践与常见坑
> 综合官方文档与社区经验
## setData 性能优化
setData 是小程序性能的关键瓶颈因为数据需要从逻辑层JS 线程)序列化后传输到视图层(渲染线程)。
### 原则
1. **减少数据量**:只传需要更新的字段
```javascript
// ❌ 错误:传整个列表
this.setData({ list: this.data.list })
// ✅ 正确:只更新变化的项
this.setData({ 'list[2].name': 'new name' })
```
2. **减少调用频率**:合并多次 setData
```javascript
// ❌ 错误:多次调用
this.setData({ a: 1 })
this.setData({ b: 2 })
this.setData({ c: 3 })
// ✅ 正确:合并为一次
this.setData({ a: 1, b: 2, c: 3 })
```
3. **后台页面不要 setData**
```javascript
// ❌ 错误:页面隐藏后仍在 setData如定时器
onShow() {
this._timer = setInterval(() => {
this.setData({ time: Date.now() })
}, 1000)
},
// ✅ 正确:页面隐藏时停止
onHide() {
clearInterval(this._timer)
}
```
4. **避免在 onPageScroll 中 setData**
```javascript
// ❌ 错误
onPageScroll(e) {
this.setData({ scrollTop: e.scrollTop })
}
// ✅ 正确:用 WXS 响应事件或节流
onPageScroll: throttle(function(e) {
if (this._needUpdate) {
this.setData({ isTop: e.scrollTop < 100 })
}
}, 100)
```
5. **大列表用纯数据字段**
```javascript
Component({
options: { pureDataPattern: /^_/ },
data: {
displayList: [], // 用于渲染
_rawList: [] // 纯数据,不传输到视图层
}
})
```
## 分包加载
### 基本分包
```json
// app.json
{
"pages": [
"pages/index/index",
"pages/logs/logs"
],
"subpackages": [
{
"root": "packageA",
"name": "pack-a",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root": "packageB",
"name": "pack-b",
"pages": [
"pages/apple/apple"
]
}
]
}
```
**限制**
- 整个小程序所有分包大小不超过 20MB使用分包时
- 单个分包/主包大小不超过 2MB
- tabBar 页面必须在主包
### 独立分包
不依赖主包即可运行,适合独立功能页面(如活动页)。
```json
{
"subpackages": [
{
"root": "packageIndependent",
"pages": ["pages/activity/activity"],
"independent": true
}
]
}
```
**注意**独立分包中不能使用主包的公共资源js/组件/样式)。
### 分包预下载
```json
{
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["packageA"]
},
"pages/logs/logs": {
"network": "wifi",
"packages": ["packageB"]
}
}
}
```
## 小程序与 H5 的关键差异
| 特性 | H5 | 小程序 |
|------|-----|--------|
| DOM 操作 | 支持 document/window | ❌ 不支持 |
| BOM | 支持 | ❌ 不支持 |
| 路由 | URL hash/history | 页面栈(最多 10 层) |
| 样式 | 完整 CSS | WXSS部分 CSS 不支持) |
| 脚本 | 完整 JS + Web API | JS无 DOM API |
| 渲染 | 单线程 | 双线程(逻辑层 + 视图层) |
| 网络请求 | fetch/XMLHttpRequest | wx.request需配置域名 |
| 本地存储 | localStorage | wx.setStorage10MB |
| Cookie | 支持 | ❌ 不支持(需自行管理) |
| 动态创建元素 | 支持 | ❌ 不支持 |
| eval / new Function | 支持 | ❌ 不支持 |
| SVG | 支持 | 部分支持image src 可用) |
### 常见迁移坑
1. **没有 Cookie**:登录态需要自行通过 header 传递 token
2. **没有 DOM**:不能用 jQuery、不能 `document.getElementById`
3. **不支持动态执行代码**`eval()``new Function()` 都不可用
4. **样式差异**
- 不支持 `*` 通配符选择器
- 不支持 `>` `+` `~` 等关系选择器(部分版本已支持)
- 不支持 `@media` 的部分写法
- 不支持 `position: fixed` 在某些场景下的表现
5. **页面栈限制**:最多 10 层,超过后 navigateTo 会失败
6. **包大小限制**:主包 2MB总包 20MB
7. **网络请求域名白名单**:必须在管理后台配置
8. **不支持 npm 直接引入**:需要通过开发者工具构建 npm
## TypeScript 支持
小程序原生支持 TypeScript
```json
// tsconfig.json项目根目录
{
"compilerOptions": {
"strict": true,
"target": "ES2017",
"module": "ESNext",
"moduleResolution": "Node",
"lib": ["ES2017"],
"typeRoots": ["./typings"]
},
"include": ["**/*.ts"],
"exclude": ["node_modules"]
}
```
```typescript
// 页面 .ts 文件
Page({
data: {
msg: 'Hello' as string,
list: [] as Array<{ id: number; name: string }>
},
onLoad(options: Record<string, string | undefined>) {
const id = options.id
}
})
// 组件 .ts 文件
Component({
properties: {
title: { type: String, value: '' }
},
data: {
count: 0 as number
},
methods: {
increment() {
this.setData({ count: this.data.count + 1 })
}
}
})
```
## npm 支持
1. 在小程序根目录执行 `npm install`
2. 在开发者工具中:工具 → 构建 npm
3. 构建后会生成 `miniprogram_npm` 目录
4. 使用:`const dayjs = require('dayjs')`
**注意**
- 不是所有 npm 包都能在小程序中使用(不能依赖 Node.js 内置模块或浏览器 API
- 每次 `npm install` 后都需要重新构建 npm
## 自定义 tabBar
```json
// app.json
{
"tabBar": {
"custom": true,
"list": [
{ "pagePath": "pages/index/index", "text": "首页" },
{ "pagePath": "pages/mine/mine", "text": "我的" }
]
}
}
```
在根目录创建 `custom-tab-bar/` 组件:
```
custom-tab-bar/
├── index.js
├── index.json
├── index.wxml
└── index.wxss
```
## 骨架屏
开发者工具支持自动生成骨架屏:
1. 在模拟器中预览页面
2. 点击模拟器右下角「...」→「生成骨架屏」
3. 会自动生成 `页面名.skeleton.wxml``页面名.skeleton.wxss`
```json
// 页面 json 中引用
{
"initialRenderingCache": "static"
}
```
## 常见审核被拒原因
1. **功能不完整**:提交审核时确保所有功能可用
2. **测试账号未提供**:需要登录的小程序必须提供测试账号
3. **类目不符**:选择的服务类目与实际功能不匹配
4. **诱导分享/关注**:不能强制用户分享或关注公众号才能使用
5. **虚拟支付**iOS 不允许虚拟商品使用微信支付(需走 IAP
6. **内容违规**UGC 内容需要内容安全检测
7. **隐私协议**:需要配置隐私保护指引
8. **授权滥用**:不能在首页就弹出授权请求,需要在使用时才请求
## 调试技巧
```javascript
// 真机调试日志
const log = wx.getRealtimeLogManager()
log.info('info message')
log.warn('warn message')
log.error('error message')
// 性能监控
const performance = wx.getPerformance()
const observer = performance.createObserver((entryList) => {
console.log(entryList.getEntries())
})
observer.observe({ entryTypes: ['render', 'script', 'navigation'] })
```
## 在线查询
- 性能优化https://developers.weixin.qq.com/miniprogram/dev/framework/performance/tips.html
- 分包加载https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html
- npm 支持https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html
- 自定义 tabBarhttps://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html