当前位置: 首页 > news >正文

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

文章目录

    • 小程序的事件处理
      • 🧊小程序的事件监听
      • 🧊常见事件类型划分
      • 🧊事件对象属性分析
      • 🧊事件参数传递方法
      • 🧊事件传递案例练习
      • 🧊事件冒泡事件捕获
      • 🧊知识点补充mark

小程序的事件处理

🧊小程序的事件监听

什么时候会产生事件呢?

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

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

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

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

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

事件时如何处理呢?

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

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

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

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

事件的基本使用

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

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

<!-- 绑定上onBtnTap事件 -->
<button size="mini" bindtap="onBtnTap">按钮</button>
// index.js

// 在对应的 Page 中找到相应的事件处理函数
Page({
	onBtnTap() {
		console.log("按钮点击");
	}
})
  • 当某个事件触发时, 在相应的 Page 中对应的事件处理函数, 会产生一个事件对象, 并且这个对象被传入到该回调函数中,参数是event。
// index.js

Page({
	onBtnTap(event) {
		console.log(event);
	}
})
  • 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
  }]
}

🧊常见事件类型划分

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

比如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结构

<!-- index.wxml -->

<view id="view" bindtap="onViewTap" class="box">
	<button id="btn" size="mini" type="primary">按钮</button>
</view>

给view添加如下样式

/* index.wxss */

.box {
	width: 400rpx;
	height: 400rpx;
	background-color: skyblue;
}

展示效果如下

在这里插入图片描述

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

// index.js

Page({
	onViewTap(event) {
		console.log(event.target);
		console.log(event.currentTarget);
	}
})

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

{id: "view", offsetLeft: 0, offsetTop: 0, dataset: {}}
{id: "view", offsetLeft: 0, offsetTop: 0, dataset: {}}

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

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

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

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


🧊事件参数传递方法

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

格式:data-属性的名称

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

自定义属性的基本使用

  • wxml文件中通过自定义属性, 将数据传递到对应的事件处理函数中
<!-- index.wxml -->

<!-- 通过自定义属性传递数据 -->
<view 
	bindtap="onArgumentTap"
	data-name="chenyq"
	data-age="18"
	data-height="1.88"
>
	参数传递
</view>
  • 在对应的事件处理函数中获取到传递的数据
// index.js

Page({
	onArgumentTap(event) {
		console.log(event.currentTarget.dataset.name);
		console.log(event.currentTarget.dataset.age);
		console.log(event.currentTarget.dataset.height);
	}
})

🧊事件传递案例练习

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

在这里插入图片描述

  • 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>
  • js的逻辑代码
Page({
	data: {
		titles: ["衣服", "鞋子", "裤子"],
		currentIndex: 0
	},
	onTitleTap(event) {
		this.setData({
			currentIndex: event.currentTarget.dataset.index
		})
	}
})
  • wxss文件的样式
.active {
	color: pink;
	border-bottom: 3px solid pink;
}

.box {
	display: flex;
	justify-content: space-between;
}

.box .title {
	margin: 0 10px;
	padding: 10rpx 40rpx;
}

🧊事件冒泡事件捕获

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

在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>
  • 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>

🧊知识点补充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>
  • 获取mark传递的数据, 通过event.mark获取
Page({
	onBtnTap(event) {
		// 通过event.mark获取
		console.log(event.mark);
	}
})

相关文章:

  • SSM大学生心理健康服务平台毕业设计-附源码071131
  • springboot绿色食品商城毕业设计-附源码061109
  • 猿创征文|技术成长之路-【Java编程系列】之文件OSS存储实践:Amazon S3实现文件上传下载
  • Docker10:DockerFile的介绍与指令说明
  • Java求数组所有子数组的两种方法
  • j2cache入门使用
  • dockerkubernets篇(二十七)
  • 操作系统--用JavaScript实现银行家算法
  • js严格模式
  • MySQL数据库——使用聚合函数查询
  • Java Excel 合并单元格 Java Excel 实现尾部添加数据 Java Excel 合并单元格 添加数据 poi excel 合并单元格
  • SSM仓库管理系统毕业设计-附源码061015
  • 猿创征文|Docker【配置好的镜像】 迁移到【新服务器】上 不需要重新配置环境参数·爽
  • 关于现代化应用和云原生应用
  • R语言矩阵运算:矩阵转置、计算逆矩阵、两个矩阵的相乘、构建nxn对角(单位)矩阵
  • Angular6错误 Service: No provider for Renderer2
  • js写一个简单的选项卡
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • React-flux杂记
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 算法之不定期更新(一)(2018-04-12)
  • 用 Swift 编写面向协议的视图
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • #if #elif #endif
  • (Git) gitignore基础使用
  • (转)fock函数详解
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转)详解PHP处理密码的几种方式
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .cn根服务器被攻击之后
  • .jks文件(JAVA KeyStore)
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .NET MVC第三章、三种传值方式
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • .net中我喜欢的两种验证码
  • [ SNOI 2013 ] Quare
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [2023-年度总结]凡是过往,皆为序章
  • [ai笔记9] openAI Sora技术文档引用文献汇总
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [CC2642r1] ble5 stacks 蓝牙协议栈 介绍和理解
  • [Codeforces] probabilities (R1600) Part.1
  • [hadoop读书笔记] 第十五章 sqoop1.4.6小实验 - 将mysq数据导入HBASE
  • [JavaEE] 线程与进程的区别详解
  • [LeetCode] 197. 上升的温度
  • [leetcode] Balanced Binary Tree
  • [MicroPython]TPYBoard v102 CAN总线通信
  • [OCR]Python 3 下的文字识别CnOCR
  • [python3] 装饰器
  • [RK3568][Android11]内核Oops日志分析
  • [RK-Linux] 移植Linux-5.10到RK3399(四)| 检查HDMI配置与打开内核LOGO显示