一 通过实例来认识
(一) 给出代码
我们直接通过一个实例来引入我们想要讲解的内容:
<input type="text" bindinput="handleInput" />
<button bindtap="handletap" data-operation="{{1}}">+</button>
<button bindtap="handletap" data-operation="{{-1}}">-</button>
<view>你输入的是:{{number}}</view>
上述代码就四行,首先是一个 input 输入框,目的是用来输入一些值,同时下面标签就会显示,接着是两个 button 用来分别执行 +1 或者 -1 的操作,最后一个 view 标签就是为了 进行数据输入或变化的回显
Page({
data: {
number:0
},
handleInput(e){
this.setData({
number:e.detail.value
})
},
handletap(e){
const operation = e.currentTarget.dataset.operation
this.setData({
number:this.data.number + operation
// number:this.data.number * 1 + e.currentTarget.dataset.operation
})
}
})
这里给出的就是对应的 js 代码,涉及到了对于输入以及 +1 或者 -1 操作的一个具体逻辑处理,核心就是围绕 data 中定义的 number 变量进行处理(具体逻辑接着会提到),结合前面的 wxml 代码分析一下:
(二) 分析代码
分析标签中属性中的部分:
bindinput="handleInput"
bindtap="handletap" data-operation="{{-1}}"
- 绑定事件的关键字是
bind
例如上面用到的bindinput
和bindtap
就是分别对于输入和点击事件的一个绑定 - 而后面的一个名称例如 handleInput 就是自定义的事件名称,我们在 js 中书写方法也是与这个后面的名称相对应
- 注:绑定关键字为 bind 仅针对此例,并非只是 bind
补充几个 input 中相对常用的事件绑定属性
属性 | 类型 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|
bindinput | eventhandle | 是 | 键盘输入时触发,event.detail = {value, cursor, keyCode},keyCode 为键值,2.1.0 起支持,处理函数可以直接 return 一个字符串,将替换输入框的内容。 | 1.0.0 |
bindfocus | eventhandle | 是 | 输入框聚焦时触发,event.detail = { value, height },height 为键盘高度,在基础库 1.9.90 起支持 | 1.0.0 |
bindblur | eventhandle | 是 | 输入框失去焦点时触发,event.detail = {value: value} |
如果想要获取到输入框的值,通过时间源对象来获取 e.detail.value
(1) JS 中赋值问题
输入框中输入的值赋值给 data 中的 number,如果按惯性思维直接赋值是有问题的
-
不能使用 this.data.numer = e.detail.value
-
不能使用 this.number = e.detail.value
-
需要使用:
this.setData({
number:e.detail.value
})
(2) JS 中按钮传参问题
添加按钮点击事件:关键字是 bindtap
我们按钮想要达到的目的是,点击按钮进行 number 的 +1 或者 -1 ,通过根据我们上面的 js 代码可以看出,这里所采用实现的方式是根据页面属性中传来的参数,进行相加,例如 number + 1 或者 number + (-1) 达到加减效果
但是,直接传参是有问题的!!!只能通过属性赋值
正解:bindtap="handletap" data-operation="{{-1}}"
(3) 忘记想要的值对应在哪里
说明:如果记不住例如:e.detail.value、e.currentTarget.dataset.operation 则可以使用如下的方式,先把事件打印出来
handleInput(e){
console.log(e);
},
在找到对应的层级
二 事件绑定类别
(一) 分类
我们上面的例子使用了 bind 这个事件绑定关键字,但是它会发生冒泡事件
-
冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递
-
非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递
我们还有一些别的选择,我们下面在 (3) (4) 中会一个一个进行分析
- bind:普通绑定(会发生冒泡事件)
- catch:可以阻止事件冒泡
- capture-bind: 捕获阶段绑定(后面的捕获流程和冒泡流程还会继续执行)
- capture-catch:中断捕获阶段和取消冒泡阶段,在捕获阶段阻止事件的传递
(二) 冒泡事件列表
在分析前,我们还要补充一个点,那就是 WXML 的冒泡事件列表:
我们起码现在知道了 bind 和 catch 的作用,但是正例如我们上面用到的 bindinput 或者 bindtap ,bind 后面的内容又是什么呢?是固定的还是自定义的呢?这一段我直接贴一段官网的文档说明
类型 | 触发条件 | 最低版本 |
---|---|---|
touchstart | 手指触摸动作开始 | |
touchmove | 手指触摸后移动 | |
touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 | |
touchend | 手指触摸动作结束 | |
tap | 手指触摸后马上离开 | |
longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 | 1.5.0 |
longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替) | |
transitionend | 会在 WXSS transition 或 wx.createAnimation 动画结束后触发 | |
animationstart | 会在一个 WXSS animation 动画开始时触发 | |
animationiteration | 会在一个 WXSS animation 一次迭代结束时触发 | |
animationend | 会在一个 WXSS animation 动画完成时触发 | |
touchforcechange | 在支持 3D Touch 的 iPhone 设备,重按时会触发 | 1.9.90 |
注:除上表之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如 form 的submit事件,input 的input事件,scroll-view 的scroll事件,(详见各个组件)
看完上面的表格,应该就比较清楚了,正因为我们很多事件都是通过手机点一下某个组件等进行,所以 tap 是比较常用的
(三) bind 和 catch
说明:代码在下面自取
(1) bind
前面我们提到了,使用 bind 会发生冒泡事件,我们来模拟一下
首先我们写了三个嵌套的 view 标签,然后接着使用 bindtap 进行事件绑定,进行一个基本的打印逻辑,看看会有什么情况发生
当点击中间层后,首先执行了中间层的事件效果,但是最外层的事件效果也被执行了,这也就是冒泡事件发生了
冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递
非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递
(3) catch
这一次我们仍然点击中间这一层,如果在上面的基础上,我们将中间层的事件绑定使用 catch,而不是 bind ,结果会是怎样呢?
结果就是冒泡事件被阻止了,点击后只显示中间层的事件
(四) capture-bind 和 capture-catch
前面提及到这两个内容的时候,我们提到了一个概念也就是事件的捕获阶段,简单说一下:
自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。
(1) capture-bind:tap
依旧是刚才的例子,将三层的属性都修改为 capture-bind:tap="handleTap1"
这种形式的
当我们点击最里层的内容时,执行结果如下:
即它与包裹它的两层都执行了,且是从外至内
(2) capture-catch:tap
将三层属性修改为 capture-catch:tap="handleTap1"
这种形式,点击任意一层:
结果都是只执行最外层的
(五) 简单总结
- bind:点击会触发它和包裹它的所有事件,且从内向外执行(冒泡事件)
- catch:点击哪个就触发哪个,独立的(阻止冒泡事件)
- capture-bind: 点击会触发它和包裹它的所有事件,且从外向内执行
- capture-catch:如何点击都只会触发最外层的事件
(六) 代码提取
代码给出的是 capture-bind:tap 的情况, bindtap 或者 catchtap 以及 capture-catch 只需要将 capture-bind:tap 替换就行了
wxml
<view class="outer" capture-bind:tap="handleTap1">
这是最外层
<view class="middle" capture-bind:tap="handleTap2">
这是中间层
<view class="inner" capture-bind:tap="handleTap3">
这是最里层
</view>
</view>
</view>
wxss
.outer {
text-align: center;
background-color: red;
height: 300rpx;
}
.middle {
background-color: orange;
60%;
height: 200rpx;
}
.inner {
background-color: yellow;
60%;
height: 100rpx;
}