【小程序】中的事件处理详解
文章目录
- 小程序的事件处理
- ?小程序的事件监听
- ?常见事件类型划分
- ?事件对象属性分析
- ?事件参数传递方法
- ?事件传递案例练习
- ?事件冒泡事件捕获
- ?知识点补充mark
小程序的事件处理
?小程序的事件监听
什么时候会产生事件呢?
小程序需要经常
和用户进行某种交互
,比如点击界面上的某个按钮或者区域,比如滑动了某个区域;事件是视图层到逻辑层的通讯方式;
事件可以将用户的行为反馈到逻辑层进行处理;
事件可以绑定在组件上,当触发事件时,就会执行逻辑层中对应的事件处理函数;
事件对象可以携带额外信息,如 id, dataset, touches;
事件时如何处理呢?
事件是通过bind/catch这个属性绑定在组件上的(和普通的属性写法很相似, 以key=“value”形式);
key以bind或catch开头, 从1.5.0版本开始, 可以在bind和catch后加上一个冒号;
同时在当前页面的Page构造器中定义对应的事件处理函数, 如果没有对应的函数, 触发事件时会报错;
比如当用户点击该button区域时,达到触发条件生成事件tap,该事件处理函数会被执行,同时还会收到一个
事件对象event
。
事件的基本使用
- 在组件中绑定一个事件处理函数。
如
bindtap
,表示当用户点击该组件的时候会在该页面对应的 Page 中找到相应的事件处理函数。
<!-- 绑定上onBtnTap事件 -->
<button size="mini" bindtap="onBtnTap">按钮</button>
// index.js
// 在对应的 Page 中找到相应的事件处理函数
Page({
onBtnTap() {
console.log("按钮点击");
}
})
当某个事件触发时, 在相应的 Page 中对应的事件处理函数, 会产生一个事件对象, 并且这个对象被传入到该回调函数中,参数是event。
// index.js
Page({
onBtnTap(event) {
console.log(event);
}
})
console.log打印出来的event大致信息如下
{
“type”:”tap”,
“timeStamp”:895,
“target”: {"id": "tapTest",
"dataset": {
"hi":"Weixin"
}
},
“currentTarget”: {"id": "tapTest",
"dataset": {
"hi":"Weixin"
}
},
“detail”: {"x":53,
"y":14
},
“touches”:[{"identifier":0,
"pageX":53,
"pageY":14,
"clientX":53,
"clientY":14
}],
“changedTouches”:[{"identifier":0,
"pageX":53,
"pageY":14,
"clientX":53,
"clientY":14
}]
}
?常见事件类型划分
某些组件会有自己特有的事件类型,大家可以在使用组件时具体查看对应的文档
比如input特有的
bindinput/bindblur/bindfocus
等比如scroll-view特有的
bindscrolltowpper/bindscrolltolower
等
这里我讲解几个所有组件都有的, 并且也比较常见的事件类型:
类型 | 触发条件 | 最低版本 |
---|---|---|
touchstart | 手指触摸动作开始 | |
touchmove | 手指触摸后移动 | |
touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 | |
touchend | 手指触摸动作结束 | |
tap | 手指触摸后马上离开 | |
longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 | 1.5.0 |
longtap | 手指触摸后,超过350ms再离开(推荐使用 longpress 事件代替) |
?事件对象属性分析
我们刚刚有简单演示, 当某个事件触发时, 会产生一个事件对象
, 并且这个对象被传入到回调函数中, 事件对象有哪些常见的属性呢?
如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数必定会收到一个事件对象。
BaseEvent 基础事件对象属性列表:
属性 | 类型 | 说明 | 基础库版本 |
---|---|---|---|
type | String | 事件类型 | |
timeStamp | Integer | 事件生成时的时间戳 | |
target | Object | 触发事件的组件的一些属性值集合 | |
currentTarget | Object | 当前组件的一些属性值集合 | |
mark | Object | 事件标记数据 | 2.7.1 |
这里我重点讲解一下target和currentTarget的区别
target
触发事件的源组件(当前触发事件的组件)。
属性 | 类型 | 说明 |
---|---|---|
id | String | 事件源组件的id |
dataset | Object | 事件源组件上由data- 开头的自定义属性组成的集合 |
currentTarget
事件绑定的当前组件(处理事件的组件)。
属性 | 类型 | 说明 |
---|---|---|
id | String | 当前组件的id |
dataset | Object | 当前组件上由data- 开头的自定义属性组成的集合 |
例如我们有如下一个wxml结构
<!-- index.wxml -->
<view id="view" bindtap="onViewTap" class="box">
<button id="btn" size="mini" type="primary">按钮</button>
</view>
给view添加如下样式
/* index.wxss */
.box {
width: 400rpx;
height: 400rpx;
background-color: skyblue;
}
展示效果如下
我们监听view的点击事件, 在相应的page文件中打印target和currentTarget
// index.js
Page({
onViewTap(event) {
console.log(event.target);
console.log(event.currentTarget);
}
})
此时点击button组件之外的view组件区域, target和currentTarget是没有任何区别的, 大致打印如下
{
id: "view", offsetLeft: 0, offsetTop: 0, dataset: {
…}}
{
id: "view", offsetLeft: 0, offsetTop: 0, dataset: {
…}}
当我们点击button组件, 会产生冒泡事件, 此时target和currentTarget就会有区别, 大致打印如下
{
id: "btn", offsetLeft: 0, offsetTop: 0, dataset: {
…}}
{
id: "view", offsetLeft: 0, offsetTop: 0, dataset: {
…}}
此时触发事件的是button组件冒泡到view组件, 因此target打印的是button组件
而此时处理事件的组件时view组件 (button组件冒泡到view组件, 由view组件处理事件), 因此currentTarget打印的是view组件
?事件参数传递方法
当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过data-属性来完成:
格式:
data-属性的名称
获取:
event.currentTarget.dataset.属性的名称
, 一般是通过currentTarget获取, 某些特殊场景是通过target获取
自定义属性的基本使用
wxml文件中通过自定义属性, 将数据传递到对应的事件处理函数中
参数传递在对应的事件处理函数中获取到传递的数据
// index.js
Page({
onArgumentTap(event) {
console.log(event.currentTarget.dataset.name);
console.log(event.currentTarget.dataset.age);
console.log(event.currentTarget.dataset.height);
}
})
?事件传递案例练习
我们在小程序中, 做一个下面这样的导航栏, 要求点击哪一个导航栏, 文字颜色就改变, 并且对应的标签会显示一个横条
wxml文件的结构
{
{ item }}
js的逻辑代码
Page({
data: {
titles: ["衣服", "鞋子", "裤子"],
currentIndex: 0
},
onTitleTap(event) {
this.setData({
currentIndex: event.currentTarget.dataset.index
})
}
})
wxss文件的样式
.active {
color: pink;
border-bottom: 3px solid pink;
}
.box {
display: flex;
justify-content: space-between;
}
.box .title {
margin: 0 10px;
padding: 10rpx 40rpx;
}
?事件冒泡事件捕获
当界面产生一个事件时,事件分为了捕获阶段和冒泡阶段。
在js阶段我有写过文章详细讲解事件冒泡和事件捕获, 如果对这两个概念不清楚的可以去了解一下:
https://blog.csdn.net/m0\_71485750/article/details/125112983
对于冒泡和捕获的概念我就不再过多赘述, 在这里演示一下如何阻止冒泡和捕获
- 除
bind
外,也可以用catch
来绑定事件, 与bind
不同的是,catch
会阻止事件向上冒泡。
例如在下边这个例子中,
点击 inner view 会先后调用
onViewTap3
和onViewTap2
(因为 tap 事件会冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父节点传递)点击 middle view 会触发
onViewTap2
点击 outer view 会触发
onViewTap1
。
<view id="outer" bindtap="onViewTap1">
outer view
<!-- 阻止事件冒泡 -->
<view id="middle" catchtap="onViewTap2">
middle view
<view id="inner" bindtap="onViewTap3">
inner view
</view>
</view>
</view>
catch
阻止事件传递, 因此阻止事件捕获也是使用catch
, 捕获是通过capture-bind:tap="事件函数"
来监听的
outer view
middle view
inner view
?知识点补充mark
mark是一个比较新的语法, 小程序特有的传递数据的方法 (还是推荐使用data-\来传递数据*)
当事件触发时,事件冒泡路径上所有的
mark
会被合并,并返回给事件回调函数。(即使事件不是冒泡事件,也会mark
。)
mark基本使用
wxml中使用mark传递数据
获取mark传递的数据, 通过
event.mark
获取Page({
onBtnTap(event) {
// 通过event.mark获取
console.log(event.mark);
}
})
还没有评论,来说两句吧...