微信小程序
数据绑定
在微信小程序中,数据绑定是通过 WXML 文件中的双大括号 {{}} 语法实现的,可以将 JavaScript 文件(.js)中定义的数据动态渲染到页面上。以下是一个完整的例子:
1. 数据定义(在 .js 文件中)
js
// app.js 或页面.js 中
Page({
data: {
message: "Hello Mini Program!", // 文本数据
showMessage: true, // 条件渲染
list: ["Apple", "Banana", "Orange"], // 列表数据
count: 0 // 动态更新数据
},
// 点击事件处理函数
toggleMessage: function() {
this.setData({
showMessage: !this.data.showMessage // 切换布尔值
});
},
// 数字递增函数
increment: function() {
this.setData({
count: this.data.count + 1
});
}
});
2. 数据绑定(在 .wxml 文件中)
html
<!-- 页面.wxml -->
<view>
<!-- 1. 基础文本绑定 -->
<text>{{message}}</text>
<!-- 2. 条件渲染 -->
<view wx:if="{{showMessage}}">
<text>Message is visible!</text>
</view>
<view wx:else>
<text>Message is hidden.</text>
</view>
<!-- 3. 列表渲染 -->
<view wx:for="{{list}}" wx:key="index">
<text>{{index + 1}}. {{item}}</text>
</view>
<!-- 4. 事件绑定更新数据 -->
<button bindtap="toggleMessage">Toggle Message</button>
<button bindtap="increment">Count: {{count}}</button>
</view>
3. 效果说明
-
文本绑定:页面会直接显示 "Hello Mini Program!"。
-
条件渲染 :点击 "Toggle Message" 按钮会切换显示
Message is visible!或Message is hidden.。 -
列表渲染 :自动渲染数组
["Apple", "Banana", "Orange"],显示为:text1. Apple 2. Banana 3. Orange -
动态更新:点击 "Count" 按钮时,数字会从 0 开始递增。
核心机制
- 数据驱动视图 :通过
this.setData()更新数据,小程序会自动重新渲染相关视图。 - 条件与循环 :
wx:if控制元素显示/隐藏,wx:for遍历数组生成列表。 - 事件绑定 :
bindtap绑定点击事件,调用.js中的函数。
事件绑定
微信小程序中的事件绑定通过 bind 或 catch 前缀实现,例如 bindtap(点击事件)、bindinput(输入事件)等。下面是一个完整的例子,涵盖常见事件类型:
1. 事件绑定示例(.wxml 文件)
html
<!-- 页面.wxml -->
<view>
<!-- 1. 点击事件(bindtap) -->
<button bindtap="handleClick">点击我</button>
<text>点击次数:{{clickCount}}</text>
<!-- 2. 输入事件(bindinput) -->
<input
bindinput="handleInput"
placeholder="输入内容"
value="{{inputText}}"
/>
<text>输入内容:{{inputText}}</text>
<!-- 3. 长按事件(bindlongpress) -->
<button bindlongpress="handleLongPress">长按我</button>
<text>{{longPressText}}</text>
<!-- 4. 阻止事件冒泡(catchtap) -->
<view bindtap="parentTap">
<text>父容器(点击会触发)</text>
<button catchtap="childTap">子按钮(点击不会冒泡)</button>
</view>
<!-- 5. 传递自定义参数(data-*) -->
<button
bindtap="handleCustomParam"
data-id="123"
data-info="hello"
>传递参数</button>
</view>
2. 事件处理逻辑(.js 文件)
js
// 页面.js
Page({
data: {
clickCount: 0,
inputText: "",
longPressText: ""
},
// 1. 点击事件处理
handleClick() {
this.setData({
clickCount: this.data.clickCount + 1
});
},
// 2. 输入事件处理(实时更新输入内容)
handleInput(e) {
this.setData({
inputText: e.detail.value
});
},
// 3. 长按事件处理
handleLongPress() {
this.setData({
longPressText: "长按触发!"
});
},
// 4. 事件冒泡示例
parentTap() {
console.log("父容器点击事件");
},
childTap() {
console.log("子按钮点击事件(不会触发父容器的tap)");
},
// 5. 获取自定义参数
handleCustomParam(e) {
const id = e.currentTarget.dataset.id; // 123
const info = e.currentTarget.dataset.info; // "hello"
console.log("参数:", { id, info });
}
});
3. 效果说明
-
点击事件
- 点击按钮时,
clickCount数值递增。 - 使用
bindtap绑定点击事件。
- 点击按钮时,
-
输入事件
- 输入框内容实时同步到
inputText。 - 通过
e.detail.value获取输入值。
- 输入框内容实时同步到
-
长按事件
- 长按按钮显示 "长按触发!"。
- 使用
bindlongpress绑定长按事件。
-
阻止事件冒泡
- 点击子按钮时,
catchtap会阻止事件冒泡到父容器。 - 点击父容器其他区域仍会触发
parentTap。
- 点击子按钮时,
-
传递自定义参数
- 通过
data-*属性传递参数(如data-id)。 - 在事件对象
e.currentTarget.dataset中获取参数。
- 通过
核心机制
-
事件类型 :常用事件包括
tap(点击)、input(输入)、longpress(长按)、touchstart(触摸开始)等。 -
事件对象 :通过
e.detail获取事件详细信息(如输入值、坐标)。 -
冒泡控制:
bind允许事件冒泡(如bindtap)。catch阻止事件冒泡(如catchtap)。
-
参数传递 :使用
data-*属性向事件处理函数传递自定义数据。
微信小程序的模板语法类指令
一、列表渲染指令
-
**
wx:for**用于循环渲染数组或对象,默认通过
{{item}}和{{index}}访问元素及索引。html<view wx:for="{{list}}">{{index}}: {{item}}</view> -
**
wx:for-item**自定义循环元素的变量名(默认
item)。html<view wx:for="{{list}}" wx:for-item="book">{{book.name}}</view> -
**
wx:for-index**自定义循环索引的变量名(默认
index)。 -
**
wx:key**指定列表项的唯一标识符(如
id或*this),优化渲染性能。
二、条件渲染指令
-
**
wx:if/wx:elif/wx:else**根据条件动态控制元素的显示与隐藏,通过条件判断直接操作 DOM 结构。
html<view wx:if="{{show}}">显示内容</view> <view wx:else>隐藏内容</view> -
**
hidden属性**通过布尔值控制元素显隐(仅切换 CSS 的
display属性),适用于频繁切换的场景。html<view hidden="{{isHidden}}">通过 hidden 属性控制显隐</view>
三、模板定义与引用指令
-
**
template标签**定义可复用的代码片段,通过
name属性命名模板。html<template name="msgItem"> <view>{{index}}: {{msg}}</view> </template> -
**
is属性**动态引用模板,结合
data属性传递所需数据。html<template is="msgItem" data="{{...item}}" /> -
动态选择模板
通过三元表达式动态渲染不同模板,例如:
html<template is="{{item % 2 === 0 ? 'even' : 'odd'}}" />
四、其他辅助指令
-
**
block标签**包裹多个元素但不渲染自身,常用于结合条件或循环指令。
html<block wx:if="{{flag}}"> <view>A</view> <view>B</view> </block>
总结
| 指令类型 | 核心指令/属性 | 作用场景 |
|---|---|---|
| 列表渲染 | wx:for, wx:key |
遍历数组/对象 |
| 条件渲染 | wx:if, hidden |
动态控制元素显隐 |
| 模板定义与引用 | template, is, data |
复用代码片段 |
| 辅助标签 | block |
包裹多元素且不渲染自身 |
注意事项
- 数据绑定 :所有属性值或内容需通过
{{}}绑定动态数据(如<input value="{{text}}" />),支持简单表达式(如{{num + 1}})。 - 性能优化 :列表渲染中必须使用
wx:key提升渲染效率。 - 模板复用 :
template适用于跨页面或组件复用复杂结构。
微信小程序的界面跳转
一、基础跳转方式
-
声明式导航(
<navigator>组件) -
基本语法 :通过
url属性指定目标页面路径,open-type定义跳转类型56。html<!-- 保留当前页面跳转(可返回) --> <navigator url="/pages/detail/detail" open-type="navigate">跳转详情页</navigator> <!-- 关闭当前页面跳转(不可返回) --> <navigator url="/pages/detail/detail" open-type="redirect">重定向跳转</navigator> -
参数传递 :通过 URL 查询字符串传递参数,目标页面在
onLoad中通过options接收68。html<navigator url="/pages/detail/detail?id=123&name=test">带参跳转</navigator>
-
-
编程式导航(API 调用)
-
常用 API:
方法 作用 特点 wx.navigateTo保留当前页面跳转,可返回 最多支持 10 层页面栈 wx.redirectTo关闭当前页面跳转,不可返回 页面栈减少一层 wx.switchTab跳转至 tabBar页面,关闭其他非tabBar页面仅适用于配置了 tabBar的页面wx.reLaunch关闭所有页面并打开新页面 重置页面栈 wx.navigateBack返回上一级或多级页面 通过 delta参数控制返回层级 -
代码示例:
js// 保留跳转(带参数) wx.navigateTo({ url: '/pages/detail/detail?key=value' }); // 关闭当前页跳转 wx.redirectTo({ url: '/pages/home/home' });
-
二、高级跳转场景
-
跨小程序跳转
-
实现方式 :使用
wx.navigateToMiniProgram,需在目标小程序的app.json中配置关联34。jswx.navigateToMiniProgram({ appId: '目标小程序AppID', path: 'pages/index/index', // 目标页面路径 success: () => console.log('跳转成功') }); -
限制:需目标小程序开启关联权限,且用户已授权。
-
-
H5 页面跳转小程序
-
步骤:
- 通过第三方平台(如天天外链)生成跳转链接,配置目标小程序路径和参数。
- 将链接嵌入 H5 页面,用户点击后触发微信内置浏览器跳转逻辑。
-
示例配置:
js// 生成跳转链接(第三方工具) const url = 'https://外链域名/path?appid=小程序ID&path=目标页面';
-
-
App 跳转小程序
-
条件:
- 已认证的开放平台账号可跳转任意合法小程序。
- 未认证账号仅支持跳转同一开放平台下的小程序。
-
实现 :调用微信 SDK 的
WXLaunchMiniProgram方法。
-
三、常见问题与注意事项
-
页面栈管理
- 使用
getCurrentPages()获取当前页面栈,避免超过 10 层导致跳转失败。 reLaunch会清空页面栈,慎用于高频操作场景。
- 使用
-
**
tabBar页面限制**switchTab仅支持跳转已在app.json的tabBar配置中声明的页面。- 跳转
tabBar页面时不可携带参数。
-
外部跳转兼容性
- H5 或 App 跳转需确保目标小程序的
app.json已配置通用链接(Universal Link)。 - 部分安卓机型需手动开启"允许从外部应用跳转"权限。
- H5 或 App 跳转需确保目标小程序的
四、最佳实践
-
统一路由管理
-
封装全局路由工具类,集中处理路径拼接、参数编码等逻辑。
js// utils/router.js export const navigateTo = (path, params) => { const query = new URLSearchParams(params).toString(); wx.navigateTo({ url: `${path}?${query}` }); };
-
-
安全性控制
- 对跳转参数进行合法性校验,防止注入攻击。
- 跨小程序跳转时校验目标
appId白名单。
-
性能优化
- 减少
navigateTo层级,复杂流程优先使用redirectTo或reLaunch。 - 预加载目标页面数据,提升跳转后渲染速度
- 减少
微信小程序的生命周期
一、应用生命周期
通过 App() 函数注册,在 app.js 中定义,核心函数包括:
-
onLaunch小程序初始化时触发(仅执行一次),用于获取启动参数或初始化全局数据。 -
onShow小程序启动或从后台进入前台时触发(如用户重新打开小程序)。 -
onHide小程序从前台进入后台时触发(如用户点击右上角关闭)。 -
onError脚本执行错误或 API 调用失败时触发,用于错误监控。
二、页面生命周期
在页面 .js 文件中定义,通过 Page() 函数注册,关键函数如下:
-
onLoad页面加载时触发(仅一次),用于获取页面参数或发起网络请求。 -
onShow页面显示/切入前台时触发(如切换回该页面)。 -
onReady页面初次渲染完成时触发(仅一次),用于操作 DOM 或执行交互逻辑。 -
onHide页面隐藏/切入后台时触发(如跳转至其他页面)。 -
onUnload页面销毁时触发(如关闭页面或路由跳转离开),用于清理定时器等资源。
三、组件生命周期
通过 Component() 函数注册,在组件 .js 中定义,主要函数包括:
-
created组件实例创建时触发,但尚未挂载到页面节点树。 -
attached组件被添加到页面节点树时触发,可访问页面数据。 -
detached组件从页面节点树移除时触发,用于资源释放。 -
pageLifetimes监听组件所在页面的生命周期(如页面显示/隐藏)。
四、运行机制与状态切换
- 冷启动
首次打开或销毁后重新启动,触发onLaunch。 - 热启动(后台切前台)
从后台恢复至前台,触发onShow。 - 挂起
后台持续 5 秒无操作后,JS 线程停止,保留内存状态。 - 销毁
长时间未使用(30 分钟)或系统资源不足时触发,完全终止运行。
生命周期执行顺序示例
text
应用启动 → onLaunch → 页面加载 → onLoad → onShow → onReady
切换后台 → 应用 onHide → 页面 onHide
重新进入 → 应用 onShow → 页面 onShow
销毁页面 → 页面 onUnload
注意事项
- 性能优化 :避免在
onShow中频繁执行耗时操作,优先使用onLoad初始化数据。 - 数据同步 :页面隐藏时(
onHide)保存临时数据,避免丢失。 - 组件复用 :利用
detached清理组件内事件监听,防止内存泄漏。
微信小程序的组件使用
一、组件核心概念
-
作用与优势
- 代码复用:封装 UI 和逻辑,避免重复开发。
- 独立性:组件拥有独立的数据、样式和生命周期,与页面解耦。
- 维护性:复杂业务拆分为多个组件,降低代码耦合度。
-
组件与页面的区别
特性 页面 组件 文件结构 包含 .json文件声明页面需在 .json中声明"component": true生命周期 onLoad,onShow等created,attached等使用方式 通过路由跳转访问 需在页面或父组件中引入
二、组件创建与使用
-
创建自定义组件
-
文件结构:
textcomponents/ my-component/ my-component.js // 组件逻辑 my-component.wxml // 组件模板 my-component.wxss // 组件样式 my-component.json // 组件配置 -
配置
my-component.json:json{ "component": true, "usingComponents": {} // 可嵌套其他组件 }
-
-
在页面中引入组件
-
声明组件 (页面
.json中):json{ "usingComponents": { "my-component": "/components/my-component/my-component" } } -
使用组件 (页面
.wxml中):html<my-component prop-a="{{value}}" bind:myevent="handleEvent" />
-
三、组件核心配置
-
数据与属性
-
内部数据 (
data):jsComponent({ data: { count: 0 } }) -
外部属性 (
properties):支持类型校验和默认值:jsComponent({ properties: { propA: { type: String, value: 'default' }, propB: Number // 简写 } })
-
-
事件通信
-
触发事件(子组件向父组件):
js// 子组件中触发 this.triggerEvent('myevent', { detail: data }, { bubbles: false }) -
监听事件(父组件中):
html<!-- 父组件.wxml --> <my-component bind:myevent="handleEvent" />
-
-
插槽(Slot)
-
默认插槽:
html<!-- 组件模板.wxml --> <view class="container"> <slot></slot> </view> <!-- 使用组件 --> <my-component> <text>插入的内容</text> </my-component> -
具名插槽:
html<!-- 组件模板.wxml --> <slot name="header"></slot> <slot name="footer"></slot> <!-- 使用组件 --> <my-component> <text slot="header">头部内容</text> <text slot="footer">底部内容</text> </my-component>
-
四、高级功能
-
组件间关系
-
定义关系 (
relations):jsComponent({ relations: { './child-component': { type: 'child', linked(target) { console.log('子组件已链接', target) } } } }) -
访问关联组件 :通过
this.getRelationNodes('./child-component')。
-
-
外部样式类
-
暴露样式类 (组件
.js中):jsComponent({ externalClasses: ['custom-class'] // 允许外部传入样式类 }) -
使用外部样式(父组件中):
html<my-component custom-class="my-style" />
-
-
生命周期
生命周期 触发时机 created组件实例刚创建(不能调用 setData)attached组件完全初始化并插入页面 DOM 树 detached组件从页面 DOM 树移除
五、常见问题与解决
| 问题场景 | 解决方案 |
|---|---|
| 组件样式不生效 | 检查组件 .json 是否声明 "styleIsolation": "apply-shared"(启用样式隔离) |
| 父组件无法监听子组件事件 | 确认 triggerEvent 的第三个参数未设置 bubbles: false(默认向上冒泡) |
| 插槽内容渲染异常 | 确保组件 .wxml 中正确使用 <slot name="xxx"> 并与使用端 slot 属性匹配 |
| 组件间数据不同步 | 使用 observers 监听属性变化:properties: { propA: { observer: function } } |
六、最佳实践
-
性能优化
-
避免在
attached生命周期中执行耗时操作。 -
使用
pureDataPattern标记纯数据字段,减少不必要的渲染:jsComponent({ options: { pureDataPattern: /^_/ // 以 _ 开头的字段为纯数据 }, data: { _internalData: '不参与渲染' } })
-
-
组件复用性设计
-
通过
behaviors复用代码逻辑:js// behavior.js module.exports = Behavior({ methods: { sharedMethod() { /* ... */ } } }) // 组件中引入 Component({ behaviors: [require('./behavior.js')] })
-
微信小程序的传值
一、页面间传值
1. URL 参数传递
-
适用场景:页面跳转时传递简单参数(如 ID)。
-
实现方式:
js// 跳转时传参(发送方) wx.navigateTo({ url: '/pages/detail/detail?id=123&name=test' }) // 接收参数(接收方 detail 页面的 onLoad 函数) onLoad(options) { const { id, name } = options // id='123', name='test' } -
注意 :参数需拼接为字符串,复杂数据需用
JSON.stringify序列化。
2. 本地存储
-
适用场景:跨页面持久化数据(如用户 Token)。
-
实现方式:
js// 存储数据 wx.setStorageSync('key', { a: 1 }) // 读取数据(任意页面) const data = wx.getStorageSync('key') -
注意 :避免存储过大或敏感数据,异步 API 可用
wx.setStorage。
二、组件间传值
1. 父传子:Properties
-
适用场景:父组件向子组件传递静态或动态数据。
-
实现方式:
html<!-- 父组件使用子组件 --> <child-component prop-a="{{value}}" /> <!-- 子组件定义 properties --> Component({ properties: { propA: { type: String, value: '默认值' } } })
2. 子传父:自定义事件
-
适用场景:子组件向父组件传递数据或触发行为。
-
实现方式:
js// 子组件触发事件 this.triggerEvent('eventName', { data: 123 }) // 父组件监听事件 <child-component bind:eventName="handleEvent" /> // 父事件处理函数 handleEvent(e) { const data = e.detail.data // 123 }
3. 兄弟组件传值
- 方法一:通过父组件中转(结合 Properties + 事件)。
- 方法二:使用全局事件总线(需自行封装或使用库)。
三、全局数据管理
1. 全局变量(app.js)
-
适用场景:多页面共享数据(如用户信息)。
-
实现方式:
js// app.js 中定义 App({ globalData: { token: 'xxxx' } }) // 任意页面或组件获取 const app = getApp() console.log(app.globalData.token)
2. 状态管理工具
- 推荐库 :
wechat-weapp-redux、mobx-miniprogram。 - 适用场景:复杂应用的多组件状态同步。
四、其他传值方式
1. 页面栈传值
-
适用场景:返回上一页时传递数据。
-
实现方式:
js// 获取页面栈实例 const pages = getCurrentPages() const prevPage = pages[pages.length - 2] // 上一页实例 // 修改上一页数据 prevPage.setData({ backData: '123' }) // 返回上一页 wx.navigateBack()
2. 通过 Dataset 传递
-
适用场景:事件触发时传递元素自定义数据。
-
实现方式:
html<view data-id="123" bindtap="handleTap"></view> <script> handleTap(e) { const id = e.currentTarget.dataset.id // '123' } </script>
五、最佳实践总结
| 场景 | 推荐方法 | 注意事项 |
|---|---|---|
| 简单页面跳转传参 | URL 参数 | 数据量小,避免复杂结构 |
| 父子组件通信 | Properties + 自定义事件 | 避免滥用双向绑定 |
| 跨页面持久化数据 | 本地存储(wx.setStorageSync) |
定期清理过期数据 |
| 全局共享状态 | app.globalData 或状态管理库 |
复杂项目优先使用 Redux/MobX |
| 兄弟组件通信 | 父组件中转或全局事件 | 结构复杂时考虑状态管理工具 |
关键注意事项
- 性能优化:避免频繁传递大数据,优先通过 ID 查询详情。
- 数据安全:敏感数据(如密码)禁止明文存储或传递。
- 内存管理 :页面销毁时(
onUnload)及时清理无用数据。
微信登录流程
一、流程图解
二、分步流程说明
-
用户触发登录操作
用户点击登录按钮,小程序前端调用
wx.login()接口获取临时登录凭证code,有效期 5 分钟。 -
发送 code 至开发者服务器
小程序通过 HTTPS 请求将
code发送至开发者服务器,用于换取用户唯一标识openid和会话密钥session_key。 -
换取 session_key 和 openid
开发者服务器调用微信接口
https://api.weixin.qq.com/sns/jscode2session,提交以下参数:appid:小程序 IDsecret:小程序密钥js_code:接收到的codegrant_type:固定为authorization_code
微信服务器返回openid(用户唯一标识)和session_key(会话密钥)。
-
生成自定义登录态
开发者服务器根据业务需求生成自定义登录态(如 JWT Token),并与
openid绑定存储至数据库或缓存系统。 -
返回 Token 至小程序
开发者服务器将 Token 返回给小程序前端,前端通过
wx.setStorageSync存储至本地缓存,后续请求携带 Token 验证身份。
三、关键注意事项
-
安全性要求
session_key严禁传输至客户端,仅用于服务端解密用户敏感数据(如手机号)。- Token 需设置有效期,建议结合
session_key过期时间(默认 30 分钟)。
-
用户信息获取
- 若需获取用户昵称、头像等,需调用
wx.getUserProfile并引导用户授权。 - 加密数据(如
encryptedData)需在服务端用session_key解密。
- 若需获取用户昵称、头像等,需调用
-
登录态维护
- 建议在
app.globalData或本地缓存中存储 Token,定期检查过期时间并自动续期。
- 建议在
四、常见问题处理
| 问题 | 解决方案 |
|--------------------|------------------------------|---|
| code 失效(超时/重复使用) | 重新调用 wx.login() 获取新 code | |
| session_key 泄露风险 | 限制接口调用频率,避免明文传输敏感数据 |
| 多端登录冲突 | 基于 openid 绑定设备标识,强制下线旧设备 |
微信支付流程
一、流程图解
二、分步流程说明
-
前置条件
- 小程序需完成企业认证,并关联微信支付商户号(主体一致)
- 开发者服务器需配置
appid、mch_id(商户号)、API 密钥等敏感信息
-
核心步骤
① 用户下单
- 用户在小程序内选择商品,点击「支付」按钮触发支付流程
- 小程序前端调用
wx.login()获取code,发送至后端换取用户openid(用户唯一标识)
② 生成预付单
-
开发者服务器调用微信支付「统一下单接口」,提交以下参数:
openid(用户标识)body(商品描述)total_fee(金额,单位为分)notify_url(支付结果回调地址)
-
微信支付返回
prepay_id(预付单标识)和签名参数(paySign、nonceStr等)
③ 调起支付控件
-
小程序前端通过
wx.requestPayment调起支付界面,携带以下参数:timeStamp(时间戳)nonceStr(随机字符串)package(格式:prepay_id=xxx)signType(签名类型,默认MD5或HMAC-SHA256)paySign(服务端生成的签名)
④ 支付结果处理
- 支付成功:微信支付异步通知开发者服务器(需验证签名和金额一致性)
- 支付失败:前端显示错误提示(如余额不足、网络异常等)
三、前端代码案例
用户触发支付按钮
js
// pages/pay/pay.js
Page({
handlePayment() {
// 1. 获取用户openid(需提前登录)
const openid = wx.getStorageSync('openid');
// 2. 向后端请求支付参数
wx.request({
url: 'https://your-api.com/create-pay-order',
method: 'POST',
data: {
productId: '123', // 商品ID
totalFee: 100, // 金额(单位:分)
openid: openid // 用户唯一标识
},
success: (res) => {
// 3. 接收后端返回的支付参数
const payParams = res.data;
this.launchPayment(payParams);
},
fail: (err) => {
wx.showToast({ title: '订单创建失败', icon: 'none' });
}
});
},
// 调起微信支付
launchPayment(payParams) {
wx.requestPayment({
timeStamp: payParams.timeStamp, // 时间戳(秒级)
nonceStr: payParams.nonceStr, // 随机字符串
package: payParams.package, // prepay_id=xxx
signType: 'RSA', // 2025年起强制使用RSA签名
paySign: payParams.paySign, // 服务端生成的签名
success: (res) => {
// 4. 支付成功处理
wx.showToast({ title: '支付成功' });
this.checkOrderStatus();
},
fail: (err) => {
// 5. 支付失败处理
const errMsg = err.errMsg || '支付中断';
wx.showToast({ title: errMsg, icon: 'none' });
}
});
},
// 查询最终订单状态(兜底逻辑)
checkOrderStatus() {
wx.request({
url: 'https://your-api.com/check-order',
method: 'POST',
data: { orderId: 'ORDER_123' },
success: (res) => {
if (res.data.status === 'SUCCESS') {
wx.navigateTo({ url: '/pages/success/success' });
}
}
});
}
});
四、核心代码说明
1. 支付参数获取
| 参数 | 来源 | 示例值 |
|---|---|---|
timeStamp |
服务端生成(秒级时间戳) | "1717027890" |
nonceStr |
服务端生成的随机字符串 | "a1b2c3d4e5f6g7h8" |
package |
微信返回的预付单标识 | "prepay_id=wx1234567890" |
signType |
固定为 RSA(2025 年强制要求) |
"RSA" |
paySign |
服务端使用商户私钥生成的 RSA 签名 | "MIIEvQIBADANBg..." |
2. 安全校验要点
js
// 支付参数校验示例(前端辅助验证)
function validateParams(payParams) {
const requiredFields = ['timeStamp', 'nonceStr', 'package', 'paySign'];
return requiredFields.every(field => payParams[field]);
}
// 调用支付前验证参数
if (!validateParams(payParams)) {
wx.showToast({ title: '支付参数异常', icon: 'none' });
return;
}
五、支付流程注意事项
-
签名安全
- 服务端必须使用 微信商户平台 的 API 私钥生成
paySign - 禁止在前端生成签名或传输私钥
- 服务端必须使用 微信商户平台 的 API 私钥生成
-
支付结果兜底
- 即使收到支付成功回调,仍需通过
checkOrderStatus查询最终状态 - 处理场景:网络中断、用户关闭小程序等异常
- 即使收到支付成功回调,仍需通过
-
用户体验优化
js// 支付超时处理(30秒限制) setTimeout(() => { wx.showToast({ title: '支付超时,请重试', icon: 'none' }); }, 30000); -
错误码处理
js// 常见错误码处理 const errorMap = { 'requestPayment:fail cancel': '用户取消支付', 'requestPayment:fail no auth': '未授权支付功能' }; wx.requestPayment({ // ... fail: (err) => { const message = errorMap[err.errMsg] || '支付失败'; wx.showToast({ title: message, icon: 'none' }); } });
六、测试建议
-
沙箱环境
js// 测试环境开关 const isTestEnv = true; // 上线前设为false const API_BASE_URL = isTestEnv ? 'https://test.your-api.com' : 'https://prod.your-api.com';
微信小程序分包
一、分包背景与目的
-
核心限制
- 整个小程序所有分包大小不超过
30M(服务商代开发的小程序不超过20M) - 单个分包/主包大小不能超过
2M 独立分包可独立运行,无需依赖主包加载
- 整个小程序所有分包大小不超过
-
主要优势
- 优化首次启动速度,仅下载主包36
- 支持多团队协作开发,按功能模块拆分代码27
- 突破主包体积限制,扩展小程序功能16
二、分包项目构成
- 目录结构示例
text
├── app.js # 主包入口文件
├── app.json # 分包配置(含 subpackages 字段)
├── pages/ # 主包页面(含 TabBar 页面)
│ ├── index
│ └── profile
├── subPackage1/ # 分包1
│ └── pages/
│ ├── cart
│ └── detail
└── subPackage2/ # 分包2
└── pages/
├── order
└── payment
- 主包 :必须包含启动页(如
pages/index)和 TabBar 页面 - 分包:独立目录存放页面、组件及私有资源
- 配置文件
app.json
json
{
"pages": ["pages/index", "pages/profile"],
"subpackages": [
{
"root": "subPackage1", // 分包根目录
"name": "shopModule", // 分包别名(可选)
"pages": ["pages/cart", "pages/detail"],
"independent": false // 是否独立分包
},
{
"root": "subPackage2",
"pages": ["pages/order", "pages/payment"]
}
]
}
root:分包根目录路径independent:设置为true时,分包可独立运行
三、分包加载规则与限制
-
加载规则
- 启动小程序时仅下载主包,访问分包页面时动态加载对应子包
- 独立分包首次访问时直接加载,无需主包依赖
-
体积限制
类型 大小限制 说明 主包 ≤ 2MB 含公共资源和 TabBar 页面 单个分包 ≤ 2MB 独立分包也需遵守 所有分包总和 整个小程序所有分包大小不超过 30M(服务商代开发的小程序不超过 20M) -
预加载分包
- 通过
preloadRule配置提前加载高频使用的分包
- 通过
json
{
"preloadRule": {
"pages/index": {
"network": "all",
"packages": ["subPackage1"] // 访问主包 index 页时预加载分包1
}
}
}
四、分包开发注意事项
-
路径配置
- 分包内页面路径需相对于
root目录(如subPackage1/pages/cart) - 跨分包跳转需使用绝对路径:
/subPackage1/pages/cart
- 分包内页面路径需相对于
-
资源引用
- 分包私有资源(如图片、样式)需存放于分包目录内
- 公共资源建议放置在主包,避免重复打包
-
常见错误
- TabBar 页面放在分包中:必须保留在主包
- 分包路径配置错误:导致页面无法加载或白屏
五、优化策略
-
公共资源提取
- 将通用组件、工具库(如
utils)放置在主包 - 使用
npm或Vant等第三方库时,优先选择按需加载
- 将通用组件、工具库(如
-
独立分包使用场景
- 营销活动页、支付流程等高频独立功能
- 示例:独立分包中配置
"independent": true实现快速启动
-
分包大小监控
- 通过开发者工具「代码依赖分析」检测分包体积
- 超限解决方案:压缩图片、删除冗余代码、拆分更小子包
微信小程序 npm 构建详解(以 Vant Weapp 为例)
一、构建流程
-
初始化 npm 项目
bashcd /your-project-path # 进入项目根目录 npm init -y # 自动生成 package.json :ml-citation{ref="4,6" data="citationList"}- 云开发项目需进入
miniprogram子目录执行初始化。
- 云开发项目需进入
-
安装 Vant Weapp
bashnpm i @vant/weapp -S --production -
配置文件调整
-
删除
app.json中的"style": "v2":避免基础组件样式冲突。 -
修改
project.config.json:json{ "setting": { "packNpmManually": true, "packNpmRelationList": [{ "packageJsonPath": "./package.json", "miniprogramNpmDistDir": "./miniprogram/" # 指向项目根目录 :ml-citation{ref="1,4" data="citationList"} }] } }
-
-
构建 npm
- 微信开发者工具中点击 工具 > 构建 npm ,成功生成
miniprogram_npm目录。
- 微信开发者工具中点击 工具 > 构建 npm ,成功生成
二、Vant Weapp 集成
-
引入组件
-
全局配置(
app.json) :json{ "usingComponents": { "van-button": "@vant/weapp/button/index" # 路径包含 miniprogram_npm :ml-citation{ref="2,5" data="citationList"} } } -
页面级配置(页面
.json文件) :按需引入减少体积57。
-
-
全局样式加载
css/* app.wxss */ @import '/miniprogram_npm/@vant/weapp/common/index.wxss'; # 引入 Vant 基础样式 :ml-citation{ref="1,6" data="citationList"} -
组件使用示例
html<!-- 页面.wxml --> <van-button type="primary" bind:click="handleClick">提交</van-button>
三、常见问题与解决
| 问题 | 解决方案 |
|---|---|
构建后无 miniprogram_npm 目录 |
检查 project.config.json 的 miniprogramNpmDistDir 路径是否匹配项目结构 |
npm install 报错权限不足** |
以管理员身份运行开发者工具,或手动创建 package.json 后重试 |
| 组件样式不生效 | 确认已删除 app.json 的 "style": "v2" 并正确引入全局样式文件 |
**提示 Component not found** |
检查组件路径是否为 @vant/weapp/xxx/index(构建后自动映射到 miniprogram_npm) |
四、最佳实践
-
版本控制
- 固定依赖版本(如
@vant/weapp@2.15.0),避免自动升级导致兼容性问题。 - 定期执行
npm outdated检测更新。
- 固定依赖版本(如
-
分包优化
- 主包存放公共组件,独立分包单独声明依赖(需在分包目录创建
package.json)。
- 主包存放公共组件,独立分包单独声明依赖(需在分包目录创建
-
性能监控
- 使用开发者工具 代码体积分析 功能,对超过 2MB 的分包进行代码拆分或压缩。