交互的脉络:小程序事件系统详解

交互的脉络:小程序事件系统详解

所属专栏 :《微信小程序-实战笔记30讲》
作者:码力无边

前言

在前面的课程中,我们已经学会了使用bindtap来响应用户的点击事件。这就像我们学会了在家里的电灯开关上贴一个"开灯"的标签,按下它,灯就会亮。这解决了最基本的需求。

但是,如果家里的布局很复杂呢?比如,你按下了客厅的总开关,是只希望客厅的灯亮,还是希望整个房子的灯都跟着亮?如果你想在开灯的同时,顺便告诉控制中心"是我按的,现在是晚上8点",又该怎么做?

这些更复杂的交互场景,背后都依赖于一套清晰的规则,这就是小程序的事件系统。理解事件系统,就如同掌握了整个交互世界的"交通规则"。

今天,我们将深入事件系统的三大核心:

  1. 事件绑定与事件对象 :重新审视我们熟悉的bindtap,并解剖事件触发时传递的event对象。
  2. bind vs catch:揭秘事件冒泡机制,以及如何利用它或阻止它。
  3. 传递自定义参数 :学习如何通过data-*属性,在事件中携带额外的信息。

掌握这些,你将能够设计出更精妙、更高效的用户交互逻辑。

一、再探事件绑定与事件对象

我们先回顾一下事件处理流程:

  1. WXML中绑定 :在组件上使用bindcatch加上事件类型(如bindtap)来指定事件处理函数。
  2. JS中处理 :在页面的.js文件中定义同名函数,该函数会自动接收一个event对象作为参数。

这个event对象,就是事件发生时的"现场快照",它包含了关于这次事件的所有关键信息。让我们来解剖一下它里面有什么宝贝。

动手实践
WXML:

html 复制代码
<button bindtap="handleTap">点我查看Event对象</button>

JS:

javascript 复制代码
Page({
  handleTap: function(event) {
    console.log(event);
  }
})

点击按钮后,在控制台展开打印出的event对象,你会看到很多属性,我们重点关注以下几个:

  • type : string,事件的类型,这里是'tap'
  • timeStamp : number,事件生成时的时间戳。
  • target : object,触发事件的源头组件 。即使事件冒泡,target也永远是最初那个被点击的组件。
    • event.target.id: 源头组件的id
    • event.target.dataset: 源头组件上所有data-*属性组成的集合。
  • currentTarget : object当前正在处理事件的组件 。在事件冒泡过程中,currentTarget会变化,而target不会。
    • event.currentTarget.id: 当前组件的id
    • event.currentTarget.dataset: 当前组件上所有data-*属性组成的集合。

targetcurrentTarget的区别非常重要,我们将在下一节的事件冒泡中看到它们的威力。

二、事件冒泡:bindcatch 的博弈

什么是事件冒泡?

想象一下,你往一个平静的湖里扔一颗石子,水波会从落点(target)开始,一圈圈向外扩散。

在WXML的嵌套结构中,事件的触发也类似。当你点击一个内部组件时,这个事件不仅会通知它自己,还会像气泡一样,从水底(内层组件)不断向上(外层组件)浮起,依次触发所有父级组件上绑定的同类型tap事件,直到文档的根节点。这个过程,就叫做事件冒泡

bind:放行者

使用bind绑定的事件,默认会参与冒泡。它会执行自己的处理函数,然后把事件继续向上传递。

catch:终结者

使用catch绑定的事件,是一个"霸道"的捕获者。它会执行自己的处理函数,然后立即终止事件的冒泡过程,后续的父级组件将收不到这个事件。

动手实践 - 理解冒泡与阻止冒泡:
WXML:

html 复制代码
<!-- 使用 bind -->
<view class="outer-box" bindtap="handleOuterTap">
  Outer Box (bind)
  <view class="inner-box" bindtap="handleInnerTap">
    Inner Box (bind)
  </view>
</view>

<!-- 使用 catch -->
<view class="outer-box" bindtap="handleOuterTap" style="margin-top: 20rpx;">
  Outer Box (catch)
  <view class="inner-box" catchtap="handleInnerTap">
    Inner Box (catch)
  </view>
</view>

JS:

javascript 复制代码
Page({
  handleOuterTap: function() {
    console.log('触发了 Outer Box 的 tap 事件');
  },
  handleInnerTap: function() {
    console.log('触发了 Inner Box 的 tap 事件');
  }
})

实验结果:

  1. 点击第一个例子中的"Inner Box (bind)",你会发现控制台依次打印了"Inner Box"和"Outer Box"的日志。这就是事件冒泡。
  2. 点击第二个例子中的"Inner Box (catch)",你会发现控制台只打印 了"Inner Box"的日志。"Outer Box"的事件被catch阻止了。

应用场景:

  • 事件委托 :当一个列表有很多个子项都需要点击事件时,你不需要给每个子项都绑定bindtap。你可以在它们的父容器上绑定一个bindtap,然后通过event.target来判断用户具体点击的是哪个子项。这可以极大地提升性能。
  • 防止误触 :在一个弹窗上,通常我们会给遮罩层绑定一个catchtap来关闭弹窗,同时阻止点击事件穿透到下方的页面内容。

三、data-*:事件传递的"秘密信使"

我们经常会遇到这样的需求:一个商品列表中有很多个商品,点击任何一个,都需要跳转到对应的详情页。我们如何知道用户点击的是哪个商品呢?

这时,data-*自定义属性就派上用场了。我们可以将任何需要传递的数据,以data-为前缀,写在组件的属性上。

规则:

  • data-开头,后面跟自定义的名称,如data-product-id
  • 多个单词用连字符-连接。
  • 在事件对象的dataset中,连字符会被自动转换成驼峰命名法(productId)。

动手实践 - 商品列表点击跳转:
JS (先准备数据):

javascript 复制代码
Page({
  data: {
    products: [
      { id: 'p001', name: '高性能笔记本' },
      { id: 'p002', name: '无线机械键盘' },
      { id: 'p003', name: '4K显示器' }
    ]
  }
})

WXML (使用wx:for循环和data-*)

html 复制代码
<view 
  class="product-item" 
  wx:for="{{products}}" 
  wx:key="id"
  bindtap="gotoDetail"
  data-product-id="{{item.id}}"
  data-product-name="{{item.name}}"
>
  {{item.name}}
</view>

在这里,我们为每个商品项绑定了同一个gotoDetail事件,并通过data-product-iddata-product-name把每个商品的独特信息"藏"在了组件上。

JS (处理事件并获取数据):

javascript 复制代码
Page({
  // ... data 部分 ...
  gotoDetail: function(event) {
    // 通过 event.currentTarget.dataset 获取数据
    const dataset = event.currentTarget.dataset;
    const productId = dataset.productId; // 注意驼峰命名
    const productName = dataset.productName;

    console.log(`用户点击了商品,ID是:${productId},名称是:${productName}`);
    
    // 接下来可以执行页面跳转
    // wx.navigateTo({
    //   url: `/pages/detail/detail?id=${productId}`
    // })
  }
})

点击不同的商品项,看看控制台打印出的ID和名称是不是正确的?通过data-*,我们用一个事件处理函数就优雅地管理了整个列表的点击行为。

结语

今天,我们深入了小程序交互的底层脉络------事件系统。现在,你不仅知道如何响应事件,更理解了事件的传播方式和控制方法。我们回顾一下核心:

  • 事件对象 event 是信息宝库,event.target(源头)和 event.currentTarget(当前处理者)是区分点击来源的关键。
  • 事件冒泡 是默认行为,bind 会放行冒泡,而 catch 会终止它,合理运用可以优化性能和避免误触。
  • data-* 自定义属性 是在WXML向JS传递数据的"秘密信使",是实现列表类交互的首选方案。

掌握了事件系统,你就拥有了精细化操控用户交互的能力。这为我们构建更复杂的应用打下了坚实的基础。

在下一讲,我们将学习小程序中一个非常强大的特性:列表与条件渲染 。我们将学习如何使用wx:forwx:if来动态地生成页面内容,让你的小程序能够根据数据的变化,呈现出千变万化的界面。

我们下篇见!

相关推荐
DokiDoki之父2 小时前
web核心—HTTP
前端·网络协议·http
咖啡の猫2 小时前
Vue 简介
前端·javascript·vue.js
Moment3 小时前
写代码也能享受?这款显示器让调试变得轻松又高效!😎😎😎
前端·后端
゜ eVer ㄨ3 小时前
React-router v6学生管理系统笔记
前端·笔记·react.js
产品大道3 小时前
[分享] 千呼万唤始出来《WX小程序反编译教程》
小程序
m0_526119403 小时前
pdf文件根据页数解析成图片 js vue3
前端·javascript·pdf
时光少年3 小时前
Compose AnnotatedString实现Html样式解析
android·前端
用户904706683573 小时前
假数据生成器——JSONPlaceholder
前端
光影少年3 小时前
react16中的hooks的底层实现原理
前端·react.js·掘金·金石计划