305 lines
7.3 KiB
Markdown
305 lines
7.3 KiB
Markdown
# 开发最佳实践与常见坑
|
||
|
||
> 综合官方文档与社区经验
|
||
|
||
## 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.setStorage(10MB) |
|
||
| 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
|
||
- 自定义 tabBar:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html
|