• 【小程序】中的事件处理详解


    小程序的事件处理

    🧊小程序的事件监听

    什么时候会产生事件呢?

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

    事件是视图层到逻辑层的通讯方式;

    事件可以将用户的行为反馈到逻辑层进行处理;

    事件可以绑定在组件上,当触发事件时,就会执行逻辑层中对应的事件处理函数;

    事件对象可以携带额外信息,如 id, dataset, touches;

    事件时如何处理呢?

    事件是通过bind/catch这个属性绑定在组件上的(和普通的属性写法很相似, 以key=“value”形式);

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

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

    比如当用户点击该button区域时,达到触发条件生成事件tap,该事件处理函数会被执行,同时还会收到一个事件对象event

    事件的基本使用

    • 在组件中绑定一个事件处理函数。

    bindtap,表示当用户点击该组件的时候会在该页面对应的 Page 中找到相应的事件处理函数。

    
    <button size="mini" bindtap="onBtnTap">按钮button>
    
    • 1
    • 2
    // index.js
    
    // 在对应的 Page 中找到相应的事件处理函数
    Page({
    	onBtnTap() {
    		console.log("按钮点击");
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 当某个事件触发时, 在相应的 Page 中对应的事件处理函数, 会产生一个事件对象, 并且这个对象被传入到该回调函数中,参数是event。
    // index.js
    
    Page({
    	onBtnTap(event) {
    		console.log(event);
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 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
      }]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    🧊常见事件类型划分

    某些组件会有自己特有的事件类型,大家可以在使用组件时具体查看对应的文档

    比如input特有的bindinput/bindblur/bindfocus

    比如scroll-view特有的bindscrolltowpper/bindscrolltolower

    这里我讲解几个所有组件都有的, 并且也比较常见的事件类型

    类型触发条件最低版本
    touchstart手指触摸动作开始
    touchmove手指触摸后移动
    touchcancel手指触摸动作被打断,如来电提醒,弹窗
    touchend手指触摸动作结束
    tap手指触摸后马上离开
    longpress手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发1.5.0
    longtap手指触摸后,超过350ms再离开(推荐使用 longpress 事件代替)

    🧊事件对象属性分析

    我们刚刚有简单演示, 当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中, 事件对象有哪些常见的属性呢?

    如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数必定会收到一个事件对象。

    BaseEvent 基础事件对象属性列表:

    属性类型说明基础库版本
    typeString事件类型
    timeStampInteger事件生成时的时间戳
    targetObject触发事件的组件的一些属性值集合
    currentTargetObject当前组件的一些属性值集合
    markObject事件标记数据2.7.1

    这里我重点讲解一下target和currentTarget的区别

    target

    触发事件的源组件(当前触发事件的组件)。

    属性类型说明
    idString事件源组件的id
    datasetObject事件源组件上由data-开头的自定义属性组成的集合

    currentTarget

    事件绑定的当前组件(处理事件的组件)。

    属性类型说明
    idString当前组件的id
    datasetObject当前组件上由data-开头的自定义属性组成的集合

    例如我们有如下一个wxml结构

    
    
    <view id="view" bindtap="onViewTap" class="box">
    	<button id="btn" size="mini" type="primary">按钮button>
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    给view添加如下样式

    /* index.wxss */
    
    .box {
    	width: 400rpx;
    	height: 400rpx;
    	background-color: skyblue;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    展示效果如下

    在这里插入图片描述

    我们监听view的点击事件, 在相应的page文件中打印target和currentTarget

    // index.js
    
    Page({
    	onViewTap(event) {
    		console.log(event.target);
    		console.log(event.currentTarget);
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时点击button组件之外的view组件区域, target和currentTarget是没有任何区别的, 大致打印如下

    {id: "view", offsetLeft: 0, offsetTop: 0, dataset: {}}
    {id: "view", offsetLeft: 0, offsetTop: 0, dataset: {}}
    
    • 1
    • 2

    当我们点击button组件, 会产生冒泡事件, 此时target和currentTarget就会有区别, 大致打印如下

    {id: "btn", offsetLeft: 0, offsetTop: 0, dataset: {}}
    {id: "view", offsetLeft: 0, offsetTop: 0, dataset: {}}
    
    • 1
    • 2

    此时触发事件的是button组件冒泡到view组件, 因此target打印的是button组件

    而此时处理事件的组件时view组件 (button组件冒泡到view组件, 由view组件处理事件), 因此currentTarget打印的是view组件


    🧊事件参数传递方法

    当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过data-属性来完成

    格式:data-属性的名称

    获取:event.currentTarget.dataset.属性的名称, 一般是通过currentTarget获取, 某些特殊场景是通过target获取

    自定义属性的基本使用

    • wxml文件中通过自定义属性, 将数据传递到对应的事件处理函数中
    
    
    
    <view 
    	bindtap="onArgumentTap"
    	data-name="chenyq"
    	data-age="18"
    	data-height="1.88"
    >
    	参数传递
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 在对应的事件处理函数中获取到传递的数据
    // index.js
    
    Page({
    	onArgumentTap(event) {
    		console.log(event.currentTarget.dataset.name);
    		console.log(event.currentTarget.dataset.age);
    		console.log(event.currentTarget.dataset.height);
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    🧊事件传递案例练习

    我们在小程序中, 做一个下面这样的导航栏, 要求点击哪一个导航栏, 文字颜色就改变, 并且对应的标签会显示一个横条

    在这里插入图片描述

    • wxml文件的结构
    <view class="box">
    	<block wx:for="{{ titles }}" wx:key="*this">
    		<text
    			bindtap="onTitleTap"
    			data-index="{{ index }}"
    			class="title {{ currentIndex === index ? 'active' : ' ' }}"
    		>
    			{{ item }}
    		text>
    	block>
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • js的逻辑代码
    Page({
    	data: {
    		titles: ["衣服", "鞋子", "裤子"],
    		currentIndex: 0
    	},
    	onTitleTap(event) {
    		this.setData({
    			currentIndex: event.currentTarget.dataset.index
    		})
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • wxss文件的样式
    .active {
    	color: pink;
    	border-bottom: 3px solid pink;
    }
    
    .box {
    	display: flex;
    	justify-content: space-between;
    }
    
    .box .title {
    	margin: 0 10px;
    	padding: 10rpx 40rpx;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🧊事件冒泡事件捕获

    当界面产生一个事件时,事件分为了捕获阶段和冒泡阶段

    在js阶段我有写过文章详细讲解事件冒泡和事件捕获, 如果对这两个概念不清楚的可以去了解一下:

    https://blog.csdn.net/m0_71485750/article/details/125112983

    在这里插入图片描述

    对于冒泡和捕获的概念我就不再过多赘述, 在这里演示一下如何阻止冒泡和捕获

    • bind 外,也可以用 catch 来绑定事件, 与 bind 不同的是, catch 会阻止事件向上冒泡

    例如在下边这个例子中,

    点击 inner view 会先后调用onViewTap3onViewTap2(因为 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • catch 阻止事件传递, 因此阻止事件捕获也是使用 catch, 捕获是通过capture-bind:tap="事件函数"来监听的
    <view id="outer" capture-bind:tap="onCaptureTap1">
      outer view
      
      <view id="middle" capture-catch:tap="onCaptureTap1">
        middle view
        <view id="inner" capture-bind:tap="onCaptureTap1">
          inner view
        view>
      view>
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    🧊知识点补充mark

    mark是一个比较新的语法, 小程序特有的传递数据的方法 (还是推荐使用data-*来传递数据)

    当事件触发时,事件冒泡路径上所有的 mark 会被合并,并返回给事件回调函数。(即使事件不是冒泡事件,也会 mark 。)

    mark基本使用

    • wxml中使用mark传递数据
    <button 
    	size="mini" 
    	bindtap="onBtnTap"
    	mark:name="chenyq"
    	mark:age="18"
    	mark:height="1.88"
    >
    	mark使用
    button>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 获取mark传递的数据, 通过event.mark获取
    Page({
    	onBtnTap(event) {
    		// 通过event.mark获取
    		console.log(event.mark);
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    AI只需26秒,就可以设计一款会走路的机器人
    简单理解注意力机制与实现
    【MySQL高级】SQL优化
    CSS------我又回来了
    我和Java的爱恨情仇
    [附源码]Java计算机毕业设计SSM仿咸鱼二手物品交易系统
    洛谷 P4197&&P7834 Peaks 题解
    Python实时采集Windows CPU\MEMORY\HDD使用率
    vue之作用域插槽和具名插槽slot、scope
    【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)
  • 原文地址:https://blog.csdn.net/m0_71485750/article/details/126411180