美文网首页Cocos Creator
CreatorPrimer|触摸事件冒泡

CreatorPrimer|触摸事件冒泡

作者: 张晓衡 | 来源:发表于2018-12-19 14:29 被阅读51次

    这两天正在愁公众号写点什么,打开微信看到uikiller老用户「悦雨」遇到了一个问题:

    地图拖动与子节点触摸事件产生冲突,表现为在子节点上拖动,地图不能动

    一句话不太好描述问题,在征得「悦雨」同意后,将这次交流的内容截图出来:



    在与「悦雨」的交流过程中,我用ScrollView + TileMap + Button花了五分钟做了一个小测试,将TiledMap放在ScrollView中,在TiledMap中又放值了一个按钮,验证了一下曾经的经验是否任然有效,结果是OK的,于是将测试场景发给了「悦雨」。

    快速原型

    有了这个案例今天就以这个地图场景为例,看看不写代码,利用引擎内置组件,如何快速实现一个原型或组件功能测试 ,请看下面视频:

    【插入视频】

    从源码中学习

    为什么在ScrollView中拖动,不会触发子节点的TOUCH事件呢?先看下ScrollView上的一个关键属性:


    ScrollView.png

    有了Cancel Inner Event这个线索,我们直接从ScrollView组件源码入手,看看它是什么实现的。

    以cc.ScrollView组件为例,看如何定位组件源码:

    1. 使用Chrome浏览器启动游戏预览
    2. 打开Chrome DevTools工具
    3. 键盘快捷键:ctrl + p 或 cmd + p
    4. 输入:ccscrollview (引擎组件原文件名公式:cc + 组件名)
    5. 从显示的列表上找到要查看的源码文件

    选择CCScrollView.js文件,自动跳转到Sources标签,打开文件内容,键入ctrl + f 或 cmd + f 在当前文件中搜索:cancelInnerEvents,找到关键代码:

    ScrollView源码.png
    1. 可以看到976行中,当this.cancelInnerEvents变量为真可能会执行到下面的代码,设置成员变量this._touchMoved = true
    2. 再看1006行_onTouchEnd函数,在这里判断了_touchMoved这个变量,停止TOUCH_END事件的传播,这样子节点的触摸事件就不会被触发了
    3. 993行_onTouchMoved函数最后一行代码this._stopPropagationIfTargetIsMe(event)它是在有条件地停止TOUCH_MOVE事件的传播。

    通过上面的分析,再通过断点跟踪,在ScrollView和Button组件中分别打上断点,我们在Button组件上做点击,ScrollView组件的_onTouchEnded居然先被断下来,它是怎么做到的呢?

    在CCScrollView.js源码中搜“TOUCH_END”关键字,找到TOUCH事件注册的代码:

    image.png

    看看这里有与自己平时注册TOUCH事件有什么不同?相信你已经发现了,关键在最后一个参数:useCapture,用于是否捕获子节点事件,又称之为向下冒泡(默认是向上冒泡),下面以TOUC_END事件为例,简单说明一下:

    this.node.on(
      cc.Node.EventType.TOUCH_END,   //触摸事件类型
      this._onTouchEnded,            //事件处理函数
      this,                          //事件处理函数的this上下文(使用箭头函数时通常被省略)
      true                           //是否捕获子节点Touch事件
    );
    

    为了帮助大家更好地理解,我做了个简单的小组件,请看代码:

    cc.Class({
        extends: cc.Component,
        properties: {
            useCapture: false, //是否启用捕获
        },
        onLoad () {
            this.node.on(
                cc.Node.EventType.TOUCH_END,
                () => cc.log('touchend', this.node.name), //测试时观察日志输入出
                this, 
                this.useCapture
            );
        }
    });
    

    把这个组件挂到两个父子关系的节点上,在父节点上开启捕获,看下面截图:


    运行点击红色节点,看看日志输出:



    从日志中看到白色节点先响应,然后是红色节点,我们把白色父节点的UseCapture关闭,再看看日志输出:


    这次是红色子节点先响应,白色父节点后响应,更多细节可以参考Cocos Creator官方文档:https://docs.cocos.com/creator/manual/zh/scripting/internal-events.html?h=%E5%86%92%E6%B3%A1

    还有对应的官方范例:TouchPropagation

    题外话

    这次除了教程,还想再聊一个事情,经常会有同学通过微信、QQ、公众号向Shawn咨询问题,首先感谢大家对shawn的信任,如果是在自己的能力范围内且对大家帮助的内容,Shawn一定真诚对待,这也正是「奎特尔星球」内容的重要来源。但是因为个人能力和时间有限,不是每一个人的问题Shawn都能解答,还望大家见谅。

    微信、QQ很容易让人在工作时分心,一般我在做事的时候会将手机静音或离远一点,公众号上偶尔也收有留言,但有时会忘记去公众号上查看,超过24小时的留言,看到了想回复也无没办法,很是无奈。为了能把公众号做好,Shawn特地定制了一个邮箱:shawn@creator-star.cn,如有问题讨论或投稿欢邮件联系,公众号需要大家的支持和帮助,愿我们一起成长!

    相关文章

      网友评论

        本文标题:CreatorPrimer|触摸事件冒泡

        本文链接:https://www.haomeiwen.com/subject/smtpnftx.html