记录H5内嵌到flutter App的一个问题,引发后面使用fastClick,引发后面input输入框单击无效问题。。。

文章目录

概要

最近开发遇到一个很奇怪的问题,很特殊,为此记录一下

场景:H5单页面内嵌到App端

双方技术栈:H5 是 vue3 + vite / App 是flutter

发现问题

再一次开发的时候,ui检查样式是,发现页面无法点击了,必须重新进入才能点击,只有进入后的最开始点击的那一次生效,之后整个页面的点击事件都不生效


开始我保持怀疑的态度,因为我用了公司的安卓测试机,苹果测试机都没有问题,后来我用我自己的手机,突然发现,上诉问题复现了。。。

再经过我仔细来回测试,我发现只有IOS 18以上的系统才会出现这种问题,我公司的苹果测试机系统是16的

排查问题

  • 怀疑布局的问题

    为什么会有这个怀疑呢,因为当时我这个页面用了fixed以及absolute布局,大家都知道最开始的时候苹果对定位一直不是很友好的,为此我特意写了个demo,没有使用任何定位,但是其他的和我开发的内容一模一样,发现还是存在上述问题

  • 怀疑vue3的问题

    为什么这么说呢,是因为开始我问我的同事是否遇到过,都说没有,他们之前也开发过这种H5内嵌App的业务需求,但是他们用的是vue2的技术栈,为此我特意写了个vue2 和 vue3的demo,除了写法不一样,其他的是一模一样,结果发现都会出现上述问题

  • 怀疑App问题

    为什么会怀疑App的问题呢,因为我反复测试,发现最开始click点击事件都是好的,只有当点击调用App里面flutter方法后,唤起弹框后,我整个页面的click事件都失效了,怀疑是不是调用完他们的方法后,是不是有一层看不到的蒙版挡住了,但是App反馈说没有,并且说如果有蒙版那么不应该能滑动,事实是可以滑动,只是点击失效了

FastClick 解决问题

排查了半天,其实问题是知道了,但是解决呢,就比较恶心了,为什么呢,App说那没问题,所以App不解决,本来想说是App环境问题,但是老板用进入这个页面发现点击不了,肯定会找H5啊,因为页面内容是H5开发的,没办法只能想办法解决了

  • click失效,那尝试使用dblclick/touchstart 事件代替
    发现这两个事件都没问题,但是点击很麻烦或者误触,实际效果太不好了,但这两个事件都生效给我带来了新的思路
  • FastClick 包
    FastClick最原本的目的是用于解决移动设备上触摸事件延迟的 JavaScript 库,主要功能是消除这种 300 毫秒的延迟。其实现原理主要包括以下几个步骤
    1,监听触摸事件:
    FastClick 主要通过监听 touchstart 和 touchend 事件来处理用户的触摸行为。它会在touchstart 事件触发时记录时间戳和触摸目标。
    2,计算时间差:
    当 touchend 事件触发时,FastClick 会比较 touchstart 事件和 touchend 事件的时间差。如果时间差小于一定阈值(通常是 250 毫秒),且目标元素是可点击的(例如,按钮或链接),则 FastClick 会立即触发 click 事件,而不需要等待 300 毫秒。
    3,模拟 click 事件:
    在触摸结束时,如果触发条件符合,FastClick 会手动触发一个 click 事件,确保用户能够立即看到点击效果。它通过 document.createEvent 和 dispatchEvent 创建并分发 click 事件。
    4,处理移动端的特殊情况:
    FastClick 还处理了一些特定的移动端情况,例如:
    阻止默认的 click 事件,确保 FastClick 触发的事件可以在不产生延迟的情况下执行。
    确保只在可点击的元素上应用 FastClick,从而不会影响其他元素的默认行为。

可以简单的理解成一下内容,模拟简写FastClick伪代码示例

javascript 复制代码
function FastClick(layer) {
    this.layer = layer;
    this.trackingClick = false;
    this.trackingClickStart = 0;
    this.targetElement = null;

    // 绑定事件
    layer.addEventListener('touchstart', this.onTouchStart.bind(this), false);
    layer.addEventListener('touchend', this.onTouchEnd.bind(this), false);
    layer.addEventListener('click', this.onClick.bind(this), false);
}

FastClick.prototype.onTouchStart = function(event) {
    this.trackingClick = true;
    this.trackingClickStart = Date.now();
    this.targetElement = event.target; // 记录目标元素
};

FastClick.prototype.onTouchEnd = function(event) {
    if (!this.trackingClick) return;

    var target = this.targetElement;
    var timeDiff = Date.now() - this.trackingClickStart;

    if (timeDiff < 250) { // 阈值判断
        // 手动触发 click 事件
        var clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true });
        target.dispatchEvent(clickEvent);
    }

    this.trackingClick = false; // 重置状态
};

FastClick.prototype.onClick = function(event) {
    // 阻止默认 click 事件
    if (this.trackingClick) {
        event.preventDefault();
    }
};

// 初始化 FastClick
var layer = document.body; // 或者其他需要绑定的元素
new FastClick(layer);

FastClick 底层用的正好是touchstart和touchend重写了click事件,正好我上述的问题,只有click失效,其他事件例如touchstart是没问题的

FastClick 引发问题

正当我使用FastClick后,发现完美解决了这个问题,感到十分开心的时候,引发了另一个问题,那就是ios系统输入框需要长按/双击才能输入的问题

直接说解决吧

javascript 复制代码
import FastClick from 'fastclick'

const rewriteFocus = (targetElement) => {
  let length = null
  // Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.

  if (
    deviceIsIOS &&
    targetElement.setSelectionRange &&
    targetElement.type.indexOf('date') !== 0 &&
    targetElement.type !== 'time' &&
    targetElement.type !== 'month'
  ) {
    length = targetElement.value.length

    targetElement.focus()

    targetElement.setSelectionRange(length, length)
  } else {
    targetElement.focus()
  }
}

FastClick.attach(document.body)
FastClick.prototype.focus = rewriteFocus

以上方法也是参考以下博客的内容,其实就是重写下focus方法,这里推荐两篇博客,我也是借鉴而来

vue引入fastClick导致的输入框点击无响应问题

解决因引入了fastclick导致的ios系统输入框需要长按/双击才能输入的问题

小结

最后,我只想说累死了,这个问题,太恶心了,记录一下吧,希望对大家有点作用

相关推荐
石小石Orz10 分钟前
为什么推荐前端学习油猴脚本开发?
前端
珵煜ini13 分钟前
wd-button组件阻止事件冒泡的
前端
炒毛豆14 分钟前
vue3.4中的v-model的用法~
前端·vue.js
用户408128120038114 分钟前
大文件分片上传和断点续传
前端
极客悟道15 分钟前
颠覆传统虚拟化:在Docker容器中运行Windows系统的开源黑科技
前端·后端
前端康师傅16 分钟前
JavaScript 中你不知道的按位运算
前端·javascript
小桥风满袖18 分钟前
Three.js-硬要自学系列38之专项学习缓冲几何体
前端·css·three.js
Rubin9319 分钟前
埋点方案实现
前端
斯~内克23 分钟前
Centrifugo 深度解析:构建高性能实时应用的开源引擎
前端·开源
tianchang34 分钟前
策略模式(Strategy Pattern)深入解析与实战应用
前端·javascript·代码规范