微信小程序开发指南
🎯 概述
微信小程序是一种不需要下载安装即可使用的应用,用户扫一扫或搜一下即可打开应用。本文将分享微信小程序开发的最佳实践和常用技巧。
📚 基础概念
小程序架构
┌─────────────────────────────────────┐
│ 小程序架构 │
├─────────────────────────────────────┤
│ WXML (结构) │ WXSS (样式) │
├─────────────────────────────────────┤
│ JavaScript (逻辑) │ JSON (配置) │
├─────────────────────────────────────┤
│ 微信客户端 │
└─────────────────────────────────────┘文件结构
miniprogram/
├── app.js # 小程序逻辑
├── app.json # 小程序配置
├── app.wxss # 全局样式
├── pages/ # 页面目录
│ ├── index/ # 首页
│ │ ├── index.js
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ └── index.json
│ └── profile/ # 个人中心
├── components/ # 自定义组件
├── utils/ # 工具函数
└── images/ # 图片资源🛠️ 开发实践
1. 页面开发
javascript
// pages/index/index.js
Page({
data: {
userInfo: {},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo'),
canIUseGetUserProfile: false,
canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName')
},
onLoad() {
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
},
getUserProfile(e) {
wx.getUserProfile({
desc: '用于完善会员资料',
success: (res) => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
},
getUserInfo(e) {
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
},
// 页面分享
onShareAppMessage() {
return {
title: '自定义分享标题',
path: '/pages/index/index'
}
}
})xml
<!-- pages/index/index.wxml -->
<view class="container">
<view class="userinfo">
<block wx:if="{{canIUseOpenData}}">
<view class="userinfo-avatar" bindtap="bindViewTap">
<open-data type="userAvatarUrl"></open-data>
</view>
<open-data type="userNickName"></open-data>
</block>
<block wx:elif="{{hasUserInfo}}">
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
<block wx:else>
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
<button wx:elif="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
<view> 请使用1.4.4及以上版本基础库 </view>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>css
/* pages/index/index.wxss */
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
color: #aaa;
}
.userinfo-avatar {
overflow: hidden;
width: 128rpx;
height: 128rpx;
margin: 20rpx;
border-radius: 50%;
}
.usermotto {
margin-top: 200px;
}2. 组件开发
javascript
// components/custom-button/custom-button.js
Component({
properties: {
text: {
type: String,
value: '按钮'
},
type: {
type: String,
value: 'default'
},
size: {
type: String,
value: 'default'
}
},
data: {
loading: false
},
methods: {
onTap() {
if (this.data.loading) return
this.setData({
loading: true
})
// 触发自定义事件
this.triggerEvent('tap', {
text: this.properties.text
})
// 模拟异步操作
setTimeout(() => {
this.setData({
loading: false
})
}, 1000)
}
}
})xml
<!-- components/custom-button/custom-button.wxml -->
<button
class="custom-button {{type}} {{size}} {{loading ? 'loading' : ''}}"
bindtap="onTap"
disabled="{{loading}}"
>
<text wx:if="{{loading}}">加载中...</text>
<text wx:else>{{text}}</text>
</button>css
/* components/custom-button/custom-button.wxss */
.custom-button {
border-radius: 8rpx;
font-size: 32rpx;
padding: 20rpx 40rpx;
}
.custom-button.primary {
background-color: #007aff;
color: white;
}
.custom-button.default {
background-color: #f8f8f8;
color: #333;
}
.custom-button.small {
font-size: 24rpx;
padding: 16rpx 32rpx;
}
.custom-button.large {
font-size: 36rpx;
padding: 24rpx 48rpx;
}
.custom-button.loading {
opacity: 0.6;
}3. 网络请求
javascript
// utils/request.js
const baseURL = 'https://api.example.com'
class Request {
constructor() {
this.baseURL = baseURL
this.timeout = 10000
}
request(options) {
return new Promise((resolve, reject) => {
wx.request({
url: this.baseURL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
'Authorization': wx.getStorageSync('token') || '',
...options.header
},
timeout: this.timeout,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data)
} else {
reject(new Error(`请求失败: ${res.statusCode}`))
}
},
fail: (err) => {
reject(err)
}
})
})
}
get(url, data, options = {}) {
return this.request({
url,
method: 'GET',
data,
...options
})
}
post(url, data, options = {}) {
return this.request({
url,
method: 'POST',
data,
...options
})
}
}
export default new Request()4. 状态管理
javascript
// store/index.js
class Store {
constructor() {
this.state = {
userInfo: null,
token: null,
cartCount: 0
}
this.listeners = []
}
setState(newState) {
this.state = { ...this.state, ...newState }
this.notify()
}
getState() {
return this.state
}
subscribe(listener) {
this.listeners.push(listener)
return () => {
this.listeners = this.listeners.filter(l => l !== listener)
}
}
notify() {
this.listeners.forEach(listener => listener(this.state))
}
}
export default new Store()javascript
// pages/index/index.js
import store from '../../store/index'
Page({
data: {
userInfo: null,
cartCount: 0
},
onLoad() {
// 订阅状态变化
this.unsubscribe = store.subscribe((state) => {
this.setData({
userInfo: state.userInfo,
cartCount: state.cartCount
})
})
// 初始化数据
this.setData({
userInfo: store.getState().userInfo,
cartCount: store.getState().cartCount
})
},
onUnload() {
// 取消订阅
if (this.unsubscribe) {
this.unsubscribe()
}
},
updateUserInfo() {
store.setState({
userInfo: { name: '张三', avatar: 'avatar.jpg' }
})
}
})🚀 高级功能
1. 云开发
javascript
// 云函数示例
// cloudfunctions/getUserInfo/index.js
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
const { OPENID } = cloud.getWXContext()
try {
// 查询用户信息
const result = await cloud.database().collection('users')
.where({
_openid: OPENID
})
.get()
return {
success: true,
data: result.data[0] || null
}
} catch (error) {
return {
success: false,
error: error.message
}
}
}javascript
// 调用云函数
wx.cloud.callFunction({
name: 'getUserInfo',
success: (res) => {
console.log('云函数调用成功', res.result)
},
fail: (err) => {
console.error('云函数调用失败', err)
}
})2. 支付功能
javascript
// 微信支付
payOrder(orderInfo) {
return new Promise((resolve, reject) => {
wx.requestPayment({
timeStamp: orderInfo.timeStamp,
nonceStr: orderInfo.nonceStr,
package: orderInfo.package,
signType: orderInfo.signType,
paySign: orderInfo.paySign,
success: (res) => {
resolve(res)
},
fail: (err) => {
reject(err)
}
})
})
}
// 调用支付
async handlePay() {
try {
// 1. 创建订单
const orderResult = await this.createOrder()
// 2. 调用支付
const payResult = await this.payOrder(orderResult.data)
// 3. 支付成功处理
this.showToast('支付成功')
this.navigateTo('/pages/order/order')
} catch (error) {
console.error('支付失败', error)
this.showToast('支付失败,请重试')
}
}3. 分享功能
javascript
// 页面分享
onShareAppMessage() {
return {
title: '分享标题',
path: '/pages/index/index',
imageUrl: '/images/share.jpg'
}
}
// 分享到朋友圈
onShareTimeline() {
return {
title: '朋友圈分享标题',
imageUrl: '/images/timeline.jpg'
}
}
// 自定义分享
shareToFriend() {
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
}🔧 性能优化
1. 图片优化
javascript
// 图片懒加载
<image
src="{{item.imageUrl}}"
lazy-load="{{true}}"
mode="aspectFill"
class="lazy-image"
/>
// 图片压缩
compressImage(imagePath) {
return new Promise((resolve, reject) => {
wx.compressImage({
src: imagePath,
quality: 80,
success: (res) => {
resolve(res.tempFilePath)
},
fail: reject
})
})
}2. 数据缓存
javascript
// 数据缓存
class Cache {
static set(key, data, expire = 3600000) {
const cacheData = {
data,
expire: Date.now() + expire
}
wx.setStorageSync(key, cacheData)
}
static get(key) {
const cacheData = wx.getStorageSync(key)
if (!cacheData) return null
if (Date.now() > cacheData.expire) {
wx.removeStorageSync(key)
return null
}
return cacheData.data
}
static remove(key) {
wx.removeStorageSync(key)
}
}
// 使用缓存
const userInfo = Cache.get('userInfo')
if (!userInfo) {
// 从服务器获取数据
const data = await this.fetchUserInfo()
Cache.set('userInfo', data)
}3. 分包加载
json
// app.json
{
"pages": [
"pages/index/index",
"pages/profile/profile"
],
"subPackages": [
{
"root": "pages/shop",
"pages": [
"list/list",
"detail/detail"
]
},
{
"root": "pages/order",
"pages": [
"list/list",
"detail/detail"
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pages/shop"]
}
}
}📱 调试技巧
1. 真机调试
javascript
// 调试信息输出
console.log('调试信息', data)
console.warn('警告信息', warning)
console.error('错误信息', error)
// 条件调试
if (__DEV__) {
console.log('开发环境调试信息')
}2. 性能监控
javascript
// 页面性能监控
onLoad() {
const startTime = Date.now()
// 页面加载完成
this.onReady = () => {
const loadTime = Date.now() - startTime
console.log(`页面加载时间: ${loadTime}ms`)
}
}
// 网络请求监控
const originalRequest = wx.request
wx.request = function(options) {
const startTime = Date.now()
return originalRequest.call(this, {
...options,
success: (res) => {
const duration = Date.now() - startTime
console.log(`请求耗时: ${duration}ms`, options.url)
options.success && options.success(res)
}
})
}🎯 最佳实践
1. 代码规范
- 使用ESLint进行代码检查
- 遵循微信小程序开发规范
- 合理使用组件化开发
- 保持代码简洁易读
2. 用户体验
- 合理使用loading状态
- 提供友好的错误提示
- 优化页面加载速度
- 适配不同屏幕尺寸
3. 性能优化
- 使用分包加载
- 合理使用缓存
- 优化图片资源
- 减少不必要的渲染
4. 安全考虑
- 敏感信息加密存储
- 验证用户输入
- 使用HTTPS请求
- 定期更新依赖
小程序让应用更便捷! 📱