原生小程序 - 事件

171 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情

小程序需要经常和用户进行某种交互,比如点击界面上的某个按钮或者区域,比如滑动了某个区域

所以在小程序中经常会触发各种各样的事件

事件可以绑定在组件上,将用户的行为反馈到逻辑层进行处理

当触发事件时,就会执行逻辑层中对应的事件处理函数

事件在被触发时,也会传递事件对象,事件对象可以携带额外信息,如 id, dataset, touches

事件是通过bind/catch这个属性绑定在组件上的

事件名以bind或catch开头, 从1.5.0版本开始, 可以在bind和catch后加上一个冒号

同时在当前页面的Page构造器中定义对应的事件处理函数, 如果没有对应的函数, 触发事件时会报错

绑定事件不需要使用mustache语法, 如果使用了mustache语法会导致对应的事件无法被正常触发

公共事件

以下事件是所有组件都可以触发的事件

image.png

某些组件会有自己特性的事件类型, 具体事件可以查看对应的组件文档

  • 比如input有bindinput/bindblur/bindfocus等
  • 比如scroll-view有bindscrolltowpper/bindscrolltolower等

事件对象

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

image.png

currentTarget 和 target

<!-- 
  当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过data-属性来完成
-->
<view id="outer" class="outer" data-name="Klaus" bindtap="handleTap">
  <view id="inner" class="inner"></view>
</view>
Page({
  // 点击div.inner组件后
  handleTap(e) {
    // target - 实际触发事件的那个组件 - div.inner
    console.log(e.target)
    // currentTarget - 实际处理事件函数的那个组件 - div.outer
    console.log(e.currentTarget)

    // 因为target并不一定是处理事件的那个组件,而currentTarget一定是处理事件的那个组件
    // 也就是说小程序中的事件是存在冒泡和捕获过程的
    // 所以如果我们希望可以正确获取我们传递给事件的那些自定义参数,推荐使用currentTarget来进行获取
    console.log(e.currentTarget.dataset.name)
  }
})

touches和changedTouches

image.png

当刚开始点击的时候,只有一个手指,所以此时touches和changedTouches中对应的值是一致的

但是当一个手指按住不动,在添加第二个和第三个手指的时候,因为新增加了两个手指

所以touches中记录的是所有的手指个数,所以是长度为3的数组

而changedTouches中记录的是改变的手指个数,所以是长度为2的数组

同理,在点击结束手指离开的时候

在touchstart事件中,因为此时点击在屏幕上的手指为一个,且是从零个手指变成一个手指的点击

所以此时touches和changedTouches中的值是一致的,是长度为1的数组

但是在touchend事件中,因为此时点击屏幕的手指由一个转变为了零个手指,

所以此时touches数组为长度为0的数组,而changedTouches为长度为1的数组

image.png

参数传递

wxml

<view class="list">
  <!-- data-current-tab 在dataset中会被转换为 currentTab -->
  <view 
    wx:for="{{ list }}" 
    wx:key="*this" 
    class="item" 
    data-current-tab="{{ item }}"
    bindtap="handleTap">
    <text class="{{ item === activeTab ? 'active' : '' }}">{{ item }}</text>
  </view>
</view>

wxs

Page({
  data: {
    list: ['衣服', '裤子', '鞋子'],
    activeTab: '衣服'
  },

  handleTap(e) {
    this.setData({
      // 获取到的数据 最好通过currentTarget去获取
      // 以确保对应的元素为实际处理当前事件的那个元素
      activeTab: e.currentTarget.dataset.currentTab
    })
  }
})

wxss

.list {
  display: flex;
  align-items: center;
}

.item {
  flex: 1;
  text-align: center;
}

.item text {
  padding-bottom: 6rpx;
  display: inline-block;
}

.active {
  color: #f99;
  border-bottom: 2px solid #f99;
}

mark

使用data-*进行参数传递,在获取参数的时候需要区分currentTarget和target,且获取层级较深

为此自小程序sdk2.7开始,提供了一种新的用于进行参数传递的方式,即mark

<button mark:btnArg="button上传递的参数" bindtap="handleTap">
  <text mark:textArg="text上传递的参数">click me</text>
</button>
Page({
  handleTap(e) {
    // mark的默认值是一个空对象
    // mark中会存放所有位于该事件捕获和冒泡流程中所有元素对应的被mark标签的属性
    console.log(e.mark) // => {textArg: "text上传递的参数", btnArg: "button上传递的参数"}
  }
})

事件冒泡和捕获

image.png

  1. 事件名可以全小写,也可以使用冒号进行拼接,他们之间是没有任何区别的
bindtap === bind:tap
capture-bindtap === caoture-bind:tap
  1. bind表示的事件,该事件会正常捕获和冒泡

    但是如果使用catch表示该事件会阻止事件的进一步传递

# 该事件可以正常的进行事件冒泡和捕获
bindtap

# 该事件会阻止事件的冒泡
catchtap

# 该事件会阻止事件的捕获
capture-catchtap