Leaflet: 在 iOS13 上不会触发上下文菜单

创建于 2019-09-23  ·  47评论  ·  资料来源: Leaflet/Leaflet

iOS 更新到 13 版本后,长按不起作用并且不会触发上下文菜单事件。

最有用的评论

这个问题是从WebKit 错误 #202143 引用的。 WebKit 团队(在本例中为我)正在调查。

所有47条评论

双击以触发 doubleClickZoom 在 iOS 13 中也不起作用。解决 contextmenu 的问题要重要得多。

我确实确认了同样的问题。 经过初步检查,iOS 13 Safari 似乎无法正确触发触摸事件。

iOS Safari 中的长按不会向 Leaflet 库发送任何事件,而是由 iOS 本身处理。

双击会发出以下事件:mouseover、mousemove、mousedown、mouseup、click,这会导致传单的事件单击。

在我看来,移动 Safari iOS 13 中的严重问题,我想这与使移动 Safari 与桌面 Safari 非常相似有关。 除非触摸事件正确发送到 Leaflet,否则恐怕没有太多需要修复的。

这里有人会向 Apple 报告此事吗?

上周我向 Apple 支持部门发送了一份报告。 仍然没有答案。

我有更多的信息。 如果在地图 div 上添加单击处理程序并启用缩放控制,则长按开始作为复制/粘贴上下文菜单工作。
像那样

<div id="mapid" onclick="javascript:void(0)"/>

 -webkit-user-select: none;
 -webkit-touch-callout: none;

也无济于事,只能禁用复制/粘贴菜单

也许它对某人有用。

作为长按的临时解决方案:
添加这个库
https://www.cssscript.com/handle-long-press-tap-event-in-javascript-long-press-js/
并在 css 中
-webkit-user-select: none; -webkit-touch-callout: none;

比为长按事件添加侦听器。 并在事件处理程序中将坐标转换为传单坐标。

图书馆能用吗? 到目前为止,我已经检查了源代码,并且该库会侦听无论如何都不会发送到 Safari 的触摸事件。 只是好奇。

是的,它有效。 至少对于长按。
我已经在 iOS13 和 iPadOS13 上检查过了

很棒的提示谢谢

这是我们使用它时的最终解决方案。 它检测长按并模拟“contextmenu”MenuEvent。 把它放在你的 JS 代码中,你应该会很好。

注意:最好只为 iOS 13 用户限制执行,不要有太多听众

// Copied and modified from https://github.com/john-doherty/long-press-event/

import rs from 'rootScope'
import $ from '$'

if( rs.platform === 'ios' && / OS 13_/.test( navigator.userAgent ) ) {

    // This is our main map el
    const mapEl = $('#map-container')

    // This class adds  -webkit-user-select: none; -webkit-touch-callout: none;
    // to the BODY el
    document.body.classList.add('ios13')

    let timer = null;

    const fireLongPressEvent = originalEvent => {

        clearLongPressTimer();

        const el = originalEvent.target
        , x = originalEvent.touches[0].clientX
        , y = originalEvent.touches[0].clientY

        // This will emulate contextmenu mouse event
        const event = new MouseEvent('contextmenu', {
                                    bubbles: true,
                                    cancelable: true,
                                    clientX: x,
                                    clientY: y
                                })


        // fire the long-press event
        const suppressClickEvent = el.dispatchEvent.call(el,event);

        if (suppressClickEvent) {

            // temporarily intercept and clear the next click
            mapEl.addEventListener('touchend', function clearMouseUp(e) {
                mapEl.removeEventListener('touchend', clearMouseUp, true);
                cancelEvent(e);
            }, true);
        }
    }

    const startLongPressTimer = e => {
        clearLongPressTimer(e);
        timer = setTimeout( fireLongPressEvent.bind(null,e), 1000 );
    }

    const clearLongPressTimer = () => {
        if(timer) {
            clearTimeout(timer);
            timer = null;
        }
    }

    const cancelEvent = e => {
        e.stopImmediatePropagation();
        e.preventDefault();
        e.stopPropagation();
    }

    // hook events that clear a pending long press event
    mapEl.addEventListener('touchcancel', clearLongPressTimer, true);
    mapEl.addEventListener('touchend', clearLongPressTimer, true);
    mapEl.addEventListener('touchmove', clearLongPressTimer, true);

    // hook events that can trigger a long press event
    mapEl.addEventListener('touchstart', startLongPressTimer, true); // <- start

}

在调查类似问题时遇到了这个线程。 我发现在touchstart preventDefault上调用

我相信这归结为移动 Safari 改变了它模拟悬停事件的方式(使网站工作完全依赖悬停事件来打开菜单等)

在调查类似问题时遇到了这个线程。 我发现在touchstart preventDefault上调用

我相信这归结为移动 Safari 改变了它模拟悬停事件的方式(使网站工作完全依赖悬停事件来打开菜单等)

到目前为止对我来说是相反的,只是抑制除长按之外的所有点击。 你能分享一段对你有用的代码吗?

抱歉,我假设您使用原始触摸事件来检测双击。 如果您依赖单击/鼠标事件,那么 touchstart 上的preventDefault将阻止这些事件。

无论哪种方式,它似乎都是 iOS 中的一个错误,已在 13.1 中修复。

@felixhageloh我刚刚在运行此演示的 iOS 13.1 上进行了测试:
http://aratcliffe.github.io/Leaflet.contextmenu/examples/index.html

但问题似乎并没有得到解决! 有什么我错过了吗?
对我们来说非常关键的问题,因为我们严重依赖长按事件来工作,任何帮助将不胜感激。

这个问题是从WebKit 错误 #202143 引用的。 WebKit 团队(在本例中为我)正在调查。

这个问题是从WebKit 错误 #202143 引用的。 WebKit 团队(在本例中为我)正在调查。

我们很高兴您深入探讨这个问题。 作为 Web 开发人员,我们很高兴 iOS 13.x 上的 Safari 在发生触摸事件时的行为方式与 iOS 12.x 或 Android 上的 Chrome 相同。

很高兴你在这里。

@majid701抱歉,如果我造成了一些混乱。 我在 13.0 中看到的问题是:
双击(快速)-> 触发了单个 touchstart 和 touchend。

从 13.1 开始,我再次正确地接收到两个 touchstart 和 touchend 事件。 我正在维护的应用程序使用原始触摸事件来检测双击,所以这个固定的双击缩放适用于我们。 我错误地假设这对你来说也是如此。

if( rs.platform === 'ios' && / OS 13_/.test( navigator.userAgent ) )

请注意@ilblog ,这不适用于 iPadOS,其中用户代理字符串与桌面上的 Safari 相同,并且不会宣传 iOS。

_(从 WebKit 错误重新发布,因此只有抄送此错误的人才能看到这一点。)_

contextmenu Leaflet 事件不会被触发,因为 Leaflet 代码交替使用pointerdowntouchstart事件,并且前者的可用性排除了另一个。 在 Map.Tap.js 中, _onDown方法有这个检查if (!e.touches) { return; } ,它总是会导致提前返回,因为PointerEvent事件与TouchEvent并且没有touches属性。

因此,缺少被触发的 Leaflet contextmenu事件是一个 Leaflet 问题。

实际上,由于以下代码,此代码甚至不与指针事件一起运行:

if (Browser.touch && !Browser.pointer) {
    Map.addInitHook('addHandler', 'tap', Tap);
}

在 iOS 13 上Browser.touchBrowser.pointer都是 true,所以整个包都没有初始化。

上周我向 Apple 支持部门发送了一份报告。 仍然没有答案。

@ginger-777 你有错误号/反馈 ID 吗? 通常,虽然引起 WebKit 开发人员注意的最佳方式是直接在 bugs.webkit.org 上提交错误。

@graouts是的,在阅读您的最后一条评论后,我也注意到了这一点。 但是我测试了从Settings -> General -> Experimental Features禁用指针事件,看起来它在这个演示网站上工作:
http://aratcliffe.github.io/Leaflet.contextmenu/examples/index.html

但它在我的应用程序中不起作用。 我正在 Webview 中加载传单。

至于双击缩放,这也是 Leaflet 的一个问题。 考虑DomEvent.DoubleTap这段代码:

function onTouchStart(e) {
    var count;

    if (Browser.pointer) {
        if ((!Browser.edge) || e.pointerType === 'mouse') { return; }
        count = _pointersCount;
    } else {
        count = e.touches.length;
    }

    if (count > 1) { return; }

    var now = Date.now(),
        delta = now - (last || now);

    touch = e.touches ? e.touches[0] : e;
    doubleTap = (delta > 0 && delta <= delay);
    last = now;
}

如果浏览器支持指针事件并且它不是Edge,则该功能会提前退出。 iOS 13 上的 Safari 或任何基于 WebKit 的浏览器就是这种情况。

据我所知,这里报告的两个问题都是 Leaflet 根本没有为支持触摸事件和指针事件(长按和contextmenu事件)或支持指针事件但不是 Microsoft Edge 的浏览器做好准备(双击和dblclick事件)。

我关闭了 WebKit 错误,因为在这个阶段我们没有什么需要修复的。

@graouts是的,在阅读您的最后一条评论后,我也注意到了这一点。 但是我测试了从Settings -> General -> Experimental Features禁用指针事件,看起来它在这个演示网站上工作:
http://aratcliffe.github.io/Leaflet.contextmenu/examples/index.html

但它在我的应用程序中不起作用。 我正在 Webview 中加载传单。

是的@majid701 ,我认为此设置仅适用于 Safari,不适用于WKWebView或任何其他在 iOS 上嵌入 WebKit 的方式。 我不确定如何在 Safari 应用程序之外禁用指针事件。

我认为解决方案是修复 Leaflet 库,该库将 iOS 13 Safari 检测为“pinterType”浏览器,因此无法正确处理 Touch 事件。

非常感谢@graouts在这件事上的努力和很多帮助。

关于在移动设备上双击、修补相同代码行的公关活动https://github.com/Leaflet/Leaflet/pull/6815 ,因此我要求他们也涵盖这个问题。

if( rs.platform === 'ios' && / OS 13_/.test( navigator.userAgent ) )

请注意@ilblog ,这不适用于 iPadOS,其中用户代理字符串与桌面上的 Safari 相同,并且不会宣传 iOS。

嗯,这很有趣,因为当开发人员无法区分 macOS 和 iPad 时,它会引发另一系列问题。 这与这个 Leaflet 错误无关,但我认为 Apple 也应该解决这个问题。

https://forums.developer.apple.com/thread/119186

解决了

感谢 Apple 的宝贵意见,我至少在 iPhone 上设法解决了 iOS 13 问题。 由于 iOS13 上的 iPad 与 macOS 具有相同的用户代理字符串,因此我无法解决 iPad 上的问题。

只需像这样修改src/core/Browser.js

// 'false' for all iOS devices, that (as of version iOS13 support both, touch and pointer events)
// Unfortunately as of iOS13 it is not possible to distinguish iPad from OS X by user agent string
export var pointer = !!(window.PointerEvent || msPointer) && !userAgentContains('iphone');

带有修复程序的拉取请求在这里

https://github.com/Leaflet/Leaflet/pull/6827

if( rs.platform === 'ios' && / OS 13_/.test( navigator.userAgent ) )

请注意@ilblog ,这不适用于 iPadOS,其中用户代理字符串与桌面上的 Safari 相同,并且不会宣传 iOS。

嗯,这很有趣,因为当开发人员无法区分 macOS 和 iPad 时,它会引发另一系列问题。 这与这个 Leaflet 错误无关,但我认为 Apple 也应该解决这个问题。

通常,基于用户代理字符串做出决策并不是最佳方法。 逐案的特征检测适合绝大多数用例。 此外,iPadOS 上的 Safari 可能会使用不同的用户代理字符串,具体取决于设备类别(iPad mini 与其他大屏幕 iPad 型号)或多任务处理中的窗口大小,其中 Safari 可能使用三分之一屏幕,甚至取决于用户偏好(请求移动/桌面网站)。

如果存在不适合特征检测的情况,请在 bugs.webkit.org 上提出错误,WebKit 团队将能够确定最佳解决方案。

有关如何为 iPadOS 13 解决此问题的任何更新?
我正在使用 mousedown/mouseup 事件。

大家好,

我尝试了一个比嗅探 UA 并捏造它更好的解决方案,因为它应该更稳定。
https://github.com/Leaflet/Leaflet/pull/6855
它仍在嗅探 UA,但只是为了不更改无法测试的平台的代码。 由于可能触发dblclick事件或其他原因, edge条件似乎可以用于纾困? 在我看来(虽然我不精通 JS),指针事件的Browser.pointer功能测试应该是我们需要的唯一测试,而其他测试应该是狭窄且非常具体的,而不是“如果不是 Edge,则退出”(缺少“为什么?”),看起来应该是“如果 Edge,做一些不同的事情”(在评论中给出原因)。

不过,我在 iPad 上的 iOS13 仍然存在问题。

@graouts :回复: https://github.com/Leaflet/Leaflet/issues/6817#issuecomment -536581361 和https://github.com/Leaflet/Leaflet/issues/6817#issuecomment -536587962 :
我正在尝试在 iPad 上完成这项工作(使用上面的 PR 在 iPhone 上修复它),但是如果我双击,则不会触发第二个pointerdown 。 我发送了断点,添加了log()调用,但我看不到任何触发。 在某些情况下,iPad 似乎省略了第二次点击。
我可以通过“三次/四次点击”来放大它,但不能通过双击来放大。 全局处理程序(这是请求touchstart / touchend事物的兼容层)上的日志不会在双击时触发。
知道 iPad(带有 iOS13)可以做什么来省略第二次点击吗? 阈值是 250 毫秒,但如果速度超过 ~320 毫秒,我将无法进行第二次点击进行注册。
我的标题中确实有<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> ,如“移动传单”页面中所述。

@graouts (抱歉,不是针对你,只是问你是因为你提到来自 WebKit 团队):
如果您尝试以下事件侦听器测试页面:
https://patrickhlauke.github.io/touch/tests/event-listener.html

您可以在 iPhone 和 iPad 上看到 iOS13 之间的差异。 在 iPhone 上,我可以双击按钮并看到pointerdown+pointerup两个序列。 在 iPad 上,我无法通过双击触发此序列。 它会举办一段时间的活动。

谢谢,
飞利浦

@filcab请在 bugs.webkit.org 上提交错误,我会看看! 也就是说,我相信这个问题已经在 iOS 13.2 中得到解决,开发者种子版本已经在 developer.apple.com 上可用。 但始终提交 webkit.org 错误供团队查看。

@filcab请在 bugs.webkit.org 上提交错误,我会看看! 也就是说,我相信这个问题已经在 iOS 13.2 中得到解决,开发者种子版本已经在 developer.apple.com 上可用。 但始终提交 webkit.org 错误供团队查看。

我已经提交了https://bugs.webkit.org/show_bug.cgi?id=203031

大家好,非常感谢所有宝贵的意见——我们正在尽快调查这个问题。 我正在休假,因此无法编写代码,但请其他一些维护人员确定优先级。

快速浏览一下讨论,看起来问题的根源是 iOS13 支持指针事件规范,因此 Leaflet 部分采用了我们专门为传统 IE 移动浏览器优化的代码路径,这些浏览器通常的触摸事件不可用。

像#6827 中的代理字符串嗅探不是很可靠(随时可能中断); 修复#6855 中的指针事件可能会更好,但仍然非常冒险,因为我们在编写代码时从未打算让指针代码路径在现代浏览器中工作; 如果我们之前检测到常规触摸事件正常工作(因此,类似于export var pointer = !webkit && !!(window.PointerEvent || msPointer) ),也许我们应该尝试完全禁用指针事件?

大家好,非常感谢所有宝贵的意见——我们正在尽快调查这个问题。 我正在休假,因此无法编写代码,但请其他一些维护人员确定优先级。

快速浏览一下讨论,看起来问题的根源是 iOS13 支持指针事件规范,因此 Leaflet 部分采用了我们专门为传统 IE 移动浏览器优化的代码路径,这些浏览器通常的触摸事件不可用。

像#6827 中的代理字符串嗅探不是很可靠(随时可能中断); 修复#6855 中的指针事件可能会更好,但仍然非常冒险,因为我们在编写代码时从未打算让指针代码路径在现代浏览器中工作; 如果我们之前检测到常规触摸事件正常工作(因此,类似于export var pointer = !webkit && !!(window.PointerEvent || msPointer) ),也许我们应该尝试完全禁用指针事件?

这听起来不错,特别是如果指针事件的代码不像我预期的那么新。 我会用你提议的补丁更新我的 PR(刚刚在 iPad 和 iPhone 上测试了 iOS 13,它在这两个上都有效)。

谢谢,
飞利浦

从标准的角度来看,使用指针事件(如果可用)而不是触摸事件更可取,因为它是 W3C 标准而不是供应商特定的技术。

从技术角度来看,至少对于 iOS 实现而言,存在性能影响。 触摸事件总是同步调度的,因此任何处理它们的 JS 工作都将被阻塞并可能产生较差的响应能力。 指针事件的设计方式使得它们可以异步实现,在 iOS 上也是如此。

有两件事值得考虑,也许不是针对这个特定问题,但值得在未来牢记。

难道修复#6855 对标记不起作用? 我收到报告说长按标记不会触发上下文菜单,但会出现共享/复制操作系统菜单...

@eliboni
似乎您需要在元素上使用-webkit-touch-callout: none; (或类似的......我不擅长这个😅)。 不过不确定是哪个。 添加* { -webkit-touch-callout: none; }在我的测试中起作用(使用 iPhone 在标记上触发contextmenu事件)。
根据需要进行调整。

你好,
我无法使用 Leaflet.js 进行双击缩放。
我刚刚阅读了这篇文章,但我没有找到解决方案。
任何人都可以帮助我吗?

最好的问候康提。

最后我找到了解决方案:

我们需要更新到传单 1.5 并在以下位置启用 de Tap:

new L.map("mapid",{ attributionControl: false, zoomControl: false, tap: true });

并且工作正常。

此致

@bitxenio

恐怕使用 1.5.1 对我不起作用

我现在回到编写自己的处理程序,因为 IOS 13.2 似乎也不起作用:(

@rwillett@Bitxenio :您使用的是什么代码? 你们俩都提到了传单的特定版本。
10 月份提交的 PR#6855 修复程序不在最新版本中,后者是在 5 月份发布的。

你在使用master吗?

谢谢,
飞利浦

啊! 我们使用了官方版本。 我们没有意识到 PR#6855 不包括在内。 我们的错。

我们下载了 dev 分支,我们会尝试一下,

谢谢

我们下载了 1.6-dev,它运行良好。 ios 13.2 上的双击和上下文菜单。

感谢帮助,感激不尽。

1.6.0 发布

如果我们之前检测到常规触摸事件正常工作(因此,类似于export var pointer = !webkit && !!(window.PointerEvent || msPointer) ),也许我们应该尝试完全禁用指针事件?

@哀悼者
这确实是有风险的,并导致了 #6896 之类的问题。
请加入讨论https://github.com/Leaflet/Leaflet/issues/6977#issuecomment -577638632

此页面是否有帮助?
0 / 5 - 0 等级