click和touch事件触发顺序 糊里糊涂解决的奇怪bug

发布于:2025-07-31 ⋅ 阅读:(22) ⋅ 点赞:(0)

问题详情

在嵌入式硬件设备里,测试 “点击input密码框,弹出第三方自带键盘,点击密码框旁的小眼睛,切换输入内容加密状态,键盘收起/弹出状态不变” 的功能逻辑;实际情况却是 “点击键盘或input框之外的任何地方,键盘都会收起” 。

 <div class="w-440 h-90 items-center">
   <text class="fs-24 fw-500 mr-20">密码/text>
   <input id="input" type="{{type}}" value="{{inputvalue}}" class="w-232 h-90 fs-24 bg-cardBg items-center input-style"
     style="keyboard: {{ keyboardStyle }}; width: {{ inputwidth }}px;" placeholder="{{placeholder}}"
     onclick="handleClick" />
 </div>
 <div onclick="changeType" class="w-98 h-90 absolute" style="top: -2px; right: -2px;">
   <image if="{{showPassword}}" src="{{'/common/images/eye.png'}}" class="absolute top-25 right-24 w-41 h-41"></image>
   <image else src="{{'/common/images/eye-close.png'}}" class="absolute top-25 right-24 w-41 h-41"></image>
 </div>
    
/////

  changeType(event) {
    this.showPassword = !this.showPassword;
   	event.stopPropagation(); // 阻止冒泡
  },

在这里插入图片描述
(页面编写基于Vela JS框架)

问题分析

由于是第三方键盘,暂时看不到其底层处理方式,初步判断出两个逻辑,一是键盘的弹出和input框的focus事件相关,二是键盘弹出时,会默认在整屏生成蒙层,用户点击时触发蒙层绑定的交互事件,判断如果是非input框范围,则收起键盘(大众逻辑)

解决思路

思路1:不去考虑第三方键盘的底层处理方式,在用户点击小眼睛时,强制触发input框的focus事件

 changeType(event) {
    this.showPassword = !this.showPassword;
    if (this.focus) {
      this.$element("input").focus({focus: true})
    }
    event.stopPropagation(); // 阻止冒泡
  },

结果导致,点击小眼睛时键盘闪烁?外加需要点击两次小眼睛才会切换小眼睛的状态,就像是生成了两个蒙层,点两次才能点到小眼睛(看不到源代码,咱也是瞎猜)

思路2:如果蒙层上绑定的是onclick事件(大众逻辑),我们可以在小眼睛上绑定一个比onclick事件更快响应的事件,并在事件处理函数内,阻止事件冒泡/穿透到蒙层

这里就涉及到,click和touch事件的触发顺序了

事件触发顺序:touchstart → touchmove → touchend → click
click与touchstart触发时间差约300ms,因需区分双击和单击

我们虽然无法确认蒙层是位于小眼睛的上层还是下层,但只要小眼睛上事件能触发,我们就可以将小眼睛上绑定的事件改为最快响应的touchstart,并阻止事件冒泡/穿透

 <div ontouchstart="changeType" class="w-98 h-90 absolute" style="top: -2px; right: -2px;">
   ...
 </div>

/// 

 changeType(event) {
    this.showPassword = !this.showPassword;
    if (this.focus) {
      this.$element("input").focus({focus: true})
    }
    event.stopPropagation(); // 阻止冒泡
    event.preventDefault(); // 阻止默认事件
  },

问题解决了!键盘不闪了,小眼睛也能正常点击

但是又想到小眼睛的点击没有默认事件需要阻止,就把event.preventDefault();删了,测试无影响;又想到event.stopPropagation();生效的前提是,蒙层是小眼睛的祖先元素,为了确认又把event.stopPropagation();删了,发现也没有影响…

奇怪啊,所以解决这个问题的关键,仅仅只是将click改为了touchstart?难道小眼睛的闪烁是click的300ms延迟导致的?想不明白了…

结果就这么简单解决了…

 <div ontouchstart="changeType" class="w-98 h-90 absolute" style="top: -2px; right: -2px;">
   ...
 </div>

/// 

 changeType(event) {
    this.showPassword = !this.showPassword;
    if (this.focus) {
      this.$element("input").focus({focus: true})
    }
  },

网站公告

今日签到

点亮在社区的每一天
去签到