事件处理
事件监听
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
什么时候会产生事件呢?
- 小程序需要经常和用户进行某种交互,比如点击界面上的某个按钮或者区域,比如滑动了某个区域
- 事件是视图层到逻辑层的通讯方式
- 事件可以将用户的行为反馈到逻辑层进行处理
- 事件可以绑定在组件上,当触发事件时,就会执行逻辑层中对应的事件处理函数
- 事件对象可以携带额外信息,如 id, dataset, touches
事件时如何处理呢?
- 事件是通过 bind/catch 这个属性绑定在组件上的(和普通的属性写法很相似, 以 key="value" 形式)
- key 以 bind 或 catch 开头, 从 1.5.0 版本开始, 可以在 bind 和 catch 后加上一个冒号
- 同时在当前页面的 Page 构造器中定义对应的事件处理函数, 如果没有对应的函数, 触发事件时会报错
- 比如当用户点击该 button 区域时,达到触发条件生成事件 tap,该事件处理函数会被执行,同时还会收到一个事件对象 event
事件类型
某些组件会有自己特性的事件类型
- 比如 input 有 bindinput / bindblur / bindfocus 等
- 比如 scroll-view 有 bindscrolltoupper / bindscrolltolower 等
当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中
currentTarget和target的区别
- target 触发事件的源组件
- currentTarget 事件绑定的当前组件
html
<view id="outer" class="outer" data-name="why" bindtap="onOuterViewTap">
<view id="inner" class="inner"></view>
</view>
<script>
Page({
onOuterViewTap(event) {
console.log(event.target)
console.log(event.currentTarget)
const name = event.currentTarget.dataset.name
console.log(name)
}
})
</script>
touches和changedTouches的区别
- 在 touchend 中不同
- 多手指触摸时不同
html
<view class="touches" bindtap="onTouchTap" bindlongpress="onLongPress" bindtouchend="onTouchEnd">
多指触摸
</view>
<script>
Page({
onTouchTap(event) {
console.log('tap:', event)
},
onLongPress(event) {
console.log('long:', event)
},
onTouchEnd(event) {
console.log('end:', event)
}
})
</script>
参数传递
当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过 data-属性 来完成:
- 格式:data-属性的名称
- 获取:e.currentTarget.dataset.属性的名称
案例
html
<view class="tab-control">
<block wx:for="{{ titles }}" wx:key="*this">
<view class="item {{index === currentIndex ? 'active': ''}}" bindtap="onItemTap" data-index="{{index}}">
<text class="title">{{ item }}</text>
</view>
</block>
</view>
<script>
Page({
data: {
titles: ['手机', '电脑', 'iPad', '相机'],
currentIndex: 0
},
onItemTap(event) {
const currentIndex = event.currentTarget.dataset.index
this.setData({ currentIndex })
}
}
</script>
事件冒泡和事件捕获
将 bind 替换为 catch: 阻止事件仅一步传递
html
<view class="view1" capture-bind:tap="onView1CaptureTap" bindtap="onView1Tap">
<view class="view2" capture-bind:tap="onView2CaptureTap" bindtap="onView2Tap">
<view class="view3" capture-bind:tap="onView3CaptureTap" bindtap="onView3Tap"></view>
</view>
</view>
<script>
Page({
onView1CaptureTap() {
console.log('onView1CaptureTap')
},
onView2CaptureTap() {
console.log('onView2CaptureTap')
},
onView3CaptureTap() {
console.log('onView3CaptureTap')
},
onView1Tap() {
console.log('onView1Tap')
},
onView2Tap() {
console.log('onView2Tap')
},
onView3Tap() {
console.log('onView3Tap')
}
}
</script>
mark数据传递
可以使用 mark
来识别具体触发事件的 target 节点。此外, mark
还可以用于承载一些自定义数据(类似于 dataset
)
html
<view class="mark" bindtap="onMarkTap" data-name="why" data-age="18" mark:name="kobe" mark:age="30">
<text mark:address="洛杉矶" class="title">mark</text>
</view>
<script>
Page({
onMarkTap(event) {
const data1 = event.target.dataset
console.log(data1)
const data2 = event.mark
console.log(data2)
}
}
</script>
细节注意事项:
- 如果存在同名的
mark
,父节点的mark
会被子节点覆盖 - 在自定义组件中接收事件时,
mark
不包含自定义组件外的节点的mark
- 不同于
dataset
,节点的mark
不会做连字符和大小写转换