在移动互联网流量格局中,小程序凭借免安装、近原生体验、平台流量扶持、开发成本可控的核心优势,成为企业级前端业务的重要载体。本文围绕微信原生小程序开发、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开发的效率和原生应用的体验,掌握原生开发和跨端框架的核心能力,结合企业级的实践思路,才能更好地应对实际业务中的开发需求。