速通-微信小程序 3Day
紧接前文,搭配有助于快速,巩固/学习!话不多说开始!
经过前面几篇的学习,好简单,最起码对于做过前端Vue 开发,小程序前后端 so so easy!
页面导航🧭
小程序页面导航是实现页面 跳转 的核心能力
分为 声明式导航 WXML 标签实现,无 JS 逻辑 和 编程式导航 JS API 实现,支持逻辑前置处理 两大类;
两类方式均需区分 Tab 页面 和 非 Tab 页面 的导航规则;
-
Tab 页面 在
app.json的tabBar.list中配置的页面首页、我的...无法通过navigateBack返回; -
非 Tab 页面 未在
tabBar中配置的页面,如商品详情、订单详情...属于页面栈管理,跳转后 保留 原页面
可返回,最多保留 10 层页面栈;
以下是完整实战解析:
声明式导航🔉
通过 <navigator> 组件 实现跳转,适合 无前置逻辑 简单跳转,通过 open-type 属性控制跳转类型;
小程序声明式导航的核心场景分为 跳普通页面、跳 tabBar 页面、页面后退
- 默认-普通页面
open-type="navigate" - 底部-tabBar 页面
open-type="switchTab" - 页面「后退 / 返回」
open-type="navigateBack" delta="后退层数,默认 1" - 重定向普通页面替换当前页面,无返回按钮,
open-type="redirect"
导航到 tab页面
- 核心属性:
url必填,tabBar 页面路径 open-type="switchTab"必填,不可省略url只能填写tabBar页面的 基础路径,不能携带任何参数会失效!- 目标页面,必须先在小程序根目录的
app.json中配置在tabBar.list数组中; - 跳转后会替换页面栈,左上角无「返回」按钮,❌不支持返回到上一级页面;
<navigator url="tabBar 页面路径" open-type="switchTab" >
跳转到 tabBar页面
</navigator>
导航非 tab页面
- 核心属性:
url必填,目标页面路径 open-type="navigate"(可省略,默认值)- 路径规则:支持 绝对路径
从根目录/开始或 相对路径 可携带 URL 参数?k=v&k2=v2 - 跳转后页面左上角会显示「返回」按钮, ✅支持返回到上一级页面;
<navigator url="普通页面路径">
跳转到 普通页面
</navigator>
后退导航
- 核心属性:
open-type="navigateBack"必填 、delta="后退层级数"可选,默认值1 - 关键注意:无需配置
url属性(配置也会失效),后退的层级由delta控制; - 从当前页面回退到页面栈中已存在的页面,
delta=1表示返回上一级;
<navigator open-type="navigateBack">
返回上一页(默认delta=1)
</navigator>
编程式导航⌨️
编程式导航 是小程序通过 JS API 函数 实现页面跳转的方式;
核心优势是支持前置逻辑处理 如登录验证、表单校验、数据提交
- 导航到 Tab 页面:
wx.switchTab({object:object}) - 导航非 Tab 页面:
wx.navigateTo({object:object}) - 重定向普通页面:
wx.redirectTo({object:object}) - 后退导航:
wx.navigateBack({object:object})
导航函数:大致参数:
| 属性 | 类型 | 是否必选 | 说明 |
|---|---|---|---|
| url | string | 是 | 需要跳转,页面路径, Tab路径后不能带参数 非 tabBar 页面的路径,路径后可以带参数 |
| success | function | 否 | 接口调用成功的回调函数 |
| fail | function | 否 | 接口调用失败的回调函数 |
| complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
后退导航: 大致参数: 小程序中函数回调基本都类似,success\fail\complete
| 属性 | 类型 | 默认值 | 是否必选 | 说明 |
|---|---|---|---|---|
| delta | number | 1 | 否 | 返回页面数,delta 大于现有页面数,则返回首页; |
home.wxml 首页Tab
<view>
编程式导航:
<button bindtap="handleGoDetail" style="width: 100%;" >跳转到详情页(普通页面)</button>
<button bindtap="handleReDetail" style="width: 100%;" >重定向详情页(普通页面)</button>
<button bindtap="handleGoToMessage" style="width: 100%;" >跳转到“消息”(tabBar页面)</button>
</view>
message.wxml 消息Tab
<view>
编程式导航:
<button bindtap="handleback" style="width: 100%;" >返回上一页 (Tab页无效) </button>
</view>
detail.wxml 详情普通页面
<view>
编程式导航:
<button bindtap="handleback" style="width: 100%;" >返回上一页(默认delta=1,重定向无效~)</button>
</view>
导航到 tab页面
wx.switchTab 仅能跳转至 app.json 的 tabBar.list 中配置的页面:如首页、我的
-
跳转后 关闭所有非 Tab 页面,页面栈仅保留 Tab 页面,无法通过
navigateBack返回; -
路径不能携带参数,若需传参,需用本地存储
wx.setStorageSync 本地存储中转;
Page({
/*** 页面的初始数据 */
data: { },
// 页面JS:从首页 跳转到 商品详情页 非Tab页)
handleGoDetail(){ },
// 页面JS:从首页 重定向 到商品详情页 非Tab页)
handleReDetail(){ },
// 页面JS:从首页 切换到 Tab消息页面
handleGoToMessage(){
// 前置逻辑:验证用户是否登录(实战常用)
// 未登录则跳转到登录页(非Tab页)
// 核心:跳转Tab消息页
wx.switchTab({
url: '/pages/message/message',
success: () => { console.log('跳转到“消息Tab” 成功'); },
fail: (err) => { console.error('跳转失败:', err); },
})
}
})
导航非 tab页面
wx.navigateTo 跳转后原页面保留在 页面栈 中,新页面入栈,最多保留 10 层页面栈;
- 支持 URL 携带参数
适合列表→详情传值,新页面可通过navigateBack返回原页面
wx.redirectTo 跳转后 关闭当前页面 并出栈,新页面入栈,无法返回原页面;
Page({
/*** 页面的初始数据 */
data: { },
// 页面JS:从首页 跳转到 商品详情页 非Tab页)
handleGoDetail(){
wx.navigateTo({
url: '/pages/detail/detail',
success: () => { console.log('跳转到“详情页面” 成功'); },
fail: (err) => { console.error('跳转失败:', err); },
})
},
// 页面JS:从首页 重定向 到商品详情页 非Tab页)
handleReDetail(){
wx.redirectTo({
url: '/pages/detail/detail',
success: () => { console.log('跳转到“详情页面” 成功'); },
fail: (err) => { console.error('跳转失败:', err); },
})
},
// 页面JS:从首页 切换到 Tab消息页面
handleGoToMessage(){ }
})
后退导航
wx.navigateBack 通过 delta 参数控制后退层数
默认 delta: 1,若delta超过页面栈总数,仅返回页面栈最底层,通常-首页;
Page({
/*** 页面的初始数据 */
data: { },
// 页面JS:返回上一个页面;
handleback(){
//默认delta=1
// wx.navigateBack();
wx.navigateBack({ delta: 1 });
},
})
导航传参📠
⚠️⚠️⚠️注意:Tab 页传参禁止 URL 拼接
url仅能是 Tab 页路径,不能拼接参数,强行拼接会被忽略,必须用本地存储中转;
声明式导航传参
通过 <navigator> 的 url 属性拼接参数 实现,适合无前置逻辑的简单传参;
核心是 URL 查询字符串格式: 路径?键1=值1&键2=值2
<!-- 跳转到详情页,传递 数字 和 字符串 -->
<navigator url="/pages/detail/detail?k=540&k2='参数传递2'" open-type="navigate" >
跳转到详情页,参数传递
</navigator>
在目标页面的 onLoad 生命周期中,通过 **options参数 ** 获取传递的参数 参数默认是字符串类型
Page({
/**
* 页面加载时接收参数
* @param {Object} options - 导航传递的参数对象
*/
onLoad(options) {
console.log('接收的参数:', options);
// 输出:{ k: "540", k2: "参数传递2" }
// 类型转换:数字参数需手动转Number(默认是字符串)
const k = Number(options.k);
const k2 = options.k2;
// 赋值到data 供页面渲染
}
})
复杂数据类型:
URL 仅支持传递字符串, 复杂数据需先,在 data:{ 中定义数据 }
通过 JSON.stringify() 序列化,接收方再通过JSON.parse()反序列化;
<!-- 先在JS的 data 中定义复杂数据,再拼接序列化后的字符串 -->
<navigator url="/pages/detail/detail?detailstr={{detailstr}}" open-type="navigate">
跳转到详情页,复杂数据传递
</navigator>
发送方页面 JS
Page({
data: {
// 原始复杂数据(对象)
detailstr: {
orderId: 'O20260205001',
goodsList: [{ id: 1001, count: 2 }, { id: 1002, count: 1 }],
},
detailInfoStr: '' // 序列化后的字符串
},
onLoad() {
this.setData({
// 序列化复杂数据为字符串(需转义特殊字符,避免URL解析错误)
detailstr: encodeURIComponent(JSON.stringify(this.data.detailstr))
});
}
})
接收方页面 JS
Page({
onLoad(options) {
// 接受复杂数据类型
if(options.detailstr != null){
const details = decodeURIComponent(options.detailstr);
const detailInfo = details==null?"":JSON.parse(details);
console.log('接收的复杂数据:', detailInfo);
}
}
})
编程式导航传参
通过 wx.navigateTo/wx.redirectTo 等 API 实现,支持前置逻辑处理
传参方式与声明式一致,且新增 **eventChannel事件通道 ** 传递复杂数据 无需序列化
<!-- 发起方页面WXML,绑定事件并传递初始参数 -->
<button bindtap="handleGoToDetailParam" data-k1="1">
查看详情(编程式传参)
</button>
Page({
// 点击按钮触发编程式导航
handleGoToDetailParam(e) {
// 获取点击的ID(从事件对象中获取)
const k1 = e.currentTarget.dataset.k1;
// 编程式跳转,URL拼接参数,动态拼接参数;
wx.navigateTo({
url: `/pages/detail/detail?k1=${k1}`,
success: () => { console.log('跳转成功'); }
});
}
})
与声明式一致,在 onLoad 的 options 中获取参数:
Page({
onLoad(options) {
const k1 = Number(options.k1);
console.log('接受传递过来的参数ID:', k1,);
}
})
eventChannel 事件通道
对于熟悉/了解过 Vue的朋友来说,这个应该不会陌生… Vue 项目工程化
eventChannel 小程序页面间事件通信机制,可直接传递 对象/数组,无需序列化,适合复杂数据场景
// 发起方页面JS
Page({
handleGoToDetailEvent() {
wx.navigateTo({
url: '/pages/detail/detail',
success: (res) => {
// 获取事件通道,向目标页发送数据
res.eventChannel.emit('sendParam', {
orderId: '123',
goodsList: [{ id: 1001, count: 2 }]
});
}
});
}
})
// pages/detail/detail.js 接收方页面JS
Page({
onLoad() {
// 获取事件通道,监听发起方的事件
const eventChannel = this.getOpenerEventChannel();
eventChannel.on('sendParam', (data) => {
console.log('通过eventChannel接收的数据:', data);
});
}
})
页面事件📌
微信小程序的 页面事件,这类事件是小程序页面级别的核心回调,
写在页面 .js 文件的 Page({}) 配置中(与 data 同级),区别于组件的:点击/绑定事件
- 主要分为 页面生命周期事件 页面从创建到销毁的核心回调)
- 页面特殊交互事件 下拉刷新、上拉触底等业务常用)
⏬下拉刷新
下拉刷新 移动端专有名词,通过手指在屏幕上的下拉滑动操作,从而 重新加载页面数据的行为。
首先:开启下拉刷新: 全局开启、页面级开启(推荐),仅当前页面生效;
其次:编写刷新逻辑,页面 .js onPullDownRefresh 生命周期函数;
⚠️注意:需要手动,停止下拉刷新 wx.stopPullDownRefresh();
开启下拉刷新
全局开启:在 app.json 的 window 配置中设置,所有页面默认生效,
{
"window": {
"enablePullDownRefresh": false, // 不建议,全局开启,可以设置 false,在特定页面设置true
"backgroundTextStyle": "dark", // 下拉加载图标的颜色(dark/light)
"backgroundColor": "#f5f5f5" // 下拉时露出的背景色
}
}
页面级开启:在目标页面的 .json 中配置,仅当前页面生效(优先级高于全局)
{
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}
编写刷新逻辑
在页面的 onPullDownRefresh 生命周期函数中处理刷新逻辑
必须调用 wx.stopPullDownRefresh() 停止刷新动画 否则加载图标会一直显示;
示例DEMO: 在页面的 wxml 中有如下的 UI 结构,点击按钮可以让 count 值自增 +1
在触发页面的下拉刷新事件的时候,要把 count 的值重置为 0;
<view> count 值为: {{count}} </view>
<button bindtap="countAdd">+1</button>
Page({
/*** 页面的初始数据 */
data: { count: 0, },
// +1 按钮的点击事件处理函数
countAdd(){ this.setData({ count: this.data.count + 1 }); },
// 监听用户下拉刷新
onPullDownRefresh(){
console.log('下拉动作');
this.setData({ count: 0 });
// 数据加载完成后,停止下拉刷新动画
wx.stopPullDownRefresh();
}
})
⏫上拉触底
上拉触底 是移动端的专有名词,通过手指在屏幕上的上拉滑动操作,从而 加载更多数据 的行为
触发下一页数据加载,常用于分页列表如: 商品列表、订单列表,实现 “无限滚动” 效果
配置触底距离:
在页面 .json 中设置 onReachBottomDistance(默认 50px,即距离底部 50px 时触发):
{
"onReachBottomDistance": 60
}
编写触底加载逻辑:
在页面的 onReachBottom 生命周期函数中处理分页加载,
需添加加载锁避免重复请求,同时判断是否还有更多数据,最新版小程序,已经有自动节流处理;
- 前端请求节流,是前端性能优化中针对 高频触发的网络请求 设计的核心技巧;
控制请求的触发频率—— 在指定时间间隔内,无论请求被触发多少次,都只允许执行一次- 设置一个
开关False,每次请求时候判断,开关TRUE则请求忽略,开关False放行, - 并立刻设置
开关True,这样之后的请求,都会被忽略, - 等待请求最终回调
complete({ 开关False });
示例Demo: 开发一个无限下拉的,颜色块瀑布🎞️
<!-- 因为是随机的, 如果长度撑不起来页面,没有滚动条就不会触发! -->
<view wx:for="{{colorList}}" wx:key="index"class="num-item"style="background-color:rgba({{item}});">{{item}}</view>
<view wx:for="{{colorList}}" wx:key="index"class="num-item"style="background-color:rgba({{item}});">{{item}}</view>
Page({
/*** 页面的初始数据 */
data: {
count: 0,
colorList:[],
isloading: false,
},
// +1 按钮的点击事件处理函数
countAdd(){ this.setData({ count: this.data.count + 1 }); },
// 监听用户下拉刷新
onPullDownRefresh(){
console.log('下拉动作');
this.setData({ count: 0 });
// 数据加载完成后,停止下拉刷新动画
wx.stopPullDownRefresh();
},
// 生命周期函数--监听页面加载
onLoad(options) {
this.getColors();
},
// 获取随机颜色方法
getColors(){
wx.showLoading({ title: '数据加载中...' });
if(this.data.isloading){
console.log("当前存在未结束请求...");
return;
}
this.setData({ isloading: true });
// 核心:等待2秒后执行接口请求
setTimeout(() => {
wx.request({
url:'https://applet-base-api-t.itheima.net/api/color',
method: 'GET',
success: ({ data: res }) => {
this.setData({
// ES6 语法数组拆分 ...
colorList: [...this.data.colorList,...res.data]
})
},
complete: ()=>{
wx.hideLoading();
this.setData({ isloading: false });
}
})
}, 2000);
},
// 页面上拉触底事件的处理函数
onReachBottom(){
console.log('上拉动作');
this.getColors();
}
})
.num-item {
border:1rpx solid #efefef;
border-radius: 8rpx;
line-height:200rpx;
margin: 15rpx;
text-align: center;
text-shadow: Orpx Orpx 5rpx #fff;
box-shadow: 1rpx 1rpx 6rpx #aaa;
}
自定义编译模式
微信开发者工具 自定义编译模式
它是小程序开发调试的核心效率工具,主要用于模拟不同启动场景,
无需重复从首页跳转即可直接进入目标页面,提升调试效率,模拟真实场景;支持 启动参数配置
生命周期🎞️
什么是生命周期:
生命周期是小程序的「生命周期钩子函数」,
框架会在特定时间点自动调用这些函数,你可以在函数中编写业务逻辑
如:初始化数据、请求接口、清理资源),无需手动触发,是小程序开发的核心基础;
应用生命周期:
应用生命周期: 全局, 定义在 app.js中
小程序从启动到销毁 的全局生命周期,仅在 app.js 中配置,作用于整个小程序
App({
// 全局数据
globalData: { },
// 小程序首次启动(仅执行1次)
onLaunch(options) { console.log('小程序启动:', options); },
// 小程序切到前台(每次切回都执行)
onShow(options) { console.log('小程序切到前台:', options); },
// 小程序切到后台(每次切走都执行)
onHide() { console.log('小程序切到后台'); },
// 错误捕获
onError(error) { console.error('小程序发生代码错误或 API 调用失败时触发', error); },
// 页面不存在时触发
onPageNotFound(res) { console.log('访问的页面不存在时触发:', res); },
// 自定义全局方法
getUserInfo() { },
checkToken() { }
// ...
});
页面生命周期:
页面生命周期(单页面,定义在页面 .js 中)
页面生命周期是单个页面从 加载到卸载 的生命周期,作用于当前页面,核心函数如下:
Page({
data: { },
// 页面加载(仅执行1次)接收导航参数、初始化页面数据
onLoad(options) { console.log('页面加载,接收参数:', options); },
// 页面显示(每次切回都执行)刷新页面数据、恢复状
onShow() { console.log('页面显示'); },
// 页面初次渲染完成(仅执行1次)操作 DOM、初始化组件
onReady() { console.log('页面渲染完成'); },
// 页面隐藏(如跳转到商品详情页)暂停页面任务、保存临时数据
onHide() { console.log('页面隐藏'); },
// 页面卸载(如返回上一页并关闭当前页)清理资源、移除监听
onUnload() { console.log('页面卸载'); },
// 下拉刷新触发 刷新页面数据
onPullDownRefresh() { },
// 上拉触底触发 加载下一页数据
onReachBottom() { },
// 自定义方法:请求商品列表
getGoodsList(callback) { },
getCartCount() { /** 模拟获取购物车数量 */ }
});
应用生命周期 与 页面生命周期,联动关系
小程序启动流程:app.onLaunch → 加载首页 → 首页 onLoad → 首页 onShow → 首页 onReady
切后台流程:当前页面 onHide → app.onHide
切前台流程:app.onShow → 当前页面 onShow
页面跳转流程:当前页面 onHide → 目标页面 onLoad → 目标页面 onShow → 目标页面 onReady
页面返回流程:当前页面 onUnload → 上一页 onShow
WXS 脚本📃
什么是 wxs
WXS(WeiXin Script)是小程序专属的 渲染层脚本语言
运行在视图层(与逻辑层 JS 分离),核心作用是在 WXML 中直接处理数据或轻量逻辑,
避免频繁的跨线程通信,提升页面渲染性能,解决「逻辑层 JS」与「视图层 WXML」通信性能问题;
wxs 的应用场景:
数据格式化: 在 WXML 中直接格式化日期、金额、手机号等,无需 JS 预处理
复杂条件判断: 多条件组合判断显示内容,避免 WXML 中嵌套过多 wx:if
列表过滤 / 排序: 渲染列表时直接过滤或排序数据,减少 JS 计算压力
对于仅当前页面使用的简单逻辑,可直接在 WXML 中内联定义 WXS:
- wxs 代码可以编写在 wxml 文件中的
<wxs>标签内 - wxml 文件中的每个
<wxs></wxs>标签,必须提供 module 属性 - 用来指定当前 wxs 的模块名称,方便在 wxml 中访问模块中的成员
<view>
调用内联函数:
<view wx:if="{{filter.isHot(111)}}" >判断数据是否合格展示!</view>
<view>让字符大小写抓换, {{filter.toUpper('AdsdV')}}</view>
</view>
<wxs module="filter">
// 内联函数:判断商品是否为热销(销量>100)
function isHot(sales) {
return sales > 100;
}
function toUpper(str){
return str.toUpperCase(str);
}
// 导出函数,供外部调用
module.exports = { isHot: isHot,toUpper: toUpper };
</wxs>
外联 wxs 脚本
WXS 支持 内联定义 和 外联引入 ,外联方式适合封装通用工具函数(如格式化工具)
在项目中创建 WXS 工具文件(如 utils/format.wxs),编写通用函数;
// utils/format.wxs
// 格式化日期:时间戳 → YYYY-MM-DD
function formatDate(timestamp) {
var date = getDate(timestamp || getDate().getTime());
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
// 补零处理
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
return year + '-' + month + '-' + day;
}
// 导出函数,供外部调用
module.exports = {
formatDate: formatDate,
};
通过 <wxs> 标签引入外联文件,需指定 src(文件路径)和 module(模块名,用于调用函数):
<view>
调用内联函数:
<view wx:if="{{filter.isHot(111)}}" >判断数据是否合格展示!</view>
<view>让字符大小写抓换, {{filter.toUpper('AdsdV')}}</view>
<!-- 在WXML中调用WXS函数 -->
<view>订单创建时间:{{formatTool.formatDate()}}</view>
</view>
<!-- 引入外联WXS脚本,module命名为"formatTool" -->
<wxs src="/utils/format.wxs" module="formatTool"></wxs>
<wxs module="filter">
// 内联函数:判断商品是否为热销(销量>100)
function isHot(sales) {
return sales > 100;
}
function toUpper(str){
return str.toUpperCase(str);
}
// 导出函数,供外部调用
module.exports = { isHot: isHot,toUpper: toUpper };
</wxs>
注意事项:wxs 脚本
运行环境限制:
WXS 运行在 渲染层 无法调用小程序 API 如: wx.request、wx.showToast
也不能访问页面的 data,只能通过参数传递数据;不能与逻辑层 JS 直接通信;
语法差异(与 JS 对比:
- 变量声明仅,支持
var,无let/constwxs 不支持类似于 ES6 及以上的语法形式 - 函数声明仅,支持
function声明,无箭头函数; - 异步能力,无异步 API,不支持
Promise/async/await - 全局对象,提供
getDate()/parseInt()等基础 API,无window/document
在 iOS 设备上,小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍
在 android 设备上,二者的运行效率无差异
相关文档
黑马—小程序简介_哔哩哔哩_bilibili 对应:Day3 天内容!