Skip to content

事件处理

事件监听

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 等

image-20231007154454475

当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中

image-20231007154959987

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的区别

  1. 在 touchend 中不同
  2. 多手指触摸时不同
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>

image-20231007161727747

image-20231007161747026

参数传递

当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过 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>

事件冒泡和事件捕获

image-20231007164444905

将 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 不会做连字符和大小写转换

常备不懈,才能有备无患