共计 3103 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点:新手常踩的三大坑
最近帮几个朋友排查小程序问题,发现新手常在这些地方翻车:

- 开发环境配置
- 微信开发者工具突然报错,需要清除缓存重装
-
npm 包安装后构建失败,版本冲突频繁
-
API 调用混乱
- wx.login 拿到 code 后不知道要传给后端
-
获取用户信息时没处理拒绝授权的情况
-
调试困难
- 真机预览时样式错乱
- 安卓机上页面卡顿找不到原因
框架选型:别急着写代码
先看看主流方案对比:
| 方案 | 优势 | 劣势 |
|---|---|---|
| 原生开发 | 官方支持好,性能最优 | 多端需重复开发 |
| Taro | React 语法,生态丰富 | 复杂项目编译略慢 |
| uni-app | 跨端能力强,文档完善 | 自定义组件略繁琐 |
决策建议 :
– 只要做微信小程序 → 选原生
– 需要兼容 H5/APP → uni-app
– 团队熟悉 React → Taro
核心实现:这些代码要背下来
Page 生命周期管理
// 用 TS 定义页面数据类型
interface IData {list: any[]
loading: boolean
}
Page<IData>({
data: {list: [],
loading: true
},
async onLoad() {
// 异步数据处理示例
try {const res = await this.fetchData()
this.setData({
list: res.data,
loading: false
})
} catch (error) {console.error('数据加载失败', error)
}
},
fetchData(): Promise<any> {return new Promise((resolve) => {
wx.request({
url: 'https://api.example.com/list',
success: resolve
})
})
}
})
请求封装实战
class ApiClient {
private static instance: ApiClient
private retryCount = 0
static getInstance() {if (!ApiClient.instance) {ApiClient.instance = new ApiClient()
}
return ApiClient.instance
}
/**
* 带 Token 刷新的请求封装
* @param options 请求参数
* @param maxRetry 最大重试次数
*/
async request(options: WechatMiniprogram.RequestOption, maxRetry = 3) {
// 先从缓存获取 token
let token = wx.getStorageSync('token')
return new Promise((resolve, reject) => {
const finalOptions = {
...options,
header: {'Authorization': `Bearer ${token}`,
...options.header
}
}
wx.request({
...finalOptions,
success: (res) => {if (res.statusCode === 401) {this.refreshToken().then(() => {
this.retryCount++
if (this.retryCount <= maxRetry) {return this.request(options, maxRetry)
}
reject(new Error('授权失败'))
})
} else {resolve(res.data)
}
},
fail: reject
})
})
}
}
性能优化:让你的小程序飞起来
图片懒加载实战
在 page.json 中配置:
{
"usingComponents": {"lazy-image": "/components/lazy-image"}
}
组件实现:
Component({
properties: {
src: String,
placeholder: {
type: String,
value: '/assets/placeholder.png'
}
},
data: {loaded: false},
observers: {'src': function(src) {if (!src) return
const observer = wx.createIntersectionObserver(this)
observer.relativeToViewport({bottom: 300}).observe('.image', (res) => {if (res.intersectionRatio > 0 && !this.data.loaded) {this.setData({ loaded: true})
observer.disconnect()}
})
}
}
})
setData 优化策略
错误示范:
// 频繁触发渲染
this.setData({a: 1})
this.setData({b: 2})
this.setData({c: 3})
正确做法:
// 合并更新
this.setData({
a: 1,
b: 2,
c: 3
})
原理 :小程序底层会对 setData 做 diff 计算,合并操作能减少通信次数。
避坑指南:血泪经验总结
处理用户拒绝授权
// 获取用户信息的安全写法
function getUserProfile() {return new Promise((resolve) => {
wx.getUserProfile({
desc: '用于完善会员资料',
success: resolve,
fail: () => {
wx.showToast({
title: '授权后可获得完整功能',
icon: 'none'
})
// 降级方案:使用默认头像
resolve({
userInfo: {avatarUrl: '/assets/default-avatar.png'}
})
}
})
})
}
样式兼容技巧
/* 安卓按钮默认有灰色背景 */
button::after {display: none;}
/* iOS 滚动更流畅 */
scroll-view {-webkit-overflow-scrolling: touch;}
代码规范:专业团队的秘密
ESLint 配置示例
module.exports = {
env: {
browser: true,
es6: true
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'no-unused-vars': 'warn'
}
}
单元测试示例
// 测试自定义组件
import {mount} from '@vue/test-utils'
import MyComponent from '@/components/my-component.vue'
describe('MyComponent', () => {it('渲染带 props 的组件', () => {
const wrapper = mount(MyComponent, {
propsData: {title: '测试标题'}
})
expect(wrapper.text()).toContain('测试标题')
})
})
延伸思考
试着实现这些进阶需求:
1. 如何让图片组件支持 WebP 自动降级?
2. 设计一个全局错误监控系统
3. 实现页面预加载策略
完整 Demo 已放在 GitHub: 小程序实战 Demo 仓库 (包含所有示例代码)
刚开始可能会觉得配置繁琐,但坚持规范后会发现后期维护效率大幅提升。遇到问题多看官方文档,善用开发者工具的调试功能,祝你少走弯路!
正文完
