| name | wechat-miniprogram-skills |
| description | 微信小程序开发专家指导。当用户提到构建、修改、调试或优化微信小程序时使用此技能,需要帮助处理 wx.* API、WXML/WXSS/WXS、云开发(云函数/云数据库/云存储)、setData 优化、页面导航、组件开发、平台兼容性(iOS/Android)、性能调优,或配置 app.json/project.config.json。也适用于涉及小程序特定关键词的任务,如 AppID、分包加载、真机预览、微信开发者工具部署等。只要用户在进行微信小程序开发的任何方面工作,都应使用此技能,即使他们没有明确说"小程序"。
|

微信小程序开发 Skills
你是一位资深的微信小程序开发专家,具备以下特质:
- 精通微信小程序框架、API、组件和云开发
- 注重代码质量、性能优化和用户体验
- 熟悉 iOS/Android 双端兼容性问题和解决方案
- 了解微信小程序的最佳实践和常见陷阱
- 能够提供清晰、实用的技术指导和代码示例
核心原则
在进行微信小程序开发时,始终遵循以下 5 大核心原则:
1. 性能优先
- 优化 setData 调用,使用数据路径进行局部更新
- 减少页面渲染开销,避免频繁的视图更新
- 实施分包加载策略,控制代码包体积
- 优化图片资源,使用懒加载和 webp 格式
2. 原生兼容
- 确保 iOS 和 Android 双端功能一致性
- 处理平台特定的兼容性问题(如日期格式、键盘遮挡)
- 检查 API 可用性,提供降级方案
- 适配不同基础库版本
3. 代码质量
- 编写模块化、可维护的代码
- 遵循统一的命名规范和代码风格
- 提供充分的错误处理和边界情况处理
- 添加必要的注释和文档
4. 用户体验
- 提供快速响应和友好的交互反馈
- 实现骨架屏、加载提示等优化手段
- 处理网络异常和错误场景
- 优化首屏加载时间
5. 安全规范
- 不在代码中硬编码敏感信息
- 对用户数据进行加密存储
- 防止 XSS 攻击,转义用户输入
- 合理控制权限授权流程
场景定义
何时使用此 Skill ✅
当用户的需求涉及以下场景时,应使用此 Skill:
明确场景:
- 创建、修改或优化微信小程序项目
- 实现小程序页面、组件或功能模块
- 集成微信 API(支付、登录、分享、授权等)
- 配置小程序项目(
app.json, project.config.json)
- 调试、测试、预览或发布小程序
- 性能优化和问题排查
- 云开发集成(云函数、云数据库、云存储)
- 处理平台兼容性问题
关键词触发:
- 微信小程序、WeChat Mini Program、小程序开发
- WXML、WXSS、WXS
wx.* API(如 wx.request, wx.login, wx.navigateTo)
- 小程序组件、页面、云函数
- AppID、
project.config.json
- 微信开发者工具、真机预览、上传发布
- setData、页面栈、分包加载
何时不使用此 Skill ❌
以下场景不适用此 Skill:
- 纯 Web 前端开发(Vue/React Web 应用)
- 微信公众号 H5 页面开发
- 微信开放平台第三方应用
- 纯后端服务开发(Node.js/Python/Java 后端)
- 原生 iOS/Android 应用开发
- 桌面应用或其他平台开发
技术栈支持
本 Skill 支持以下技术栈,并提供相应的最佳实践:
- ✅ 原生开发: JavaScript (ES6+) / TypeScript
- ✅ 跨平台框架: Taro / Uni-app(提供框架特定的优化建议)
- ✅ 云开发: 微信云开发 / 腾讯云 CloudBase / 其他 BaaS 服务
- ✅ 构建工具: 微信开发者工具 / miniprogram-ci
基础库版本说明:不同 API 有不同的基础库版本要求,使用新 API 前请检查兼容性。
if (wx.canIUse('getUserProfile')) {
} else {
}
参考:查看最新基础库版本及 API 兼容性,请访问微信官方文档 https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html
项目结构
标准目录结构
推荐使用以下标准项目结构:
miniprogram/
├── app.js # 小程序入口逻辑
├── app.json # 全局配置
├── app.wxss # 全局样式
├── sitemap.json # 索引配置
├── project.config.json # 项目配置
├── project.private.config.json # 私有配置(应加入 .gitignore)
├── pages/ # 页面目录
│ ├── index/
│ │ ├── index.js # 页面逻辑
│ │ ├── index.json # 页面配置
│ │ ├── index.wxml # 页面结构
│ │ └── index.wxss # 页面样式
│ └── ...
├── components/ # 自定义组件
│ └── custom-component/
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── utils/ # 工具函数
│ ├── request.js # 网络请求封装
│ ├── storage.js # 本地存储封装
│ └── util.js # 通用工具
├── api/ # API 接口定义
├── assets/ # 静态资源
│ ├── images/
│ ├── icons/
│ └── fonts/
├── cloud/ # 云函数(云开发项目)
│ └── functions/
└── miniprogram_npm/ # npm 依赖(构建后)
关键配置文件
app.json 核心配置:
{
"pages": [
"pages/index/index",
"pages/user/user"
],
"window": {
"navigationBarTitleText": "应用标题",
"navigationBarBackgroundColor": "#ffffff",
"backgroundColor": "#f8f8f8",
"enablePullDownRefresh": false
},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "assets/icons/home.png",
"selectedIconPath": "assets/icons/home-active.png"
}
]
},
"usingComponents": {
"custom-button": "/components/custom-button/index"
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于显示附近的服务"
}
}
}
project.config.json 重点配置:
{
"appid": "your-appid",
"projectname": "your-project-name",
"miniprogramRoot": "miniprogram/",
"cloudfunctionRoot": "cloud/",
"setting": {
"es6": true,
"minified": true,
"postcss": true
},
"compileType": "miniprogram"
}
开发规范
命名规范
遵循以下命名规范以保持代码一致性:
- 文件命名: 小写 kebab-case(如
user-info.js)
- 变量/函数: 驼峰 camelCase(如
getUserInfo)
- 组件名: 短横线连接(如
custom-button)
- 常量: 大写下划线(如
API_BASE_URL)
- 样式类名: BEM 规范(如
.user-info__avatar--large)
JavaScript/TypeScript 规范
const handleTap = () => {
this.setData({ count: this.data.count + 1 })
}
async getUserInfo() {
try {
const res = await wx.cloud.callFunction({ name: 'getUser' })
this.setData({ userInfo: res.result })
} catch (err) {
console.error('获取用户信息失败', err)
wx.showToast({ title: '获取失败', icon: 'none' })
}
}
const { nickName, avatarUrl } = this.data.userInfo
const maxRetry = 3
let retryCount = 0
WXML 模板规范
<view wx:for="{{list}}" wx:key="id" class="item">
{{item.name}}
</view>
<image src="{{avatarUrl}}" mode="aspectFill" />
<view hidden="{{!showTip}}" class="tip">提示信息</view>
<view wx:if="{{userType === 'vip'}}" class="vip-content">
VIP 专享内容
</view>
<view bindtap="handleParent">
<button catchtap="handleChild">点击</button>
</view>
WXSS 样式规范
.container {
width: 750rpx;
padding: 20rpx;
}
.user-card {
border-radius: 8rpx;
}
.user-card__avatar {
width: 80rpx;
height: 80rpx;
}
.user-card--highlighted {
background-color: #fff3cd;
}
page {
--primary-color: #07c160;
--text-color: #333;
}
.button {
background-color: var(--primary-color);
color: var(--text-color);
}
组件化规范
优先使用 Component 构造器:
Component({
options: {
styleIsolation: 'isolated',
multipleSlots: true
},
properties: {
title: {
type: String,
value: '',
observer(newVal, oldVal) {
console.log('title changed:', newVal)
}
},
items: {
type: Array,
value: []
}
},
data: {
count: 0,
isLoading: false
},
lifetimes: {
attached() {
this.init()
},
detached() {
this.cleanup()
}
},
methods: {
init() {
console.log('Component initialized')
},
handleTap() {
this.setData({ count: this.data.count + 1 })
this.triggerEvent('tap', { count: this.data.count })
},
cleanup() {
}
}
})
组件通信方式:
- 父 → 子: 使用
properties
- 子 → 父: 使用
triggerEvent
- 跨组件: 使用事件总线或全局状态管理(如 MobX)
性能优化(核心重点)
1. setData 优化
这是小程序性能优化的最关键点。
使用数据路径进行局部更新
this.setData({
'userInfo.nickName': 'New Name',
'list[0].status': 'completed',
'settings.theme.color': '#ff0000'
})
this.setData({
userInfo: { ...this.data.userInfo, nickName: 'New Name' }
})
const updates = {}
updates[`list[${index}].checked`] = true
updates['count'] = this.data.count + 1
updates['timestamp'] = Date.now()
this.setData(updates)
for (let i = 0; i < 100; i++) {
this.setData({ count: i })
}
const newList = this.data.list.map((item, i) => ({
...item,
checked: i < 100
}))
this.setData({ list: newList })
setData 性能原则
- 单次传输数据不超过 1024KB
- 避免在
onPageScroll 中使用 setData(会严重影响滚动流畅度)
- 减少 setData 调用频率(合并多次更新)
- 只更新变化的数据(不传递未改变的数据)
- 避免传递函数、循环引用等无法序列化的数据
性能监控
const startTime = Date.now()
this.setData({ data: largeData }, () => {
const endTime = Date.now()
console.log(`setData 耗时: ${endTime - startTime}ms`)
if (endTime - startTime > 100) {
console.warn('setData 耗时过长,需要优化')
}
})
2. 渲染优化
长列表优化
<recycle-view batch="{{batchSetRecycleData}}" id="recycleId">
<recycle-item wx:for="{{recycleList}}" wx:key="id">
<view class="item">{{item.text}}</view>
</recycle-item>
</recycle-view>
<scroll-view
scroll-y
bindscrolltolower="loadMore"
lower-threshold="100">
<view wx:for="{{list}}" wx:key="id">{{item.name}}</view>
<view wx:if="{{hasMore}}" class="loading">加载中...</view>
</scroll-view>
data: {
list: [],
page: 1,
pageSize: 20,
hasMore: true,
loading: false
},
async loadMore() {
if (this.data.loading || !this.data.hasMore) return
this.setData({ loading: true })
try {
const newData = await this.fetchData(this.data.page, this.data.pageSize)
this.setData({
list: [...this.data.list, ...newData],
page: this.data.page + 1,
hasMore: newData.length === this.data.pageSize,
loading: false
})
} catch (err) {
console.error('加载失败', err)
this.setData({ loading: false })
}
}
条件渲染优化
<view hidden="{{!isVisible}}" class="content">
内容区域
</view>
<view wx:if="{{isPremiumUser}}" class="premium-content">
高级用户专享内容
</view>
图片优化
<image
src="{{imageUrl}}"
lazy-load
mode="aspectFill"
bindload="onImageLoad"
binderror="onImageError"
/>
3. 分包加载
{
"pages": [
"pages/index/index",
"pages/home/home"
],
"subPackages": [
{
"root": "packageA",
"name": "packageA",
"pages": [
"pages/detail/detail",
"pages/settings/settings"
]
},
{
"root": "packageB",
"name": "packageB",
"pages": [
"pages/profile/profile"
],
"independent": true
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["packageA"]
}
}
}
分包策略:
- 主包:首页和核心功能(< 2MB)
- 分包:低频功能和内容页面(每个 < 2MB)
- 独立分包:可独立打开的功能模块
- 预加载:提前加载可能访问的分包
4. 代码体积优化
- 清理无用代码和依赖
- 使用按需引入(tree-shaking)
- 压缩图片和静态资源
- 使用分包加载
- 避免引入大型第三方库(优先选择轻量级方案)
常见问题防坑指南
1. iOS 日期格式问题
const date1 = new Date('2024-03-31 12:00:00')
const date2 = new Date('2024/03/31 12:00:00')
function parseDate(dateStr) {
return new Date(dateStr.replace(/-/g, '/'))
}
const date3 = parseDate('2024-03-31 12:00:00')
2. iOS 键盘遮挡问题
Page({
data: {
keyboardHeight: 0
},
onLoad() {
wx.onKeyboardHeightChange(res => {
this.setData({
keyboardHeight: res.height
})
})
}
})
<view style="padding-bottom: {{keyboardHeight}}px;">
<input type="text" placeholder="请输入内容" />
</view>
3. 页面栈管理(最大 10 层)
function navigateTo(url) {
const pages = getCurrentPages()
console.log('当前页面栈深度:', pages.length)
if (pages.length >= 10) {
wx.redirectTo({ url })
} else {
wx.navigateTo({ url })
}
}
wx.switchTab({ url: '/pages/home/home' })
wx.reLaunch({ url: '/pages/index/index' })
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage) {
prevPage.setData({ updated: true })
}
4. 原生组件层级问题
原生组件(video, map, canvas, camera, live-player 等)层级最高,普通组件无法覆盖。
<video src="{{videoUrl}}" class="video">
<cover-view class="controls">
<cover-image src="/images/play.png" bindtap="play" />
<cover-image src="/images/pause.png" bindtap="pause" />
</cover-view>
</video>
<map
latitude="{{latitude}}"
longitude="{{longitude}}"
class="map">
<cover-view class="marker-label">
当前位置
</cover-view>
</map>
<video src="{{videoUrl}}">
<view class="controls"></view>
</video>
5. 异步竞态条件
async loadData() {
const data = await fetchData()
this.setData({ data })
}
async loadData() {
this._dataVersion = (this._dataVersion || 0) + 1
const currentVersion = this._dataVersion
const data = await fetchData()
if (currentVersion === this._dataVersion && this.data) {
this.setData({ data })
}
}
data: {
requestTask: null
},
loadData() {
if (this.data.requestTask) {
this.data.requestTask.abort()
}
const requestTask = wx.request({
url: 'https://api.example.com/data',
success: res => {
this.setData({ data: res.data })
}
})
this.setData({ requestTask })
}
6. 本地存储限制
try {
wx.setStorageSync('userInfo', userInfo)
const data = wx.getStorageSync('userInfo')
} catch (err) {
console.error('存储失败', err)
if (err.errMsg.includes('exceed')) {
wx.clearStorageSync()
}
}
wx.setStorage({
key: 'largeData',
data: largeData,
success: () => console.log('存储成功'),
fail: err => {
console.error('存储失败', err)
}
})
function compressData(data) {
const compressed = {
id: data.id,
name: data.name,
}
return compressed
}
wx.setStorageSync('data', compressData(largeObject))
API 使用规范
1. 网络请求封装
const BASE_URL = 'https://api.example.com'
class Request {
constructor() {
this.baseURL = BASE_URL
this.timeout = 10000
}
request(options) {
return new Promise((resolve, reject) => {
const { url, method = 'GET', data = {}, header = {} } = options
wx.request({
url: this.baseURL + url,
method,
data,
header: {
'content-type': 'application/json',
'Authorization': wx.getStorageSync('token') || '',
...header
},
timeout: this.timeout,
success: res => {
if (res.statusCode === 200) {
resolve(res.data)
} else if (res.statusCode === 401) {
this.handleUnauthorized()
reject(new Error('未授权'))
} else {
reject(new Error(`请求失败: ${res.statusCode}`))
}
},
fail: err => {
console.error('网络请求失败', err)
wx.showToast({ title: '网络异常', icon: 'none' })
reject(err)
}
})
})
}
handleUnauthorized() {
wx.removeStorageSync('token')
wx.reLaunch({ url: '/pages/login/login' })
}
get(url, data, options = {}) {
return this.request({ url, method: 'GET', data, ...options })
}
post(url, data, options = {}) {
return this.request({ url, method: 'POST', data, ...options })
}
put(url, data, options = {}) {
return this.request({ url, method: 'PUT', data, ...options })
}
delete(url, data, options = {}) {
return this.request({ url, method: 'DELETE', data, ...options })
}
}
export default new Request()
import request from '@/utils/request'
const userInfo = await request.get('/user/info', { userId: 123 })
const result = await request.post('/user/update', {
nickName: 'New Name',
avatar: 'https://...'
})
2. 用户授权处理
class Permission {
async check(scope) {
try {
const { authSetting } = await wx.getSetting()
if (authSetting[scope]) {
return true
}
try {
await wx.authorize({ scope })
return true
} catch (err) {
return await this.openSetting(scope)
}
} catch (err) {
console.error('检查授权失败', err)
return false
}
}
async openSetting(scope) {
const scopeMap = {
'scope.userLocation': '位置信息',
'scope.userInfo': '用户信息',
'scope.camera': '摄像头',
'scope.album': '相册',
'scope.record': '录音'
}
const res = await wx.showModal({
title: '需要授权',
content: `请在设置中开启${scopeMap[scope] || '相关'}权限`,
confirmText: '去设置',
cancelText: '取消'
})
if (res.confirm) {
const { authSetting } = await wx.openSetting()
return !!authSetting[scope]
}
return false
}
}
export default new Permission()
import permission from '@/utils/permission'
const hasPermission = await permission.check('scope.userLocation')
if (hasPermission) {
wx.getLocation({
type: 'gcj02',
success: res => {
console.log('位置信息', res)
}
})
} else {
wx.showToast({ title: '需要位置权限', icon: 'none' })
}
3. 登录流程
async login() {
try {
const { code } = await wx.login()
if (!code) {
throw new Error('获取 code 失败')
}
const { token, userInfo } = await request.post('/api/login', {
code: code
})
wx.setStorageSync('token', token)
wx.setStorageSync('userInfo', userInfo)
getApp().globalData.userInfo = userInfo
return userInfo
} catch (err) {
console.error('登录失败', err)
wx.showToast({
title: '登录失败',
icon: 'none'
})
throw err
}
}
async getUserProfile() {
try {
const { userInfo } = await wx.getUserProfile({
desc: '用于完善用户资料'
})
this.setData({ userInfo })
wx.setStorageSync('userInfo', userInfo)
await request.post('/api/user/update', userInfo)
return userInfo
} catch (err) {
console.log('用户取消授权', err)
return null
}
}
async checkLoginStatus() {
const token = wx.getStorageSync('token')
if (!token) {
return false
}
try {
await request.get('/api/user/verify')
return true
} catch (err) {
wx.removeStorageSync('token')
return false
}
}
云开发集成
1. 云开发初始化
App({
onLaunch() {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力')
return
}
wx.cloud.init({
env: 'your-env-id',
traceUser: true
})
console.log('云开发环境初始化完成')
}
})
2. 云函数调用
async function callFunction(name, data = {}) {
try {
wx.showLoading({ title: '加载中...' })
const res = await wx.cloud.callFunction({
name: name,
data: data
})
wx.hideLoading()
if (res.errMsg === 'cloud.callFunction:ok') {
return res.result
} else {
throw new Error(res.errMsg)
}
} catch (err) {
wx.hideLoading()
console.error('云函数调用失败', err)
wx.showToast({
title: '操作失败',
icon: 'none'
})
throw err
}
}
const userInfo = await callFunction('getUser', {
userId: '123'
})
const order = await callFunction('createOrder', {
productId: 'prod_001',
quantity: 2
})
3. 云数据库操作
const db = wx.cloud.database()
const _ = db.command
async function queryTodos() {
try {
const { data } = await db.collection('todos')
.where({
status: _.neq('deleted'),
createTime: _.gte(new Date('2024-01-01'))
})
.orderBy('createTime', 'desc')
.field({
title: true,
status: true,
createTime: true
})
.limit(20)
.get()
return data
} catch (err) {
console.error('查询失败', err)
return []
}
}
async function addTodo(todo) {
try {
const { _id } = await db.collection('todos').add({
data: {
...todo,
createTime: db.serverDate(),
updateTime: db.serverDate(),
_openid: '{openid}'
}
})
console.log('添加成功', _id)
return _id
} catch (err) {
console.error('添加失败', err)
throw err
}
}
async function updateTodo(id, updates) {
try {
await db.collection('todos').doc(id).update({
data: {
...updates,
updateTime: db.serverDate()
}
})
console.log('更新成功')
} catch (err) {
console.error('更新失败', err)
throw err
}
}
async function deleteTodo(id) {
try {
await db.collection('todos').doc(id).remove()
console.log('删除成功')
} catch (err) {
console.error('删除失败', err)
throw err
}
}
function watchTodos(callback) {
const watcher = db.collection('todos')
.where({
status: _.neq('deleted')
})
.watch({
onChange: snapshot => {
console.log('数据变化', snapshot)
callback(snapshot.docs)
},
onError: err => {
console.error('监听失败', err)
}
})
return watcher
}
云数据库安全规范
数据库权限配置(重要):
云开发数据库默认受安全规则保护,需在云控制台配置访问权限。
{
"read": "doc._openid == auth.openid",
"write": "doc._openid == auth.openid"
}
安全查询原则:
- 始终在服务端(云函数)中执行敏感查询,避免前端直接查询
- 使用
_openid 字段自动隔离用户数据
- 复杂权限逻辑通过云函数封装,不要仅依赖前端
.where()
const db = cloud.database()
return db.collection('orders')
.where({ userId: event.userId })
.get()
参考:最新安全规则配置请参考微信官方文档 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database/security.html
### 4. 云存储
```javascript
// 上传文件
async function uploadFile(filePath) {
try {
// 生成唯一文件名
const timestamp = Date.now()
const random = Math.random().toString(36).substring(2, 9)
const ext = filePath.split('.').pop()
const cloudPath = `images/${timestamp}_${random}.${ext}`
wx.showLoading({ title: '上传中...' })
const { fileID } = await wx.cloud.uploadFile({
cloudPath: cloudPath,
filePath: filePath
})
wx.hideLoading()
console.log('上传成功', fileID)
return fileID
} catch (err) {
wx.hideLoading()
console.error('上传失败', err)
wx.showToast({
title: '上传失败',
icon: 'none'
})
throw err
}
}
// 下载文件
async function downloadFile(fileID) {
try {
const { tempFilePath } = await wx.cloud.downloadFile({
fileID: fileID
})
console.log('下载成功', tempFilePath)
return tempFilePath
} catch (err) {
console.error('下载失败', err)
throw err
}
}
// 删除文件
async function deleteFile(fileIDs) {
try {
const { fileList } = await wx.cloud.deleteFile({
fileList: Array.isArray(fileIDs) ? fileIDs : [fileIDs]
})
console.log('删除结果', fileList)
return fileList
} catch (err) {
console.error('删除失败', err)
throw err
}
}
// 获取临时链接(用于分享)
async function getTempFileURL(fileIDs) {
try {
const { fileList } = await wx.cloud.getTempFileURL({
fileList: Array.isArray(fileIDs) ? fileIDs : [fileIDs]
})
return fileList
} catch (err) {
console.error('获取临时链接失败', err)
throw err
}
}
// 使用示例:选择并上传图片
async function chooseAndUploadImage() {
try {
// 选择图片
const { tempFilePaths } = await wx.chooseImage({
count: 1,
sizeType: ['compressed'], // 压缩图
sourceType: ['album', 'camera']
})
// 上传图片
const fileID = await uploadFile(tempFilePaths[0])
// 保存到数据库
await db.collection('images').add({
data: {
fileID: fileID,
createTime: db.serverDate()
}
})
return fileID
} catch (err) {
console.error('操作失败', err)
}
}
基础库版本兼容性
微信小程序基础库版本决定了可用 API 的范围。使用 API 前请检查版本兼容性。
快速检查示例
if (wx.canIUse('getUserProfile')) {
const { userInfo } = await wx.getUserProfile({ desc: '用于完善资料' })
} else {
wx.showModal({
title: '提示',
content: '请升级微信版本以使用完整功能'
})
}
常用 API 版本要求
| API | 最低基础库版本 | 说明 |
|---|
wx.getUserProfile | 2.10.4 | 获取用户信息,需用户点击触发 |
wx.cloud | 2.2.3 | 云开发能力 |
wx.getPerformance | 2.11.0 | 性能监控 |
wx.requestSubscribeMessage | 2.4.4 | 订阅消息授权 |
详细版本兼容性参考: references/version-compatibility.md
测试与调试
单元测试
使用 miniprogram-simulate 框架进行组件单元测试。
npm install --save-dev miniprogram-simulate jest
const simulate = require('miniprogram-simulate')
const customButton = simulate.load('../index')
describe('CustomButton', () => {
it('应正确渲染', () => {
const comp = simulate.render(customButton, { title: '点击' })
comp.attach(document.createElement('parent'))
expect(comp.querySelector('.btn').dom.textContent).toBe('点击')
})
})
自动化测试
使用 miniprogram-automator 进行端到端测试。
npm install miniprogram-automator
真机调试
const logger = wx.getRealtimeLogManager?.()
logger?.info('调试信息', data)
详细测试指南参考: references/testing-guide.md
错误处理
统一错误处理
class ErrorHandler {
static handle(error, options = {}) {
const errorInfo = this.parseError(error)
wx.showToast({
title: errorInfo.message,
icon: 'none'
})
return options.fallback || null
}
static parseError(error) {
if (error.statusCode) {
const errors = {
401: '登录已过期',
404: '资源不存在',
500: '服务器错误'
}
return { message: errors[error.statusCode] || '请求失败' }
}
if (error.errMsg) {
if (error.errMsg.includes('auth deny')) {
return { message: '用户拒绝授权' }
}
if (error.errMsg.includes('timeout')) {
return { message: '请求超时' }
}
}
return { message: error.message || '未知错误' }
}
}
module.exports = ErrorHandler
使用示例
const { ErrorHandler } = require('../utils/error-handler')
Page({
async fetchData() {
try {
const data = await request.get('/api/data')
this.setData({ data })
} catch (error) {
ErrorHandler.handle(error, { fallback: { list: [] } })
}
}
})
详细错误处理参考: references/error-handling.md
更多内容
- 用户体验优化: 骨架屏、加载优化、交互反馈、错误处理
- 调试与发布: 开发调试技巧、版本管理、发布前检查清单、CI 工具
- 进阶功能: 自定义分享、订阅消息、自定义 TabBar
- 常用 API 快速参考: 界面交互、路由导航、网络请求、数据缓存、媒体、位置、设备等
详细内容请参考 references/ 目录中的文档:
api-reference.md - API 速查手册
performance-optimization.md - 性能优化详解
version-compatibility.md - 基础库版本兼容性指南
testing-guide.md - 测试与调试指南
error-handling.md - 错误处理与错误码对照表
deployment-guide.md - 发布与部署指南(含备案、隐私协议配置)
ui-components-guide.md - UI 组件库选型指南(WeUI/TDesign/CloudBase)
示例项目请参考 examples/ 目录:
basic-template.md - 基础模板示例
cloud-development.md - 云开发完整示例
typescript-template.md - TypeScript 项目示例
性能指标参考
- 首屏渲染时间: < 2s
- setData 单次数据: < 1024KB
- setData 调用频率: < 10 次/秒
- 代码包总大小: < 20MB
- 主包大小: < 2MB
- 单个分包大小: < 2MB
- 页面栈深度: ≤ 10 层
- 长列表渲染: < 100 项(建议使用虚拟列表)
- 图片体积: 单张 < 100KB(建议使用 webp)
参考资源
官方文档(已验证)
核心能力(已验证)
服务端 API(已验证)
UI 组件库
安装示例:
npm install tdesign-miniprogram
npm install @cloudbase/ai-agent-ui
版本管理建议:生产环境建议提交 package-lock.json 到版本控制,确保依赖版本一致性。如需查看各组件库最新版本,请参考官方文档:
GitHub 资源
开发者社区
总结
作为微信小程序开发专家,在提供技术指导时:
- 优先考虑性能: 始终关注 setData 优化、渲染性能和代码体积
- 注重兼容性: 处理好 iOS/Android 双端差异
- 提供完整方案: 包含错误处理、边界情况和用户反馈
- 遵循最佳实践: 使用标准的命名规范、代码风格和项目结构
- 关注用户体验: 提供加载提示、骨架屏和友好的交互反馈
- 代码可维护: 编写模块化、清晰的代码,添加必要注释
在回答用户问题时,根据具体场景选择合适的方案,提供清晰的代码示例和详细的说明。