从零开始的微信小程序入门教程(四),理解小程序事件与冒泡机制

壹 ❀ 引
我在之前初识WXML与数据绑定两篇文章中,介绍了小程序静态模板与样式相关概念,以及小程序几种常用数据绑定方式,在知道这些知识后,我们可以写一些不算复杂的小程序页面,并能将一些自定义的数据渲染到视图层,这非常棒。那么本文我们将继续介绍小程序中比较重要的事件概念,在学习完事件后,我们可以让小程序具备一定的交互性,那么本文开始。
贰 ❀ 初识小程序事件
在小程序中,事件是视图层到逻辑层的通讯方式。
比如,我们可以将事件绑定在组件上,当用户操作该组件并触发事件时,事件会将用户行为反馈到逻辑层做处理,也就是对应的执行逻辑层中的事件处理函数。
当然,有时候行为反馈不一定是由用户来主动触发,举个生活中的例子,我们在腾讯视频看龙岭迷窟时,当播放到一集结尾,视频会自动播放下一集。将这个例子拿到小程序中来说,video组件便自带了bindended
事件,只要视频播放到末尾便会触发该事件,小程序中存在很多由组件自身提供的事件,所以综合来说,小程序中的事件由用户行为反馈事件和组件状态反馈事件两部分组成。
微信小程序除了WXML,WXSS文件之外,还提供了WXS脚本语言,为什么突然扯到这个呢,因为从基础库版本2.4.4
开始,支持使用WXS响应事件。针对于IOS环境,WXS脚本执行速度是JavaScript的2-20倍,安卓环境没啥差别,大体上来理解,用WXS解决事件问题具备一定优势。由于我们目前暂未了解WXS脚本,所以这里先不做探讨,后面会专门另起一篇文章介绍WXS脚本以及事件相关说明。学习总不能一口吃成胖子,我们一步步来。
所以本文还是主要围绕用户行为反馈事件展开讨论,让大家对于事件先有个基本概念。
还记得上篇文章中我们接触的第一个点击事件tap吗?我们来重现它,并以此加深对于事件的理解、
首先,我们在index.wxml
中与index.js
中添加如下代码:
<button bindtap="alert">bindtap</button>
Page({
data: {},
alert: function (event) {
wx.showToast({
title: '触发成功', // 标题
icon: 'success', // 图标类型,默认success
duration: 1500 // 提示窗停留时间,默认1500ms
})
}
})
有上述例子可知,实现一个事件绑定主要分为两步,第一步我们通过bindtap
绑定了一个函数alert
,第二我们在Page构造器中定义对应的事件处理函数alert
。当户点击button组件时,该组件就会在Page中找到对应的事件函数并执行,这便是一次视图到逻辑的通讯过程。

需要注意的是,此时我们使用的事件是tap
,bind
只是一个事件前缀,这就像我们用原生JS事件时所有事件前都得加一个on,比如onclick,onchange
,这是同一个道理。
除此之外,小程序中的事件支持bindtap与bind:tap
两种写法,怎么用都行。
<button bindtap="alert">bindtap</button>
<button bind:tap="alert">bindtap</button>
好了,在了解了事件基本概念后,我们来一一介绍小程序中提供的用户交互事件。
由于大部分事件均与手指触碰有关,所以为了大家更好的感受各个事件的作用,这里我推荐大家开启小程序调试器的自动预览,如下

点击编译并预览后,登陆的微信账号即可预览我们的小程序项目,如果你修改了代码,记得手动点一次编译并预览按钮。

叁 ❀ 常见事件类型
注意,这里的事件类型均为用户行为反馈事件,相关说明直接引用官网,有个小规律,小程序中所有事件名均为小写单词拼接,无驼峰拼接情况,这点大家记住。
事件类型 | 触发条件 |
---|---|
touchstart | 手指触摸动作开始触发 |
touchmove | 手指触摸后移动触发 |
touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 |
touchend | 手指触摸动作结束 |
tap | 手指触摸后马上离开 |
longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发(与tap同时定义,优先级更高) |
longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替) |
transitionend | 会在 WXSS transition 或 wx.createAnimation 动画结束后触发 |
animationstart | 会在一个 WXSS animation 动画开始时触发 |
animationiteration | 会在一个 WXSS animation 一次迭代结束时触发 |
animationend | 会在一个 WXSS animation 动画完成时触发 |
现在,我们通过例子一一加深印象,还是使用上文提供的tap事件例子,JS代码不变,我们只需要切换事件名即可:
- touchstart事件
<button bindtouchstart="alert">bindtap</button>

模拟器可能还不是很明显,大家如果通过手机预览可以发现,由于button
组件按下去有个背景变灰的渐变,而touchstart
事件即是手指触碰到组件的一瞬间方法就被执行,此时按钮还没完全按下去,大家多体验几次。
- touchmove事件
<button bindtouchmove="alert">bindtap</button>

这个就非常明显了,手指按下按钮完全变灰后没执行,一定要我们按住手指并拖动才会触发。
- touchcancel事件
<button bindtouchcancel="alert">bindtap</button>
这个我交大家怎么模拟,在手机上用左手点击button组件不要放开,用右手点击小程序更多功能按钮,此时会弹窗,由于触碰被打断,可以发现事件被顺利触发。

其次,左手按钮button,点击关闭小程序,也就是这个按钮,此时小程序会暂时退出并保存在手机后台中,通过后台直接再进入小程序,我们会发现touchcancel
事件也会触发。

- touchend事件
<button bindtouchend="alert">bindtap</button>
点击按钮,长按拖动都不会触发,直到手指离开屏幕便会触发。
- tap事件
<button bindtap="alert">bindtap</button>
上文中给了例子,虽然官方说手指触碰后马上离开触发,事实证明我按住按钮十几秒后离开,也会触发,我默认理解为click事件。
- longpress事件
<button bindlongpress="alert">bindtap</button>

快速点击快速松开并不会触发该事件,只有点击超过350ms时才会触发。
- 与动画相关的API,由于涉及到了小程序动画,这里先通过官方动画例子展示API作用,动画怎么玩后面再做介绍(留个坑...)。
<view class="box {{extraClasses}}"
bindtransitionend="transitionEnd"
bindanimationstart="animationStart"
bindanimationiteration="animationIteration"
></view>
<button class="btn" bindtap="triggerTransition">触发CSS渐变</button>
<button class="btn" bindtap="triggerAnimation">触发CSS动画</button>
.box {
width: 100rpx;
height: 100rpx;
margin: 60rpx;
background: red;
}
.btn {
margin: 30rpx 60rpx 0;
}
.box-transition {
transition: all 0.5s;
}
.box-moved {
margin-left: 590rpx;
}
@keyframes box-ani {
from {margin-left: 60rpx}
to {margin-left: 590rpx}
}
.box-animation {
animation: box-ani 1s alternate infinite;
}
const app = getApp()
Page({
data: {
extraClasses: '',
},
triggerTransition: function () {
if (this.data.extraClasses == 'box-transition box-moved') {
this.setData({
extraClasses: 'box-transition'
})
} else {
this.setData({
extraClasses: 'box-transition box-moved'
})
}
},
triggerAnimation: function () {
this.setData({
extraClasses: 'box-animation'
})
},
transitionEnd: function () {
console.log('渐变已结束')
},
animationStart: function () {
console.log('动画已开始')
},
animationIteration: function () {
console.log('动画进行中')
},
animationend:function () {
console.log("动画结束")
}
})

肆 ❀ 事件对象
在事件处理函数中,我们能接受到一个event对象参数,该参数包含了当前事件类型,以及当前组件相关信息,具体属性如下:
属性 | 类型 | 说明 |
---|---|---|
type | String | 当前绑定的事件类型 |
timeStamp | Integer | 页面打开到触发事件所经过的毫秒数 |
target | Object | 触发事件的组件的一些属性值集合 |
currentTarget | Object | 当前组件的一些属性值集合 |
detail | Object | 额外的信息 |
touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
我们来看个例子:
<button bindtap="alert" id="btn" data-name="听风是风" data-age="27">bindtap</button>
Page({
data: {},
alert: function (event) {
console.log(event);
}
})
通过点击按钮任意区域,可以看到控制台输出如下数据:

可以看到组件上自定义的data-**
数据,组件X轴Y轴偏移量,鼠标点击时的坐标等等信息均有记录。
伍 ❀ 复习事件冒泡与理解小程序事件捕获/冒泡
我们知道,在JavaScript事件监听中,分为捕获阶段--目标阶段--冒泡阶段三个部分。考虑到有同学对于该部分知识有遗忘,这里做个简单补充。
我们先来看个JavaScript的例子:
<div class="parent">
父
<div class="child">
子
</div>
</div>
.parent{
width: 200px;
height: 200px;
background-color: #bbded6;
}
.child{
width: 100px;
height: 100px;
background-color: rgba(255,80,47,1);
}
var parent = document.querySelector(".parent"),
child = document.querySelector(".child");
parent.addEventListener("click", function () {
console.log("A");
}, true);
parent.addEventListener("click", function () {
console.log("B");
});
child.addEventListener("click", function () {
console.log("D");
}, true);
child.addEventListener("click", function () {
console.log("C");
}, false);
现在,让我们用鼠标点击红色区域,猜猜会一次输出什么呢?

在说答案之前,我们先复习下addEventListener
事件监听参数以及含义:
element.addEventListener(event,function,useCapture);
其中event与function为必填,event表示事件类型,function为事件处理函数,而useCapture为选填,它的值为Boolean值。用于指定事件是否在捕获或者冒泡阶段执行,默认为false,即在冒泡阶段执行,反之在捕获阶段执行。
而上文的例子中,我们用了一个父盒子包裹了一个子盒子,抛开根元素以及body,捕获与冒泡如下:
捕获阶段:parent--child
冒泡阶段:child--parent
再观察上述例子关于useCapture
的值,所以答案是ADCB
。
OK,花了点时间用于解释JS事件监听的冒泡概念。小程序中事件同样存在捕获与冒泡阶段。
比如我们前面所说的bind
前缀就表示事件在冒泡阶段执行,而如果我们想事件在捕获阶段执行,可以在bind
前面加上capture
,即capture-bind
表示捕获阶段执行。
微信小程序中的捕获与冒泡执行与JS事件监听保持一致,这里引用官方一张图解就一目了然了:

<view
id="parent"
bind:tap="tap1"
capture-bind:tap="tap2"
>
outer view
<view
id="child"
bind:tap="tap3"
capture-bind:tap="tap4"
>
inner view
</view>
</view>
#parent {
display: block;
background-color: #bbded6;
color: #fff;
}
#child{
background-color: rgba(255,80,47,1);
}
Page({
data: {},
tap1: function (event) {
console.log('tap1');
},
tap2: function (event) {
console.log('tap2');
},
tap3: function (event) {
console.log('tap3');
},
tap4: function (event) {
console.log('tap4');
},
})
当我们点击inner view
区域,可以看到依次输出如下:

为了防止大家疑惑,这里我们先做个知识小结,首先我们前面说了事件支持bind与bind:
两种写法,这两种写法都不会阻止冒泡,所以如果大家分别给父子绑定bind事件,点子区域,会先执行子的bind
再执行父的bind
,毕竟我们没使用capture
定义捕获阶段,所以全程就只有冒泡。记住了,bind不会阻止冒泡,添加capture前缀可以响应捕获阶段。
那么问题来了,假设我们想阻止冒泡呢?这时候就得将bind
替换为catch
事件了,catch
也支持两种写法catch与catch:
,我们来试试下面这个例子:
<view
id="parent"
catch:tap="tap1"
>
outer view
<view
id="child"
catch:tap="tap3"
>
inner view
</view>
</view>
现在点击inner view
区域,可以发现只输出了tap3
,因为冒泡被阻止了。
那有同学又要问了,如果我在catch
前添加capture
前缀会怎么样?怎么样咱们修改例子试试不就知道了,看下方例子:
<view
id="parent"
bind:tap="tap1"
capture-catch:tap="tap2"
>
outer view
<view
id="child"
bind:tap="tap3"
capture-catch:tap="tap4"
>
inner view
</view>
</view>
我们将capture-bind
都改为capture-catch
,可以发现不管点击父区域还是子区域,都只会输出一个tap2
,这是因为capture-catch
会中断捕获阶段和取消冒泡阶段。所以不管点击哪,都是从捕获阶段开始,先捕获到父,然后中断捕获,也不会存在冒泡了,就这么个意思。
OK,来个小总结。
bind
不会阻止冒泡,但如果想抓捕获阶段,可以添加前缀capture
,也就是capture-bind
。
catch
会阻止冒泡,如果添加capture
前缀,捕获阶段会中断的同时,也会阻止冒泡。
最后的最后,官方给了个贴心说明,除了上文中我们列举的用户交互反馈事件之外的其它任意组件状态反馈事件,除非有特殊声明,否则都是非冒泡事件。也就是说,上文给的用户交互反馈事件都是冒泡事件。
好了,关于小程序冒泡机制就聊到这。
陆 ❀ 总结
又花了一天事件整理了小程序事件相关概念,通过本文学习,我想大家对于小程序事件应该有了一个清晰的概念。小程序中的事件分为用户交互反馈事件与组件状态反馈事件(也就是组件自带的事件)。但总体来说,事件就是视图层到逻辑层的通讯方式。
除此之外,我们粗略的给出了各个事件的使用区别,帮助大家在特定的需求下能快速定位应该使用哪个事件。最后,我们复习了JS事件监听中捕获与冒泡的基础概念,以此为基础来了解了小程序中的冒泡机制。知道了原来除了bind
还有catch
事件,以及我们还能使用capture
前缀来决定是否阻止捕获与冒泡,这对于日后开发非常有帮助。
好了,关于事件的描述就先说到这了,关于下篇文章我还没想好写什么,我是通读小程序官方文档再做的记录,我也很怕有些知识点读的遗漏了没记录清除,反正我会加油持续更新。
那么到这里,本文结束。
对了,我始终觉得我在介绍事件监听时给的图片配色在哪里见过,思考了一番,才想起来了这是良品铺子包装袋的配色,如下图。

好了,我确实够无聊...本文结束。
从零开始的微信小程序入门教程(四),理解小程序事件与冒泡机制的更多相关文章
- 从零开始的微信小程序入门教程(一)
之前说要和同事一起开发个微信小程序项目,现在也在界面设计,功能定位等需求上开始实施了.所以在还未正式写项目前,打算在空闲时间学习下小程序.本意是在学习过程中结合实践整理出一个较为入门且不是很厚的教程, ...
- 微信小程序入门教程之四:API 使用
今天是这个系列教程的最后一篇. 上一篇教程介绍了,小程序页面如何使用 JavaScript 脚本.有了脚本以后,就可以调用微信提供的各种能力(即微信 API),从而做出千变万化的页面.本篇就介绍怎么使 ...
- RabbitMQ入门教程(四):工作队列(Work Queues)
原文:RabbitMQ入门教程(四):工作队列(Work Queues) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https:/ ...
- Elasticsearch入门教程(四):Elasticsearch文档CURD
原文:Elasticsearch入门教程(四):Elasticsearch文档CURD 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: ...
- 无废话ExtJs 入门教程四[表单:FormPanel]
无废话ExtJs 入门教程四[表单:FormPanel] extjs技术交流,欢迎加群(201926085) 继上一节内容,我们在窗体里加了个表单.如下所示代码区的第28行位置,items:form. ...
- PySide——Python图形化界面入门教程(四)
PySide——Python图形化界面入门教程(四) ——创建自己的信号槽 ——Creating Your Own Signals and Slots 翻译自:http://pythoncentral ...
- JasperReports入门教程(四):多数据源
JasperReports入门教程(四):多数据源 背景 在报表使用中,一个页面需要打印多个表格,每个表格分别使用不同的数据源是很常见的一个需求.假如我们现在有一个需求如下:需要在一个报表同时打印所有 ...
- 微信小程序入门教程
首先请看demo 很简单的静态js就可以实现一款小程序开发. js.json.html.css四个核心文件 序言 开始开发应用号之前,先看看官方公布的「小程序」教程吧!(以下内容来自微信官方公布的「小 ...
- 微信小程序入门教程之一:初次上手
微信是中国使用量最大的手机 App 之一,日活跃用户超过3亿,月活跃用户超过11亿(2019年底统计),市场极大. 2017年,微信正式推出了小程序,允许外部开发者在微信内部运行自己的代码,开展业务. ...
- 天河微信小程序入门《四》:融会贯通,form表单提交数据库
天河在阔别了十几天之后终于又回来了.其实这篇文章里的demo是接着(天河微信小程序入门<三>)后面就做了的,但是因为最近在做别的项目,所以就偷懒没有发出来.放到今天来看,从前台提交数据到数 ...
随机推荐
- VUEX 使用学习四 : action
转载请注明出处: action 用于处理异步任务:action,可以操作任意的异步操作,类似于mutations,但是是替代mutations来进行异步操作的.首先mutations中必须是同步方法, ...
- [java] JSP post 提交乱码 解决方案
//在post提交的页面顶部插入下列代码 <% request.setCharacterEncoding("UTF-8"); %>
- springboot封装统一返回
springboot返回统一的标准格式 定义注解 package com.yaoling.annotation; import java.lang.annotation.*; @Target({Ele ...
- [转帖]Linux下清理内存和Cache方法见下文:
https://www.cnblogs.com/the-tops/p/8798630.html 暂时目前的环境处理方法比较简单: 在root用户下添加计划任务: */10 * * * * sync;e ...
- [转帖]使用 TiUP 扩容缩容 TiDB 集群
https://docs.pingcap.com/zh/tidb/stable/scale-tidb-using-tiup TiDB 集群可以在不中断线上服务的情况下进行扩容和缩容. 本文介绍如何使用 ...
- [转帖]Nginx应用调优案例
https://bbs.huaweicloud.com/blogs/146367 [摘要] 1 问题背景nginx的应用程序移植到TaiShan服务器上,发现业务吞吐量没有达到硬件预期,需要做相应调优 ...
- 关于信创CPU测试的一些想法和思路
关于信创CPU测试的一些想法和思路 背景 最近荷兰政府颁布了关于半导体设备出口管制的最新条例. 好像45nm以下的工艺的设备都可能收到限制. 对中国的相关厂商比如长鑫还有华虹的影响应该都比较大. 认为 ...
- [转帖]rsar - Extract data from plain-text sar files
sar -A -t -f /tmp/sa11 >/tmp/sar11 https://github.com/ryran/rsar When dealing with sysstat sar da ...
- [转帖]kubelet 原理解析五: exec的背后
https://segmentfault.com/a/1190000022163850 概述 线上排查pod 问题一般有两种方式,kubectl log或者kubectl exec调试.如果你的 lo ...
- Windows 可以操纵linux内文件,与本地一致的工具
https://github.com/allanrbo/filesremote/releases/ 感觉挺好的.