我在以前初识WXML与数据绑定两篇文章中,介绍了小程序静态模板与样式相关概念,以及小程序几种经常使用数据绑定方式,在知道这些知识后,咱们能够写一些不算复杂的小程序页面,并能将一些自定义的数据渲染到视图层,这很是棒。那么本文咱们将继续介绍小程序中比较重要的事件概念,在学习完事件后,咱们可让小程序具有必定的交互性,那么本文开始。javascript
在小程序中,事件是视图层到逻辑层的通信方式。css
好比,咱们能够将事件绑定在组件上,当用户操做该组件并触发事件时,事件会将用户行为反馈到逻辑层作处理,也就是对应的执行逻辑层中的事件处理函数。html
固然,有时候行为反馈不必定是由用户来主动触发,举个生活中的例子,咱们在腾讯视频看龙岭迷窟时,当播放到一集结尾,视频会自动播放下一集。将这个例子拿到小程序中来讲,video组件便自带了bindended
事件,只要视频播放到末尾便会触发该事件,小程序中存在不少由组件自身提供的事件,因此综合来讲,小程序中的事件由用户行为反馈事件和组件状态反馈事件两部分组成。java
微信小程序除了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中找到对应的事件函数并执行,这即是一次视图到逻辑的通信过程。app
须要注意的是,此时咱们使用的事件是tap
,bind
只是一个事件前缀,这就像咱们用原生JS事件时全部事件前都得加一个on,好比onclick,onchange
,这是同一个道理。ide
除此以外,小程序中的事件支持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代码不变,咱们只须要切换事件名便可:
<button bindtouchstart="alert">bindtap</button>
模拟器可能还不是很明显,你们若是经过手机预览能够发现,因为button
组件按下去有个背景变灰的渐变,而touchstart
事件便是手指触碰到组件的一瞬间方法就被执行,此时按钮还没彻底按下去,你们多体验几回。
<button bindtouchmove="alert">bindtap</button>
这个就很是明显了,手指按下按钮彻底变灰后没执行,必定要咱们按住手指并拖动才会触发。
<button bindtouchcancel="alert">bindtap</button>
这个我交你们怎么模拟,在手机上用左手点击button组件不要放开,用右手点击小程序更多功能按钮,此时会弹窗,因为触碰被打断,能够发现事件被顺利触发。
其次,左手按钮button,点击关闭小程序,也就是这个按钮,此时小程序会暂时退出并保存在手机后台中,经过后台直接再进入小程序,咱们会发现touchcancel
事件也会触发。
<button bindtouchend="alert">bindtap</button>
点击按钮,长按拖动都不会触发,直到手指离开屏幕便会触发。
<button bindtap="alert">bindtap</button>
上文中给了例子,虽然官方说手指触碰后立刻离开触发,事实证实我按住按钮十几秒后离开,也会触发,我默认理解为click事件。
<button bindlongpress="alert">bindtap</button>
快速点击快速松开并不会触发该事件,只有点击超过350ms时才会触发。
<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
前缀来决定是否阻止捕获与冒泡,这对于往后开发很是有帮助。
好了,关于事件的描述就先说到这了,关于下篇文章我还没想好写什么,我是通读小程序官方文档再作的记录,我也很怕有些知识点读的遗漏了没记录清除,反正我会加油持续更新。
那么到这里,本文结束。
对了,我始终以为我在介绍事件监听时给的图片配色在哪里见过,思考了一番,才想起来了这是良品铺子包装袋的配色,以下图。
好了,我确实够无聊...本文结束。