Ceiling

微信小程序开发全流程

微信小程序是一种不需要下载安装、即用即走的轻量级应用形态,依托微信生态,天然具备社交传播和低成本获客的优势。本文从账号注册、开发环境搭建、项目结构、核心语法、网络请求、登录授权、真机调试到最终的上传审核发布,完整梳理一遍微信小程序的开发流程。

一、准备工作

1. 注册小程序账号

  1. 打开 微信公众平台,点击「立即注册」,选择「小程序」。
  2. 填写一个未绑定过公众平台的邮箱,完成邮箱验证。
  3. 选择主体类型(个人、企业等),按提示填写主体信息。个人主体免费,企业主体需要营业执照。
  4. 注册完成后登录后台,在「开发 → 开发管理 → 开发设置」中可以查看到小程序唯一的 AppID

2. 安装微信开发者工具

微信开发者工具下载页 下载并安装稳定版。首次启动使用微信扫码登录,新建项目时填入刚才获取的 AppID,即可创建一个空项目。

如果只是体验学习,也可以选择「测试号」,不需要注册 AppID,但部分能力(如微信支付)无法使用。

二、项目结构

一个标准的小程序项目目录如下:

project/
├── pages/            # 页面目录,每个页面一个文件夹
│   ├── index/        # 首页
│   │   ├── index.js
│   │   ├── index.json
│   │   ├── index.wxml
│   │   └── index.wxss
│   └── logs/
├── utils/            # 工具函数目录
├── app.js            # 小程序入口逻辑
├── app.json          # 全局配置
├── app.wxss          # 全局样式
└── sitemap.json      # 搜索索引配置

每个页面由四个同名文件组成,职责各不相同:

文件后缀作用是否必需
.wxml页面结构(类似 HTML)
.wxss页面样式(类似 CSS)
.js页面逻辑与数据
.json页面级配置(导航栏、窗口表现)

全局配置 app.json

app.json 是整个小程序的核心配置文件,必须包含 pages 字段:
{
  "pages": [
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window": {
    "navigationBarTitleText": "我的小程序",
    "navigationBarBackgroundColor": "#ffffff",
    "backgroundColor": "#eeeeee"
  },
  "tabBar": {
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页"
      },
      {
        "pagePath": "pages/logs/logs",
        "text": "日志"
      }
    ]
  }
}
  • pages:页面路径数组,第一项就是小程序的首页。新建页面时在这里注册后会自动创建对应文件。
  • window:全局窗口表现,包括导航栏标题、颜色、下拉背景色等。
  • tabBar:底部 Tab 栏配置,最少 2 项、最多 5 项。

三、WXML 与 WXSS

1. WXML 模板语法

WXML 通过数据绑定把逻辑层的数据渲染到界面上:

<view class="container">
  <text>{{message}}</text>
  <text wx:if="{{count > 0}}">共 {{count}} 条记录</text>
  <text wx:else>暂无数据</text>
</view>

列表渲染使用 wx:for

<view wx:for="{{list}}" wx:key="id" class="item">
  {{index}} - {{item.name}}
</view>

条件渲染支持 wx:ifwx:elifwx:else;与条件渲染不同,hidden 只是控制显示隐藏,元素始终会被渲染。

2. WXSS 样式

WXSS 在 CSS 的基础上扩展了两个特性:

  • 尺寸单位 rpx:响应式像素,规定屏幕宽度为 750rpx,在不同机型上自动换算,适合做等比布局。
  • 样式导入:使用 @import 引入其他样式文件,如 @import "common.wxss";

样式优先级遵循就近原则:页面私有样式 page.wxss > 全局样式 app.wxss

四、页面逻辑与生命周期

1. Page 实例

每个页面的 .js 文件调用 Page() 注册一个页面实例,数据放在 data 中:

Page({
  data: {
    count: 0
  },
  onLoad(options) {
    // 页面加载,options 为路由参数
  },
  onShow() {
    // 页面显示
  },
  onPullDownRefresh() {
    // 下拉刷新
  },
  add() {
    this.setData({ count: this.data.count + 1 });
  }
});
修改 data 后必须调用 this.setData() 才能触发视图更新,直接赋值 this.data.count = 1 不会刷新界面。

2. 生命周期总览

小程序的生命周期分为应用级、页面级和组件级三层:

flowchart TD A[App onLaunch 小程序初始化] --> B[App onShow 进入前台] B --> C[Page onLoad 页面加载] C --> D[Page onShow 页面显示] D --> E[Page onReady 首次渲染完成] E --> F[用户操作页面] F --> G[Page onHide 页面隐藏] G --> H[Page onUnload 页面卸载] F --> I[App onHide 进入后台]
生命周期触发时机典型用途
onLaunch小程序初始化完成获取全局缓存、初始化配置
onLoad页面加载,一个页面只会调用一次请求数据、读取路由参数
onShow页面显示每次返回页面时刷新数据
onReady首次渲染完成操作节点、初始化 canvas
onHide页面隐藏暂停计时器、保存草稿
onUnload页面卸载清理资源

3. 事件绑定

在 WXML 中通过 bindtapcatchtap 等属性绑定事件处理函数:

<button bindtap="onTap" data-id="{{item.id}}">点击</button>
Page({
  onTap(e) {
    // 自定义数据通过 dataset 传递
    const id = e.currentTarget.dataset.id;
    console.log('点击了', id);
  }
});
  • bind 冒泡绑定:事件会向父节点冒泡。
  • catch 阻止冒泡:事件只在当前节点处理。

五、页面路由与导航

常用的页面跳转 API:

API行为说明
wx.navigateTo保留当前页,打开新页面页面栈最多 10 层,可通过 wx.navigateBack 返回
wx.redirectTo关闭当前页,打开新页面无法返回原页面
wx.switchTab跳转到 tabBar 页面会关闭所有非 tabBar 页面
wx.reLaunch关闭所有页面,打开新页面任意页面可用
wx.navigateBack返回上一层或多层通过 delta 指定层数
wx.navigateTo({
  url: '/pages/detail/detail?id=123'
});

目标页面在 onLoad(options) 中通过 options.id 接收参数。

六、网络请求

小程序通过 wx.request 发起 HTTPS 请求。生产环境要求域名必须在小程序后台「开发设置 → 服务器域名」中配置白名单,且必须是 HTTPS。

1. 基础用法

wx.request({
  url: 'https://api.example.com/list',
  method: 'GET',
  data: { page: 1 },
  success(res) {
    if (res.statusCode === 200) {
      console.log(res.data);
    }
  },
  fail(err) {
    console.error('请求失败', err);
  }
});

2. 封装 Promise 版请求

实际项目中通常封装一层,统一处理域名、加载提示和错误码:

const BASE_URL = 'https://api.example.com';

function request(options) {
  return new Promise((resolve, reject) => {
    wx.showLoading({ title: '加载中' });
    wx.request({
      url: BASE_URL + options.url,
      method: options.method || 'GET',
      data: options.data || {},
      header: {
        'Authorization': wx.getStorageSync('token') || ''
      },
      success(res) {
        if (res.statusCode === 200 && res.data.code === 0) {
          resolve(res.data.data);
        } else {
          reject(res.data);
        }
      },
      fail: reject,
      complete() {
        wx.hideLoading();
      }
    });
  });
}

module.exports = { request };

页面中使用:

const { request } = require('../../utils/request');

Page({
  data: { list: [] },
  async onLoad() {
    try {
      const list = await request({ url: '/list' });
      this.setData({ list });
    } catch (err) {
      wx.showToast({ title: '加载失败', icon: 'none' });
    }
  }
});

七、登录与用户授权

1. 登录流程

小程序登录采用「临时凭证 code 换会话」的模式,整体流程如下:

sequenceDiagram participant P as 小程序前端 participant S as 开发者服务器 participant W as 微信服务器 P->>P: wx.login() 获取 code P->>S: 提交 code S->>W: code + appid + secret 请求 code2Session W-->>S: 返回 openid、session_key S-->>P: 返回自定义登录态 token P->>P: 缓存 token,后续请求携带

前端调用 wx.login()

wx.login({
  success(res) {
    if (res.code) {
      // 将 code 发送给开发者服务器换取登录态
      wx.request({
        url: 'https://api.example.com/login',
        method: 'POST',
        data: { code: res.code }
      });
    }
  }
});

服务端拿到 code 后,请求微信接口换取 openid 和 session_key:

GET https://api.weixin.qq.com/sns/jscode2session
  ?appid=APPID
  &secret=SECRET
  &js_code=CODE
  &grant_type=authorization_code
session_key 是对用户数据进行加密签名的密钥,只能保存在服务端,绝不能下发到前端。

2. 获取用户头像昵称

新版本基础库已回收 wx.getUserProfile,现在推荐的方式是「头像昵称填写能力」:

<button open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
  选择头像
</button>
<input type="nickname" placeholder="请输入昵称" bindinput="onInputNickname">

用户选择头像后在回调中拿到临时文件路径,上传到服务器保存:

Page({
  onChooseAvatar(e) {
    const avatarUrl = e.detail.avatarUrl;
    wx.uploadFile({
      url: 'https://api.example.com/upload',
      filePath: avatarUrl,
      name: 'file'
    });
  },
  onInputNickname(e) {
    this.setData({ nickname: e.detail.value });
  }
});

3. 获取手机号

手机号获取属于敏感能力,仅认证的企业主体可用:

<button open-type="getPhoneNumber" bindgetphonenumber="onGetPhone">
  获取手机号
</button>

回调中拿到加密的 code,提交给服务端调用微信的手机号解密接口即可得到明文手机号。

八、本地存储与状态共享

1. 本地缓存

wx.setStorageSync / wx.getStorageSync 提供同步的本地存储能力,单个 key 上限 1MB,总上限 10MB:
wx.setStorageSync('token', 'abc123');
const token = wx.getStorageSync('token');
wx.removeStorageSync('token');

2. 全局数据

跨页面共享少量全局状态,可以挂在 App 实例上:

// app.js
App({
  globalData: {
    userInfo: null
  }
});

// 页面中
const app = getApp();
app.globalData.userInfo = userInfo;

如果页面间需要传递的数据量较大,更推荐通过路由参数或后端接口传递,而不是依赖 globalData。

九、常用内置组件

组件用途
view通用容器,类似 div
text文本,支持 selectable 长按选择
image图片,支持多种裁剪模式 mode
scroll-view可滚动区域
swiper轮播图
navigator页面链接,类似 a 标签
button按钮,可配合 open-type 使用开放能力
input输入框
form表单容器

图片组件常见用法:

<image src="{{imgUrl}}" mode="aspectFill" lazy-load binderror="onImgError">

十、真机调试与预览

微信开发者工具提供三种运行方式:

  1. 模拟器:在工具内直接预览,适合快速开发调试,但与真机存在表现差异。
  2. 预览:点击工具栏「预览」生成二维码,手机扫码体验,仅自己可用,二维码 30 分钟有效。
  3. 真机调试:点击「真机调试」,手机端的运行日志、断点调试会实时回传到工具面板,排查真机问题必备。

开发期间建议在工具「详情 → 本地设置」中勾选「不校验合法域名」,方便调试本地接口;上线前务必关闭并配置好正式域名。

十一、发布上线

1. 上传代码

开发完成后点击工具栏「上传」,填写版本号和备注,代码会上传到微信服务器,成为「开发版本」。

2. 提交审核

登录微信公众平台 →「版本管理」,把开发版本「提交审核」。审核一般需要填写每个页面的功能说明,通常 1~3 个工作日出结果,可在「审核设置」中配置加急审核。

3. 发布与回滚

  • 审核通过后,在版本管理页点击「发布」,用户即可搜索访问。
  • 如果线上版本出现问题,可以一键「版本回退」,回退到上一个线上版本(每个版本仅可回退一次)。
  • 建议使用「分阶段发布」,先灰度 5%~20% 的用户,观察无异常后再全量。

十二、常见问题与优化建议

  • setData 频繁调用导致卡顿:合并多次 setData 为一次;长列表只更新变化的字段,避免整体替换数组。
  • 图片加载慢:使用 CDN,配合 lazy-load 懒加载,列表缩略图请求小尺寸规格。
  • 包体积超限:主包上限 2MB,使用分包加载(subpackages)拆分页面,静态资源放到 CDN。
  • 白屏兜底:接口失败时给出明确的错误提示和重试按钮,避免空白页。
  • 安全:不要把 AppSecret、session_key 等敏感信息放在前端代码里。

总结

小程序开发的核心流程可以归纳为:注册账号拿 AppID → 开发者工具建项目 → 理解四文件结构与 app.json 配置 → 用 WXML/WXSS 搭建界面 → 在 Page 生命周期里组织逻辑 → wx.request 对接后端 → 完成登录授权 → 真机调试 → 上传、审核、发布。掌握这条主线之后,再去学习自定义组件、云开发、分包等进阶能力,会顺畅很多。