在移动互联网流量格局中,小程序凭借免安装、近原生体验、平台流量扶持、开发成本可控的核心优势,成为企业级前端业务的重要载体。本文围绕微信原生小程序开发、Taro多端跨端方案、企业级小程序生态落地展开,从基础入门到工程化实践,完整覆盖小程序开发核心能力,兼顾知识点梳理、代码实操与企业实践,既可作为课堂学习笔记,也可用于后续复习、面试复盘与项目开发参考,所有示例均补充完整可运行代码,最大化落地价值。

小程序核心认知

主流移动端方案对比

小程序介于H5与原生App之间,兼顾开发效率与用户体验,是中低频业务、流量转化、端内服务的最优解,三者核心差异如下

方案 核心优势 核心劣势 适用场景
原生App 原生能力强,用户体验佳 开发成本高,双端需独立开发,发版需审核,平台依赖度高 核心高频业务
H5 无需安装,跨平台性强,开发成本低 依赖浏览器能力,用户体验一般,受WebView限制 活动页、营销页
小程序 原生体验佳,无需安装,跨平台性强,拥有良好的流量基础 受平台能力限制,多端适配存在一定成本 服务场景、中轻度交互、公域流量转化

小程序核心架构

image-20260209180018968

小程序采用渲染层与逻辑层分离架构,通过底层Native完成通信,这是其兼顾Web开发效率与原生体验的关键,也是区别于H5的核心特点

  • 渲染层:基于WebView实现,负责页面的结构与样式渲染,支持多WebView并行,对应WXML和WXSS文件
  • 逻辑层:基于JsCore实现,负责业务逻辑处理、数据管理,不直接操作DOM,对应JS文件
  • 通信桥梁:由小程序客户端提供,渲染层与逻辑层的所有数据传递、事件通信都需经过Native中转,既保证运行安全性,也实现了两层的协同工作

小程序可通过Native层调用平台原生能力,包括HTTPS请求、WebSocket、设备信息获取等,突破了传统H5的能力限制,进一步提升用户体验。

原生开发

项目创建

原生小程序开发需使用微信官方提供的开发者工具,该工具集成编码、调试、预览、上传、发布等全流程功能,是原生开发的必备工具,具体创建步骤如下

  1. 打开微信开发者工具,点击创建小程序选项
  2. 输入项目核心信息,包括项目名称、项目目录、AppID,其中AppID是小程序的唯一标识,个人开发者可使用测试号,企业开发者需在微信公众平台申请正式AppID
  3. 配置后端服务,新手建议选择不使用云服务,降低入门难度
  4. 选择模板,推荐使用基础模板,生成最简项目结构,便于后续根据需求自定义拓展

开发小贴士:开发工具可开启自动保存、热重载功能,提升开发效率;同时在设置中配置代码校验规则,提前规避语法错误,保证代码规范性。

项目结构

原生小程序的项目结构需遵循规范化分层原则,按业务职责单一拆分目录,便于后续维护与扩展,PDF中以公司部门架构做类比,让各目录作用更易理解,标准企业级项目结构如下,同时补充各目录实操示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
├── .eslintrc.js        # 代码规范配置,统一团队代码质量标准
├── .prettierrc # 代码格式化配置,保证团队代码风格一致
├── project.config.json # 项目配置,适配微信开发者工具
├── project.private.config.json # 项目私有配置
├── app.js # 小程序入口文件,仅保留全局初始化逻辑
├── app.json # 全局配置,包含页面路径、窗口样式、tabBar等
├── app.wxss # 全局样式,仅保留通用样式,如重置样式、主题色
├── sitemap.json # 微信索引配置,控制小程序页面被搜索收录
├── config/ # 全局配置文件夹,抽离硬编码内容
│ ├── api.js # 接口域名、请求常量配置
│ ├── theme.js # 主题色、字体大小、间距等样式常量
│ └── constants.js # 业务常量,如状态码、枚举值等
├── services/ # 接口请求层,统一管理所有接口调用
│ ├── request.js # 封装wx.request,添加拦截器、异常处理
│ └── user.js # 按业务模块拆分接口,如用户相关接口
├── components/ # 自定义组件文件夹,按复用性拆分
│ ├── common/ # 通用基础组件,如按钮、弹窗、加载框、输入框
│ └── business/ # 业务专属组件,如订单卡片、商品列表项
├── pages/ # 页面文件夹,按业务模块拆分
│ ├── index/ # 首页,包含index.js、index.wxml、index.wxss、index.json
│ ├── logs/ # 日志页
│ └── user/ # 个人中心等业务页面
├── utils/ # 工具函数文件夹,如时间格式化、数据校验、防抖节流
├── store/ # 状态管理,中大型项目必备,如mobx、redux
└── static/ # 静态资源文件夹,统一管理图片、图标、字体等

实操示例 配置文件抽离

将全局常量抽离到config目录,避免硬编码,便于后续统一修改维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// config/api.js 接口相关配置
module.exports = {
BASE_URL: "https://api.test.com", // 接口基础域名
TIMEOUT: 10000 // 请求超时时间,单位ms
}

// config/theme.js 样式常量配置
module.exports = {
primaryColor: '#165DFF', // 主色调
secondaryColor: '#FF7D00', // 辅助色
fontSize: {
sm: '24rpx', // 小号字体
md: '28rpx', // 中号字体
lg: '32rpx' // 大号字体
},
margin: {
xs: '10rpx',
sm: '20rpx',
md: '30rpx'
}
}

// config/constants.js 业务常量配置
module.exports = {
CODE_SUCCESS: 200, // 请求成功状态码
CODE_TOKEN_INVALID: 401, // 令牌失效状态码
CODE_ERROR: 500, // 服务器错误状态码
USER_ROLE: {
STUDENT: 1,
TEACHER: 2
}
}

实操示例 请求封装

在services目录下封装wx.request,统一处理请求拦截、响应拦截、异常处理,减少重复代码,提升接口调用规范性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// services/request.js
const { BASE_URL, TIMEOUT } = require('../config/api');
const { CODE_SUCCESS, CODE_TOKEN_INVALID } = require('../config/constants');

// 封装微信原生请求
function request(options) {
return new Promise((resolve, reject) => {
wx.request({
url: BASE_URL + options.url, // 拼接完整接口地址
method: options.method || 'GET', // 默认请求方式为GET
data: options.data || {}, // 默认请求参数为空
header: {
'content-type': 'application/json',
'token': wx.getStorageSync('token') || '' // 携带登录态令牌
},
timeout: TIMEOUT, // 请求超时时间
// 响应拦截:统一处理响应结果
success: (res) => {
const { code, data, msg } = res.data;
if (code === CODE_SUCCESS) {
// 请求成功,返回响应数据
resolve(data);
} else {
// 令牌失效,跳转至登录页
if (code === CODE_TOKEN_INVALID) {
wx.navigateTo({ url: '/pages/login/login' });
}
// 统一错误提示
wx.showToast({
title: msg || '请求失败,请稍后重试',
icon: 'none',
duration: 2000
});
reject(res.data);
}
},
// 网络错误拦截
fail: (err) => {
wx.showToast({
title: '网络异常,请检查网络连接',
icon: 'none',
duration: 2000
});
reject(err);
}
});
});
}

// 导出GET、POST方法,简化接口调用
module.exports = {
get: (url, data) => request({ url, data, method: 'GET' }),
post: (url, data) => request({ url, data, method: 'POST' })
}

小程序注册

小程序的运行需先完成全局注册,再完成页面注册,分别通过App和Page两个构造函数实现,二者均包含生命周期回调函数,是开发的核心入口。

全局注册 App

在app.js中通过App注册小程序,指定全局生命周期、全局数据和全局方法,仅负责全局初始化逻辑,不处理具体业务逻辑,确保入口文件简洁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// app.js
App({
// 全局数据,所有页面可通过getApp获取
globalData: {
userInfo: null,
token: '',
isLogin: false
},
// 小程序初始化,全局只触发一次
onLaunch(options) {
console.log('小程序初始化', options);
// 初始化时获取登录态
this.checkLoginStatus();
},
// 小程序启动或从后台切到前台,每次切换都会触发
onShow(options) {
console.log('小程序切到前台', options);
// 切前台时更新登录态
if (this.globalData.isLogin) {
this.updateUserInfo();
}
},
// 小程序从后台切到前台,触发
onHide() {
console.log('小程序切到后台');
},
// 全局错误监听,捕获小程序运行中的所有错误
onError(msg) {
console.log('小程序运行错误', msg);
// 错误上报,便于排查问题
this.reportError(msg);
},
// 页面不存在监听,当跳转的页面路径未在app.json中声明时触发
onPageNotFound(res) {
console.log('页面不存在', res);
// 跳转至首页,避免用户看到错误页面
wx.navigateTo({ url: '/pages/index/index' });
},
// 监听系统主题变化
onThemeChange(res) {
console.log('系统主题变化', res);
},
// 未处理的Promise拒绝事件监听
onUnhandledRejection(res) {
console.log('未处理的Promise拒绝', res);
},
// 自定义全局方法:检查登录状态
checkLoginStatus() {
const token = wx.getStorageSync('token');
if (token) {
this.globalData.token = token;
this.globalData.isLogin = true;
} else {
this.globalData.isLogin = false;
}
},
// 自定义全局方法:更新用户信息
updateUserInfo() {
// 调用用户信息接口,更新全局用户数据
},
// 自定义全局方法:错误上报
reportError(msg) {
// 调用错误上报接口,将错误信息发送至服务器
}
});

// 其他页面获取全局数据和方法
const app = getApp();
console.log(app.globalData.token);
app.checkLoginStatus();

页面组成

一个小程序页面由四个文件组成,各司其职,且文件名称必须与页面文件夹名称一致,微信开发者工具会自动识别并关联,四个文件的核心作用如下

文件类型 是否必需 核心作用 备注
js 页面逻辑处理,包含生命周期、数据、事件处理函数 .js后缀的JS脚本文件
wxml 页面结构渲染,定义页面的DOM结构 .wxml后缀的WXML模板文件,类似HTML
json 页面配置,可覆盖全局app.json的配置 .json后缀的JSON配置文件,仅对当前页面生效
wxss 页面样式定义,控制页面元素的显示样式 .wxss后缀的WXSS样式文件,类似CSS,支持rpx单位

实操示例 页面配置

页面json配置可自定义当前页面的导航栏、下拉刷新等特性,覆盖全局配置

1
2
3
4
5
6
7
8
9
// pages/index/index.json
{
"navigationBarTitleText": "首页", // 导航栏标题
"navigationBarBackgroundColor": "#165DFF", // 导航栏背景色
"navigationBarTextStyle": "white", // 导航栏文字颜色,仅支持black/white
"enablePullDownRefresh": true, // 开启下拉刷新
"backgroundColor": "#f5f5f5", // 页面背景色
"backgroundTextStyle": "dark" // 下拉刷新文字颜色
}

页面注册

每个页面的js文件通过Page注册,包含页面数据、生命周期回调函数、事件处理函数和自定义业务方法,是页面业务逻辑的核心。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// pages/index/index.js
const app = getApp();
const { get } = require('../../services/request');

// 页面注册
Page({
// 页面初始数据,WXML中的动态数据均来自此处
data: {
bannerList: [], // 轮播图数据
productList: [], // 商品列表数据
isLoading: true, // 加载状态
page: 1, // 当前页码
pageSize: 10 // 每页条数
},
// 页面加载,只触发一次,接收路由参数
onLoad(options) {
console.log('页面加载,路由参数', options);
// 加载页面初始化数据
this.loadPageData();
},
// 页面显示,每次切到该页面都会触发
onShow() {
console.log('页面显示');
// 页面显示时,更新页面状态(如登录态变化后更新数据)
if (app.globalData.isLogin !== this.data.isLogin) {
this.setData({
isLogin: app.globalData.isLogin
});
this.loadPageData();
}
},
// 页面初次渲染完成,只触发一次
onReady() {
console.log('页面渲染完成');
// 可在此处获取页面节点信息、创建动画等
},
// 页面隐藏,当页面被跳转、切后台时触发
onHide() {
console.log('页面隐藏');
},
// 页面卸载,当页面被关闭时触发
onUnload() {
console.log('页面卸载');
// 可在此处释放资源,如清除定时器
},
// 下拉刷新触发
onPullDownRefresh() {
console.log('下拉刷新');
// 重置页码,重新加载数据
this.setData({ page: 1 });
this.loadPageData(() => {
// 数据加载完成后,停止下拉刷新
wx.stopPullDownRefresh();
});
},
// 页面触底触发,用于上拉加载更多
onReachBottom() {
console.log('页面触底');
if (!this.data.isLoading) {
this.setData({ page: this.data.page + 1 });
this.loadMoreData();
}
},
// 用户点击右上角分享
onShareAppMessage() {
return {
title: '首页分享',
path: '/pages/index/index',
imageUrl: '/static/images/share.jpg'
};
},
// 自定义方法:加载页面初始化数据
async loadPageData(callback) {
try {
this.setData({ isLoading: true });
// 调用接口获取数据
const [bannerData, productData] = await Promise.all([
get('/home/banner'),
get('/home/product', { page: this.data.page, pageSize: this.data.pageSize })
]);
// 更新页面数据,驱动视图刷新
this.setData({
bannerList: bannerData,
productList: productData.list,
isLoading: false
});
// 执行回调函数(如下拉刷新停止)
callback && callback();
} catch (err) {
this.setData({ isLoading: false });
console.error('加载数据失败', err);
}
},
// 自定义方法:加载更多数据
async loadMoreData() {
try {
this.setData({ isLoading: true });
const productData = await get('/home/product', {
page: this.data.page,
pageSize: this.data.pageSize
});
// 拼接更多数据,避免覆盖原有数据
this.setData({
productList: [...this.data.productList, ...productData.list],
isLoading: false
});
} catch (err) {
this.setData({ isLoading: false });
console.error('加载更多失败', err);
}
},
// 自定义事件处理函数:跳转到商品详情页
goProductDetail(e) {
// 通过data-*获取传递的参数
const { id } = e.currentTarget.dataset;
// 路由跳转
wx.navigateTo({ url: `/pages/product/detail/detail?id=${id}` });
}
});

页面生命周期

每个小程序页面都有若干生命周期函数,在页面注册时定义,会在相应的时机自动触发,掌握生命周期的执行顺序,能更合理地安排业务逻辑,核心生命周期如下

生命周期函数 类型 核心作用
onLoad 函数 监听页面加载,页面创建后只触发一次,可接收路由参数,适合初始化数据
onShow 函数 监听页面显示,每次页面切换到前台、从其他页面返回时都会触发
onReady 函数 监听页面初次渲染完成,只触发一次,适合获取页面节点、创建动画
onHide 函数 监听页面隐藏,页面跳转、切后台时触发,适合暂停任务(如定时器)
onUnload 函数 监听页面卸载,页面关闭时触发,适合释放资源(如清除定时器、取消请求)

生命周期执行顺序:onLoad → onShow → onReady → onHide → onUnload

页面路由

小程序的页面跳转通过路由实现,路由事件的发起分为两种方式,用户操作和开发者调用API或组件,小程序通过页面栈管理所有打开的页面,页面栈按跳转顺序存放页面。

  • 路由发起时机:用户操作,如按下手机返回按钮;开发者调用API,如wx.navigateTo,或使用组件,如navigator
  • 页面栈管理:小程序页面栈遵循先进后出原则,每次跳转新页面,页面入栈;返回上一页,页面出栈
  • 路由配置:所有页面路径都需在app.json的pages或subpackages中声明,否则无法跳转

常用路由API实操

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 1. 保留当前页面,跳转到新页面(最多跳转10层)
wx.navigateTo({
url: '/pages/product/detail/detail?id=100'
});

// 2. 关闭当前页面,跳转到新页面(不保留当前页面)
wx.redirectTo({
url: '/pages/index/index'
});

// 3. 跳转到tabBar页面,关闭其他所有非tabBar页面
wx.switchTab({
url: '/pages/user/user'
});

// 4. 关闭所有页面,跳转到新页面
wx.reLaunch({
url: '/pages/login/login'
});

// 5. 返回上一页(可指定返回层数)
wx.navigateBack({
delta: 1 // 返回1层,默认返回1层
});

组件

微信小程序官方提供了一系列基础组件,组件是视图层的基本组成单元,几乎所有组件都有各自定义的属性,可对组件的功能或样式进行修饰,便于快速搭建页面。

核心注意事项:所有组件与属性均为小写,以连字符连接;组件需使用正确的标签格式,包含开始标签、包裹内容和结束标签;组件嵌套有规则,如text标签内可嵌套text,view标签可嵌套所有组件。

常用基础组件实操

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- pages/index/index.wxml -->
<!-- 1. view组件:容器组件,用于包裹其他组件 -->
<view class="container">
<!-- 2. swiper组件:轮播图组件 -->
<swiper autoplay circular indicator-dots interval="3000">
<swiper-item wx:for="{{bannerList}}" wx:key="id">
<!-- 3. image组件:图片组件 -->
<image src="{{item.imgUrl}}" mode="widthFix" class="banner-img" /
</swiper-item>
</swiper>

<!-- 4. text组件:文本组件,仅支持嵌套text -->
<text class="title">商品列表</text>

<!-- 5. button组件:按钮组件 -->
<!-- 6. scroll-view组件:滚动视图组件 -->
<scroll-view scroll-y class="scroll-container">
<view class="product-item" wx:for="{{productList}}" wx:key="id">
<image src="{{item.imgUrl}}" mode="aspectFill" class="product-img" /<text class="product-name">{{item.name}}</text>
<text class="product-price">¥{{item.price}}</text>
</view>
</scroll-view>
</view>

API

微信小程序官方提供了一系列微信原生API,内置wx对象,通过wx对象可获取微信平台原生能力,覆盖网络请求、本地存储、设备信息、界面交互、导航等多种场景,API分为同步和异步两种,同步API后缀为Sync,异步API通过回调或Promise处理结果。

常用API实操

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 1. 本地存储(同步API)
// 存储数据
wx.setStorageSync('userInfo', { name: '张三', age: 20, gender: '男' });
// 获取数据
const userInfo = wx.getStorageSync('userInfo');
console.log('本地存储的用户信息', userInfo);
// 删除数据
wx.removeStorageSync('userInfo');
// 清空所有本地存储
wx.clearStorageSync();

// 2. 界面交互(异步API)
// 提示框
wx.showToast({
title: '操作成功',
icon: 'success', // 图标,可选success、loading、none
duration: 2000, // 显示时长,单位ms
mask: true // 是否显示透明蒙层,防止触摸穿透
});

// 确认弹窗
wx.showModal({
title: '提示',
content: '确定要删除这条数据吗?',
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定,执行删除操作');
} else if (res.cancel) {
console.log('用户点击取消,取消删除');
}
}
});

// 加载提示
wx.showLoading({
title: '加载中...',
mask: true
});
// 关闭加载提示(需在数据加载完成后调用)
setTimeout(() => {
wx.hideLoading();
}, 1000);

// 3. 获取设备信息
wx.getSystemInfo({
success: (res) => {
console.log('设备信息', res);
// 可获取设备型号、屏幕尺寸、系统版本等信息
}
});

事件系统

事件是视图层到逻辑层的通讯方式,页面交互通过定义的各种事件来驱动,事件可以绑定在组件上,触发事件时,会执行逻辑层中对应的事件处理函数,支持事件冒泡和事件捕获,遵循DOM标准。

事件绑定实操

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!-- pages/index/index.wxml 事件绑定 -->
<!-- 1. 基础事件绑定:bindtap,允许事件冒泡 -->
<view bindtap="tapHandler" data-name="小程序" data-id="100">点击我触发事件</view>

<!-- 2. 阻止事件冒泡:catchtap,阻止事件向上传播 -->
<view class="parent" bindtap="parentTap">
父容器
<view class="child" catchtap="childTap">子容器(阻止冒泡)</view>
</view>

<!-- 3. 事件捕获:capture-bind,事件捕获阶段触发 -->
<view capture-bind:tap="captureHandler">
捕获事件测试
</view>
// pages/index/index.js 事件处理函数
Page({
// 基础事件处理
tapHandler(e) {
// 通过e.currentTarget.dataset获取传递的参数
const { name, id } = e.currentTarget.dataset;
console.log('事件触发,传递的参数', name, id); // 小程序 100
},
// 父容器事件
parentTap() {
console.log('父容器事件触发');
},
// 子容器事件(阻止冒泡)
childTap() {
console.log('子容器事件触发');
// 由于使用catchtap,父容器事件不会触发
},
// 事件捕获处理
captureHandler() {
console.log('事件捕获阶段触发');
}
});

动态数据渲染

小程序采用数据驱动的开发模式,视图层的动态数据全部来自Page的data,通过setData修改data中的数据,视图会自动更新,核心支持数据绑定、列表渲染、条件渲染三种方式,均基于Mustache语法,即双大括号。

全场景实操示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!-- pages/index/index.wxml 动态渲染 -->
<!-- 1. 数据绑定:单向绑定,支持简单表达式 -->
<view>{{message}}</view>
<view>{{1 + 2}}</view>
<view>{{isShow ? '显示内容' : '隐藏内容'}}</view>
<image src="{{imgUrl}}" mode="widthFix" /<view style="color: {{primaryColor}}">动态样式绑定</view>

<!-- 2. 列表渲染:wx:for + wx:key,wx:key必加,提升渲染效率 -->
<view class="user-list">
<view wx:for="{{userList}}" wx:key="id" class="user-item">
索引:{{index}},姓名:{{item.name}},年龄:{{item.age}},性别:{{item.gender}}
</view>
</view>

<!-- 3. 条件渲染:wx:if/wx:elif/wx:else,可结合block批量控制 -->
<view wx:if="{{score >= 90}}">优秀</view>
<view wx:elif="{{score >= 60}}">及格</view>
<view wx:else>不及格</view>

<!-- 批量条件渲染:block不渲染实际DOM,仅用于包裹 -->
<block wx:if="{{isShowBlock}}">
<view>批量渲染内容1</view>
<view>批量渲染内容2</view>
<view>批量渲染内容3</view>
</block>

<!-- 4. 模板渲染:复用相同结构 -->
<template is="productTemplate" data="{{...product}}" /
// pages/index/index.js 数据管理与更新
Page({
data: {
message: 'Hello 小程序',
isShow: true,
imgUrl: 'https://test.com/avatar.png',
primaryColor: '#165DFF',
userList: [
{ id: 1, name: '张三', age: 20, gender: '' },
{ id: 2, name: '李四', age: 21, gender: '' },
{ id: 3, name: '王五', age: 22, gender: '' }
],
score: 85,
isShowBlock: true,
product: {
name: '测试商品',
imgUrl: 'https://test.com/product.jpg'
}
},
// 自定义方法修改数据驱动视图更新
changeData() {
this.setData({
message: 'Hello 小程序开发',
isShow: false,
score: 59,
primaryColor: '#FF7D00',
// 直接修改数组中的某一项
'userList[0].age': 25,
// 直接修改对象中的属性
'product.name': '修改后的商品名称'
});
}
});

代码包版本

小程序从开发到上线供普通用户访问,需经历四种版本,微信公众平台对版本管理有严格规则,不同版本对应不同的使用场景和权限,核心说明如下

版本类型 核心说明 适用人群
开发版本 使用开发者工具,可将代码上传到开发版本中。开发版本只保留每人最新的一份上传代码,点击提交审核可将代码提交至审核中版本,开发版本可删除,不影响线上版本和审核中版本。 开发人员
体验版本 可以选择某个开发版本作为体验版,并且选取一份体验版,用于内部测试验收。 测试人员、产品人员
审核中版本 只能有一份代码处于审核中,有审核结果后可以发布到线上,也可直接重新提交审核,覆盖原审核版本。 微信审核团队
线上版本 线上所有用户使用的代码版本,该版本代码在新版本代码发布后被覆盖更新。 所有用户

Taro开发

Taro核心介绍

Taro是一款跨端开发框架,使用Taro可只书写一套代码,再通过Taro的编译工具,将源代码分别编译出可以在不同端运行的代码,包括微信、支付宝、百度、抖音、快手等小程序平台,以及H5、App端。

Taro的核心优势的是模拟DOM和BOM,提供类Web的开发体验,同时拥有标准组件库和标准API,基于webpack打包处理,让前端开发者无需学习各平台原生语法,即可实现多端开发,大幅降低多端适配成本。

项目创建

Taro基于Node.js开发,需先安装Node.js,版本建议14及以上,核心通过Taro CLI创建项目,完整实操步骤如下,包含开发与生产两种模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 1. 全局安装Taro CLI(建议安装最新稳定版)
npm install -g @tarojs/cli

// 2. 验证安装是否成功,查看版本号
taro -v

// 3. 初始化Taro项目,按提示选择配置(框架选React/Vue,模板选基础模板)
taro init myApp

// 4. 进入项目目录
cd myApp

// 5. 安装项目依赖
npm install

// 6. 编译运行到指定平台(开发模式,热更新,监听文件修改)
// 微信小程序
npm run dev:weapp
// 支付宝小程序
npm run dev:alipay
// 百度小程序
npm run dev:swan
// 抖音小程序
npm run dev:tt
// H5端
npm run dev:h5

// 7. 生产环境编译(不监听文件修改,对代码进行压缩打包,用于上线)
// 微信小程序生产打包
npm run build:weapp
// 其他平台生产打包类似,替换对应的平台标识即可

// 8. 预览小程序
// 使用对应平台的开发者工具,打开项目目录下的dist目录,即可预览小程序效果

避坑小贴士:全局Taro CLI版本与项目本地版本需保持一致,否则会出现编译错误;若npm安装依赖失败,可使用cnpm或yarn替代npm。

项目结构

Taro项目结构遵循前端工程化原则,核心分为编译结果目录和源码目录,各平台的编译产物按文件夹拆分,便于管理,标准项目结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
├── dist/                # 编译结果目录,各平台产物按文件夹拆分
├── config/ # 项目编译配置目录
│ ├── index.js # 默认配置
│ ├── dev.js # 开发环境配置
│ └── prod.js # 生产环境配置
├── src/ # 源码目录,核心开发目录
│ ├── pages/ # 页面文件目录,按业务模块拆分
│ │ └── index/ # 首页目录
│ │ ├── index.jsx/tsx # 页面逻辑(React/Vue语法)
│ │ ├── index.config.js # 页面配置(对应原生json)
│ │ └── index.css/scss # 页面样式
│ ├── components/ # 自定义组件目录
│ ├── services/ # 接口请求层
│ ├── utils/ # 工具函数目录
│ ├── app.jsx/tsx # 项目入口文件
│ ├── app.config.js # 项目入口配置(对应原生app.json)
│ └── app.css/scss # 项目全局样式
├── project.config.json # 微信小程序项目配置
├── project.tt.json # 抖音小程序项目配置
├── project.swan.json # 百度小程序项目配置
├── project.qq.json # QQ小程序项目配置
├── babel.config.js # Babel配置
├── tsconfig.json # TypeScript配置(若使用TS)
├── .eslintrc # ESLint配置,代码规范检查
└── package.json # 项目依赖配置

语法对比

Taro支持React和Vue两种框架,其中React语法最常用,与微信原生小程序的开发语法差异较大,核心区别在于页面结构、数据绑定、事件处理等方面,以下是简单组件的两种写法对比,补充完整实操示例

原生小程序写法

1
2
3
4
5
6
7
8
// index.js 页面逻辑
Page({
data: {
name: 'World'
}
})
<!-- index.wxml 页面结构 -->
<view>Hello, {{name}}!</view>

Taro React写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/pages/index/index.jsx
import React, { useState } from 'react';
import { View, Text } from '@tarojs/components';
import './index.css';

// 首页组件
export default function Index() {
// 状态管理,替代原生Page的data
const [name, setName] = useState('World');

// 自定义方法:修改状态
const changeName = () => {
setName('Taro跨端开发');
};

return (
<View className="index-page">
{/* 数据绑定:单大括号,替代原生双大括号 */}
<Text onClick={changeName}>Hello, {name}!</Text>
</View>
);
}

// 页面配置,替代原生index.json
Index.config = {
navigationBarTitleText: 'Taro首页'
};

核心语法对比总结

开发场景 微信原生小程序 Taro React
页面基础结构 分js、wxml、wxss、json四个文件 单jsx文件,整合结构、逻辑、样式(或分离样式)
数据绑定 Mustache语法,双大括号 单大括号,遵循React语法
事件处理 bindtap、catchtap等 onClick、onChange等,遵循React事件命名
状态管理 Page.data + setData useState、useReducer、Redux等React状态管理方式
列表渲染 wx:for + wx:key 数组map方法 + key属性
条件渲染 wx:if、wx:elif、wx:else 逻辑与运算、三元表达式
页面配置 单独json文件 组件配置对象,如Index.config

携程小程序生态

多平台小程序适配

各平台的核心开发差异在于全局对象开发者工具

小程序类型 全局对象 核心开发者工具
微信小程序 wx 微信开发者工具
支付宝小程序 my 支付宝开发者工具
百度小程序 swan 百度智能小程序开发者工具
抖音小程序 tt 抖音开发者工具
快手小程序 ks 快手开发者工具
快应用 qa 快应用开发者工具

携程企业级基础建设

携程为小程序开发搭建了全链路的基础设施,覆盖应用框架、跨端方案、性能监控、发布系统、错误预警等,核心目标是提升开发效率、保障运行稳定性、优化用户体验

  • 跨端框架:基于Taro二次开发,适配携程的业务特性;
  • 性能监控:搭建了专属的性能监控系统,实时监控小程序的加载速度、渲染性能、接口耗时;
  • 错误预警:自动化错误预警方案,代码报错后及时推送至开发人员,快速定位问题;
  • 发布系统:定制化的发布流程,支持多平台一键发布、灰度发布、版本回滚;
  • 代码质量:代码覆盖率检测系统、ESLint/Prettier代码规范,保障团队开发的代码一致性。

携程Taro跨端解决方案

Taro跨端解决方案

携程在Taro的基础上,设计了模块化的跨端解决方案,核心思路是将不同的业务线拆分为独立的Taro模块(如机票、酒店、火车票、度假),通过模块组合快速生成不同的小程序项目,大幅提升业务迭代效率:

  1. 搭建Taro bundle仓库池,将各业务线(机票taro-flight、酒店taro-hotel、火车票taro-train)拆分为独立的Taro模块;
  2. 根据业务需求,将多个Taro模块组合打包,生成对应的小程序项目(如携程主小程序包含机票+酒店+火车票,度假独立小程序仅包含度假模块);
  3. 封装Taro公共基础文件,包含全局配置、通用组件、工具函数,所有业务模块均可复用,减少重复开发。

组合打包

这种方案的核心优势是高复用、低耦合,单个业务模块的更新无需重新编译整个项目,大幅提升了迭代效率,也符合携程多业务线、多平台的小程序业务特点。

学习总结

本次携程前端训练营的小程序开发课程,从基础认知原生开发,再到Taro跨端企业级生态,完成了小程序开发的全链路讲解,核心学习要点可总结为3点:

  1. 夯实原生基础:微信原生小程序是所有小程序开发的基础,重点掌握规范化项目结构、数据驱动视图、原生API/组件,这是后续跨端开发的核心;
  2. 掌握Taro跨端:Taro是解决多平台适配的核心工具,基于React/Vue语法,前端开发者可快速上手,重点掌握项目创建、编译运行、跨端适配
  3. 理解企业级实践:企业级小程序开发不仅是「功能实现」,更注重开发效率、代码质量、运行稳定性、业务复用,携程的模块化跨端方案和基础设施建设,为企业级小程序开发提供了优秀的参考。

小程序作为前端开发的主流方向之一,其核心是融合Web开发的效率和原生应用的体验,掌握原生开发和跨端框架的核心能力,结合企业级的实践思路,才能更好地应对实际业务中的开发需求。