速通-微信小程序 2Day
速通-微信小程序 2Day
速通-微信小程序-CSDN博客 紧接前文,搭配有助于快速,巩固/学习!话不多说开始!
这一部分挺简单的,最起码对于做过前端Vue 开发,前后端的 me,so so easy!
WXML 模板语法
WXML(WeiXin Markup Language)是小程序的视图层模板语言,
作用类似 HTML,但扩展了「数据绑定、逻辑渲染、事件绑定」等核心能力,
是小程序 数据驱动视图 核心能力:数据绑定、逻辑渲染(列表/条件)、事件绑定;
数据绑定:
Mustache 语法 ,把data中的数据绑定到页面中渲染:
WXML 通过双大括号 {{}}将 JS 逻辑层数据渲染到视图层,支持 内容绑定、属性绑定、表达式运算
-
{{}}内支持简单表达式(算术、三元、逻辑运算),但不支持复杂语句(如if/for循环) -
文本绑定中,
{{}}会自动解析\n为换行符(对应之前text组件的换行场景) -
⚠️绑定的数据必须在页面
data中定义,否则会显示为空;
内容绑定: <标签> {{ 绑定页面data中的变量,文本渲染 }} </标签>
属性绑定: 标签,属性值也用 {{}} 绑定,注意,属性名无需加引号(区别于 VUE 的v-bind)
xxx.js
Page({
/** 页面的初始数据 */
data: {
img: "https://i1.hdslb.com/bfs/face/6ac26f27a6d25da7865cab8e0806676c8f4cd62c.webp",
username: "wsm",
age: 25
},
/** 省略其他配置.... */
})
xxx.wxml
<view>
<!-- 绑定页面data中的变量 -->
<text>用户名:{{username +'\n'}}</text>
<text>年龄:{{age + 1 +'\n'}}</text> <!-- 支持表达式运算 -->
<text>成年:{{age >= 18 ? '是' : '否'}} \n</text> <!-- 三元运算 -->
<!-- 动态绑定标签属性-data中的变量 -->
<image src="{{img}}" mode="widthFix"></image>
</view>
![]()
事件绑定:
小程序的事件绑定是视图层(WXML)与逻辑层(JS)通信的核心方式 也是实现用户交互的唯一入口;
由于小程序是双线程模型(渲染层 + 逻辑层),事件需通过微信客户端(Native)中转,
因此绑定规则、事件对象与普通网页的 DOM 事件有本质差异;
![]()
事件 中转通信
小程序的事件并非直接的 DOM 事件,而是通过 微信客户端作为中转桥接层
将视图层用户交互 点击、输入 转发到逻辑层 JS 函数处理,这种设计避免了直接 DOM 操作;
-
核心限制 :禁止直接操作 DOM,所有交互必须通过
事件绑定 + 数据驱动实现 -
触发流程 :用户在视图层触发事件 → 微信客户端捕获事件并封装成事件对象
→ 转发到逻辑层对应的 JS 函数 → 逻辑层处理后通过
setData更新视图;
事件绑定的两种核心方式:
小程序提供 bind 和 catch 两种绑定前缀,核心区别是是否允许事件冒泡
| 绑定方式 | 行为 | 适用场景 |
|---|---|---|
| bind | 绑定事件并允许冒泡(事件会向上传递给父元素) | 需要父元素响应子元素事件的场景 如:事件委托) |
| catch | 绑定事件并阻止冒泡(事件不会向上传递) | 仅需当前元素响应事件的场景 如:按钮点击、表单提交) |
<!-- 父元素绑定bindtap,子元素绑定bindtap -->
<view bindtap="parentTap" style="padding: 20rpx; background: #f0f0f0;">
<button bindtap="childTap">点击子元素(允许冒泡)</button>
</view>
<!-- 父元素绑定bindtap,子元素绑定catchtap -->
<view bindtap="parentTap"
style="padding: 20rpx; background: #f0f0f0; margin-top: 20rpx;">
<button catchtap="childTap">点击子元素(阻止冒泡)</button>
</view>
/** 页面定义函数 */
parentTap() {
console.log("父元素事件触发");
},
childTap() {
console.log("子元素事件触发");
}
![]()
-
点击第一个按钮(
bindtap):会先触发childTap,再触发parentTap(事件冒泡到父元素) -
点击第二个按钮(
catchtap):仅触发childTap,不会触发parentTap(阻止冒泡)
事件对象(e):交互数据的 “载体”
事件触发时,逻辑层的 JS 函数会收到一个 事件对象e,包含事件的所有信息,核心属性如下:
| 属性 | 作用 |
|---|---|
| e.type | 事件类型(如 tap、input)区分不同事件类型,如同时绑定多种事件时判断触发源) |
| e.target | 触发事件的源元素(实际点击的元素) 事件委托场景中,获取触发事件的具体子元素 |
| e.currentTarget | 绑定事件的当前元素(事件绑定的元素) 获取绑定事件的元素的自定义属性或统一处理父元素逻辑 |
| e.detail | 事件携带的额外信息(如表单输入值、滑动距离) 获取表单组件的输入内容(如 input 实时值)、滑动组件的位移量 |
| e.dataset | 元素的自定义属性(通过 data-* 定义)事件传参的核心方式(如传递商品 ID、列表项索引) |
<view bindtap="handleTap" data-id="parent">
<button data-id="child">点击按钮</button>
</view>
handleTap(e) {
console.log(e.target.dataset.id); // 输出:child(实际触发的元素是按钮)
console.log(e.currentTarget.dataset.id); // 输出:parent(绑定事件的元素是view)
}
target 和 currentTarget 的区别
target:指向实际触发事件的元素(子元素)
currentTarget:指向绑定事件的元素(父元素)
![]()
小程序 常用事件
冒泡事件(支持bind/catch)
| 事件名 | 触发场景 | 实战用途 |
|---|---|---|
| tap | 点击元素 (手指触摸后马上离开) | 按钮点击、列表项跳转、提交操作 |
| longpress | 长按元素(触摸时间≥350ms) | 弹出操作菜单、删除确认 |
| touchstart | 手指触摸开始 | 滑动交互、手势识别 |
| touchend | 手指触摸结束 | 滑动结束、手势确认 |
| touchmove | 手指触摸后移动 | 滑动拖拽、进度条控制 |
非冒泡事件(仅支持bind,catch无效)
| 事件名 | 触发场景 | 实战用途 |
|---|---|---|
| submit | 表单提交 | 提交表单数据到后端 |
| scroll | 页面 / 滚动容器滚动 | 监听滚动位置、实现上拉加载更多 |
| change | 表单组件值变化(如 switch、picker) | 监听开关状态、选择器变化 |
| input | 输入框内容变化 | 实时获取用户输入(如搜索框、表单) |
事件传参:data-* 自定义属性
小程序不支持直接在事件绑定中传参 如: bindtap="handleClick(123)"会报错
必须通过data-*自定义属性传递参数,再从事件对象的 e.currentTarget.dataset 中获取;
<!-- 事件传参: -->
<view>
<!-- 可以为组件提供data-*自定义属性传参,其中*代表的是参数的名字,示例代码如下: -->
<button bindtap="handleTapparam" data-param1="123" data-param2="{{123}}" >事件传参 param1</button>
</view>
handleTapparam(e){
//通过 event.target.dataset.参数名 即可获取到具体参数的值
//通过dataset可以访问到具体参数的值
console.log(e.target.dataset);
console.log(e.target.dataset.param1);
console.log(e.target.dataset.param2);
}
表单事件的detail属性:
实现文本框和 data 之间的数据同步
小程序文本框(input组件)与页面data的 数据双向同步
核心依托小程序 数据绑定 +input 组件 输入事件监听 🖥️🖥️🖥️
通过setData完成视图层(文本框)与逻辑层(data)的双向数据更新;
- 文本框通过
value="{{data中的变量}}"实现 data 到文本框的单向渲染(初始值回显); - 绑定
input组件的输入事件(bindinput/bindblur),实时 / 按需获取文本框输入值; - 在事件处理函数中,通过
this.setData({ 变量: 输入值 })完成 文本框到 data 的反向同步; - 全程遵循小程序「数据驱动视图」原则, 禁止直接操作 DOM ,所有数据更新均通过
setData实现;
<input value="{{inpmas}}" bindinput="inpvalue"
style="border: 1px solid black; margin: 5px; padding: 5px;" />
/** 页面的初始数据 */
data: {
img: ".................",
inpmas: '兴趣爱好',
username: "wsm",
age: 25,
},
//data 之间的数据同步
inpvalue(e){
//通过 e.detail.value 获取到文本框最新的值
this.setData({ inpmas: e.detail.value });
console.log(this.data.inpmas);
},
![]()
条件渲染:
WXML 的条件渲染是小程序根据逻辑层(JS)数据动态控制视图层元素显示 / 隐藏的核心能力,
完全遵循「数据驱动视图」原则,禁止直接操作 DOM 修改显示状态。
wx:if
wx:if / wx:elif / wx:else(多分支条件,逻辑销毁 / 重建)
wx:if 是 WXML 原生支持的 多分支条件渲染语法 ,支持单条件、多条件分支、嵌套判断
底层通过 销毁 / 重建组件节点 实现显示 / 隐藏(条件不满足时节点从渲染树移除,满足时重新创建)
<view>
<!-- 当isShow为true时显示,否则销毁该节点 -->
<view wx:if="{{isShow}}">仅满足条件时显示</view>
<!-- 多分支按顺序匹配,仅执行第一个满足条件的分支 -->
<view wx:if="{{status === 0}}">待支付</view>
<view wx:elif="{{status === 1}}">已支付/待发货</view>
<view wx:elif="{{status === 2}}">已发货/待收货</view>
<view wx:else>已完成/已取消</view>
<!-- block包裹多节点,一次控制所有元素的显示/隐藏 -->
<block wx:if="{{hasData}}">
<view>商品名称:{{goods.name}}</view>
<view>商品价格:{{goods.price}}元</view>
<button>立即购买</button>
</block>
<!-- 空状态提示 -->
<view wx:else>暂无商品数据</view>
</view>
Page({
/** 页面的初始数据 */
data: {
status: 3,
isShow: false,
hasData: false,
goods: { name:"AAA", price:12.00 },
},
})
![]()
<block> 包裹多节点(不生成冗余 DOM)
若需要 同时控制多个元素的条件显示,直接给每个元素加wx:if会冗余,
可使用<block>标签包裹 ——<block>是 WXML 的无渲染容器,
仅用于包裹节点,不生成实际 DOM 元素,不影响页面布局;
wx:hidden
hidden 是 WXML 元素的通用属性,仅支持单分支条件判断(隐藏 / 显示)
底层通过CSS 的 display: none 实现隐藏 —— 元素节点始终存在于渲染树中
仅通过样式控制不可见,适合 单条件、高频切换 的场景(如弹窗、下拉菜单、开关控制的内容
<view>
<!-- 方式1:直接写布尔值(静态,无动态切换需求) -->
<view hidden="{{true}}">静态隐藏的内容</view>
<!-- 方式2:绑定data中的布尔变量(推荐,支持动态切换) -->
<view hidden="{{isHidden}}">高频切换的内容(如弹窗)</view>
<!-- 方式3:结合简单表达式(无需额外定义data变量) -->
<view hidden="{{list.length === 0}}">列表有数据时显示</view>
</view>
Page({
/** 页面的初始数据 */
data: {
// 控制hidden的核心变量
isHidden: false,
list: [1,2]
},
})
![]()
if 🆚 hidden
两者的核心差异在于 底层实现方式,直接决定了 切换性能开销 和 适用场景
运行方式不同:
- wx:if 以动态创建和移除元素的方式,控制元素的展示与隐藏
- hidden 以切换样式的方式(display: none/block;),控制元素的显示与隐藏
使用建议: 频繁切换时,建议使用 hidden,控制条件复杂时,建议使用 wx:if、wx:elif、wx:else
wx:for 列表渲染
wx:for 是 WXML 原生核心的列表渲染指令,用于将数组 / 对象中的数据循环渲染为页面节点;
将逻辑层(JS)data中的数组 / 对象,在视图层(WXML)中循环生成相同结构的节点,
实现数据与视图的联动渲染,无需手动操作 DOM;
直接给元素绑定wx:for="{{数组名}}",即可循环渲染该元素;
小程序自动提供 2 个默认变量,无需手动定义:
-
item:当前循环的 数组项每一个元素 -
index:当前循环的 索引从 0 开始
wx:key是必填项 无合法wx:key会触发控制台性能警告,且列表重排时易出现渲染错误
<view>
<!-- wx:for绑定数组,wx:key绑定唯一标识 -->
<view wx:for="{{goodsList}}" wx:key="id" class="goods-item">
<text>第{{index+1}}个商品:</text>
<text>名称:{{item.name}},价格:{{item.price}}元</text>
</view>
</view>
Page({
/** 页面的初始数据 */
data: {
// 模拟后端返回的商品列表,id为唯一标识
goodsList: [
{ id: 1, name: "小程序开发实战", price: 59 },
{ id: 2, name: "Java后端进阶", price: 79 },
{ id: 3, name: "全栈开发指南", price: 99 }
]
},
})
![]()
WXSS 模板样式
WXSS(WeiXin Style Sheet)是小程序的专属样式语言,
类似于CSS样式,并,在 CSS 基础上扩展了 rpx 响应式尺寸单位 解决移动端多设备适配复用问题;
rpx 尺寸单位
什么是 rpx 尺寸单位
rpx(responsive pixel)是小程序独有的响应式尺寸单位
用于统一不同屏幕宽度设备的尺寸显示,替代 CSS 中的固定单位 px,无需手动计算适配比例;
实现原理: 小程序将所有设备的屏幕宽度统一映射为 750rpx 750rpx = 设备实际屏幕宽度
框架会根据设备屏幕宽度自动换算 rpx 对应的物理像素:
- 在 iPhone X(屏幕宽度 375px)上:换算比例与 iPhone 6 一致
- 在 iPhone 6(屏幕宽度 375px)上:
750rpx = 375px→1rpx = 0.5px - 在安卓设备(如屏幕宽度 414px)上:
750rpx = 414px→1rpx ≈ 0.552px
设计稿适配:主流设计稿宽度为 750px,设计稿上的 1px 可直接对应小程序的 1rpx
官方建议:开发微信小程序时,设计师可以用 iPhone6 作为视觉稿的标准
@import 样式导入
用于导入外部 WXSS 样式文件,实现 公共样式复用
如:全局主题、组件样式、工具类),避免重复编写样式,提升代码可维护性;
支持 相对路径 和 绝对路径 ,必须用双引号包裹路径,结尾加分号,可导入多个文件,按顺序合并样式;
![]()
app.json 全局配置
小程序根目录下的 app.json 文件是小程序的 全局配置文件: 常用的配置项如下:
- pages: 记录当前小程序所有页面的存放路径,必选,小程序启动的基础
- tabBar: 设置小程序底部的 tabBar 效果
- window: 全局设置小程序窗口的外观
- style: 是否启用新版的组件样式
配置 window
| 属性名 | 默认值 | 说明 |
|---|---|---|
| navigationBarTitleText | 字符串 | 导航栏标题文字内容 |
| navigationBarBackgroundColor | #000000 | 导航栏背景颜色,如 #000000 |
| navigationBarTextStyle | white | 导航栏标题颜色,仅支持 black/white |
| backgroundColor | #ffffff | 窗口的背景色 |
| backgroundTextStyle | dark | 下拉 loading 的样式,仅支持 dark/light |
| enablePullDownRefresh | false | 是否全局开启下拉刷新 |
| onReachBottomDistance | 50 | 页面上拉触底事件触发,距页面底部距离,单位为px |
| navigationStyle | default |
custom 为自定义导航栏,适合沉浸式页面 |
配置 tabBar
tabBar 是小程序的 全局底部导航组件,用于在多个核心页面(如首页、我的、订单)之间快速切换;
是多页面小程序的标配。它完全在 app.json 中配置,无需编写额外代码,以下完整配置指南🧭:
小程序中通常将其分为: 底部 tabBar 、顶部 tabBar
-
tabBar中只能:配置最少 2 个、最多 5 个 tab 页签
-
渲染
顶部tabBar时,不显示 icon,只显示文本
tabBar 是 app.json 的顶级配置项,分为必填项和可选项
| 配置项 | 必填 / 取值 / 说明 |
|---|---|
| color | 是,tab 未选中时的文字颜色(十六进制色值,如 #666666) |
| selectedColor | 是,tab 选中时的文字颜色(需与 color 区分,如品牌色 #ff4444) |
| backgroundColor | 是,tabBar 的背景色(十六进制色值,如 #ffffff) |
| borderStyle | 否,tabBar 上边框的样式,仅支持 black/white,默认 black
|
| position | 否,tabBar 的位置,默认 bottom(底部),可选 top(顶部)⚠️ 注意: position: "top" 时,不显示 icon,仅显示文字 |
| custom | 否,是否使用自定义 tabBar(默认 false)开启后需在根目录创建 custom-tab-bar 自定义组件,适合复杂交互; |
| list | 是,tab 项的数组,最少 2 个,最多 5 个,每个元素为一个 tab 配置对象; |
每个 tab 项的配置(list 数组元素)
| 配置项 | 必填 / 取值 / 说明 |
|---|---|
| pagePath | 是,点击 tab 跳转的页面路径, 必须是 pages 数组中已注册的页面 如 pages/index/index
|
| text | 是,tab 上显示的文字,如 首页 我的
|
| iconPath | 否,tab 未选中时的图标路径,建议用 81px:81px 的 2x 图,避免模糊 |
| selectedIconPath | 否,tab 选中时的图标路径,需与 iconPath 尺寸一致 |
以下是 <常见小程序> 的典型 tabBar 配置: 首页 / 消息 / 联系我们
{
"pages": [
"pages/home/home",
"pages/contact/contact",
"pages/message/message"
],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "我的小程序",
"navigationBarBackgroundColor": "#FFFFFF"
},
"style": "v2",
"lazyCodeLoading": "requiredComponents",
"componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json",
"tabBar": {
"color": "#666666",
"selectedColor": "#ff4444",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [
{
"text": "首页",
"pagePath": "pages/home/home",
"iconPath": "images/tab/home.png",
"selectedIconPath": "images/tab/home-active.png"
},
{
"text": "消息",
"pagePath": "pages/message/message",
"iconPath": "images/tab/message.png",
"selectedIconPath": "images/tab/message-active.png"
},
{
"text": "联系我们",
"pagePath": "pages/contact/contact",
"iconPath": "images/tab/contact.png",
"selectedIconPath": "images/tab/contact-active.png"
}
]
}
}
- ⚠️ tabBar —— list 最少两个最多5个,且必须在 Page中存在!!!
![]()
xxx.json 局部配置
小程序中,每个页面都有自己的 .json 配置文件,用来对当前页面的窗口外观、页面效果等进行配置
小程序中,app.json 中的 window 节点,可以全局配置小程序中每个页面的窗口表现;
-
如果,某些小程序页面想要拥有特殊的窗口表现,
-
此时,
页面级别的 .json就可以实现这种需求
根据就近原则,最终的效果以页面配置为准
网络数据请求
小程序中网络数据请求的限制:
为保障用户数据安全,小程序的网络请求有以下强制规则:
域名白名单
-
上线请求的域名必须在,微信公众平台
开发管理→开发设置→服务器域名中配置白名单,仅支持 HTTPS 协议,域名必须经过 ICP 备案,可在小程序:项目配置中查看!

-
开发阶段可在开发者工具中开启
不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书豁免;上线前必须完成域名备案并配置白名单;
详情——本地配置——不校验合法域名
仅在开发阶段使用,上线必须合法域名HTTPS!!
协议要求
-
上线: 仅支持
HTTPS/WSS协议,禁止使用HTTP; - 开发阶段: 可暂时豁免,上线前必须切换为 HTTPS 域名;
请求频率
- 单个小程序的并发请求数限制为 10 个,高频请求需做节流/合并
- 避免短时间内发起大量请求,可通过防抖 / 合并请求优化
跨域限制
-
仅需配置微信域名白名单,无需后端设置 CORS
-
无需配置 CORS(由微信客户端中转请求,无浏览器同源限制)
相关测试接口:
GET: https://applet-base-api-t.itheima.net/slides 获取轮播图信息;
POST: https://applet-base-api-t.itheima.net/api/post 上传用户信息;
![]()
发生 GET 请求
home.wxml
<!-- 轮播图容器:适配小程序轮播组件 -->
<swiper indicator-dots autoplay interval="3000"
circular indicator-active-color="#ff4444" class="banner-swiper">
<!-- 循环渲染轮播图项 -->
<swiper-item wx:for="{{slides}}" wx:key="id">
<image src="{{item.image}}" style="height: 100%; width: 100%;" />
</swiper-item>
</swiper>
home.js
Page({
/*** 页面的初始数据 */
data: {
slides: [] // 轮播图数据列表,初始为空
},
/** 生命周期函数--监听页面加载 */
onLoad(options) {
// 调用GET请求渲染页面轮播图~
this.getSlides();
},
//GET请求获取页面轮播图信息
getSlides() {
// 显示加载中提示,提升用户体验
wx.showLoading({title: '加载中...', mask: true});
wx.request({
url: 'https://applet-base-api-t.itheima.net/slides',
method: 'GET',
success: (res) => {
// 接口请求成功:判断状态码,更新数据
if (res.statusCode === 200 && res.data) {
this.setData({slides: res.data });
}else{
// 接口返回异常,提示用户
wx.showToast({ title: '轮播图数据加载失败', icon: 'none',duration: 2000 })
}
},
fail: (err) => {
console.error('轮播图请求失败:', err);
wx.showToast({ title: '轮播图数据加载失败', icon: 'none',duration: 2000 })
},
// 无论成功/失败,都关闭加载提示
complete: () => {
wx.hideLoading();
}
})
}
})
![]()
发送 POST 请求
<!-- 分割线 -->
<view class="divider">\n</view>
<!-- 用户信息输入区域(新增) -->
<view>
<view>
<text>姓名:</text>
<input type="text" placeholder="请输入姓名"
value="{{name}}" bindinput="syncInput" data-key="name"/>
</view>
<view class="form-item">
<text class="label">性别:</text>
<input type="text" placeholder="请输入性别 男/女"
value="{{gender}}" bindinput="syncInput" data-key="gender" />
</view>
<!-- 提交按钮 -->
<button bindtap="postUserInfo" class="submit-btn">提交用户信息</button>
</view>
<!-- POST请求结果展示区域(新增) -->
<view wx:if="{{postResult}}">
<text>提交结果:</text>
<text>{{postResult}}</text>
</view>
Page({
/*** 页面的初始数据 */
data: {
slides: [], // 轮播图数据列表,初始为空
name: '',
gender: '',
postResult: ''
},
/** 生命周期函数--监听页面加载 */
onLoad(options) { },
//GET请求页面轮播图信息
getSlides() { },
// 新增:同步输入框数据到data(实时绑定)
// 通过data-key区分是name还是gender输入框
syncInput(e) {
const key = e.currentTarget.dataset.key;
this.setData({[key]: e.detail.value });
},
// 新增:POST请求提交用户信息
postUserInfo() {
// 非空校验
const { name, gender } = this.data;
if (!name || !gender) {
wx.showToast({ title: '请完善姓名和性别', icon: 'none' });
return;
}
// 显示加载提示
wx.showLoading({ title: '提交中...', mask: true });
// 发起POST请求
wx.request({
url: 'https://applet-base-api-t.itheima.net/api/post',
method: 'POST',
data: { name, gender },
header: { 'content-type': 'application/json' },
success: (res) => {
// 将返回的JSON转为字符串,方便页面展示
if (res.statusCode === 200 && res.data) {
this.setData({postResult: JSON.stringify(res.data, null, 2)})
wx.showToast({ title: '提交成功', icon: 'success' });
}else {
wx.showToast({ title: '提交失败', icon: 'none' });
}
},
fail: (err) => {
console.error('POST请求失败:', err);
wx.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
},
complete: () => { wx.hideLoading(); },
})
}
})
![]()
小程序网络请求进阶
小程序的网络请求能力远不止 GET/POST,
完全支持 RESTful 风格的 PUT/DELETE 等方法,同时提供了专门的 API 处理表单和文件传输;
相关文档:
黑马—小程序简介_哔哩哔哩_bilibili 对应:Day2 天内容!
- blog 中涉及接口案例,可能会失效,可以到官方评论区,会定期更新最新域名!