Skip to content

微信小程序开发指南 ​

🎯 概述 ​

微信小程序是一种不需要下载安装即可使用的应用,用户扫一扫或搜一下即可打开应用。本文将分享微信小程序开发的最佳实践和常用技巧。

📚 基础概念 ​

小程序架构 ​

┌─────────────────────────────────────┐
│           小程序架构                │
├─────────────────────────────────────┤
│  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请求
  • 定期更新依赖

小程序让应用更便捷! 📱