离开 iframe 时鼠标悬停丢失:导致反向输入
Mouseup lost when leaving iframe: leads to reversed input
TL;DR 问题:
某些 javascript 如何告诉 window 鼠标按钮已被释放?由于跨域 iframe,mouseup 事件正在丢失。我可以检测到问题已经发生,但我不知道如何解决它。如果我可以强制鼠标指针定位,问题就会消失;但不允许 javascript 更改鼠标指针位置。如果我可以“启动 mouseup”,那么问题就会消失,因为它将替换丢失的 mouseup 事件;但是在新的 mouseup 事件上使用 dispatchEvent 什么都不做。
情况:
- 任何最新版本的 Chrome,任何操作系统。
- 包含位于内部的 iframe 的外部文档。根本不需要javascript。
- 外部文档和内部 iframe 文档托管在不同的域上,均为 https。不是同一基域的不同子域,而是实际上不同的域。我的示例使用 www.pressero.com 和 client-prototype.dev2.edocbuilder.com。无论证书是否有效(我的都是),问题仍然存在。
- iframe 中的文本框输入,位于或靠近左边缘。标准 LTR 文本方向。
- 几乎是最小的示例:Demo1LINK不再有效。 为了方便更改 iframe src,在外部文档中有一小部分 javascript。删除此 javascript 根本没有任何效果。
重要限制:
- 仅与Chrome和基于Chromium的浏览器发生;不是 Firefox、Safari、Edge 或 IE。
- 一些 不确定它是否对所有 Chrome 客户端都相同。我个人在大约五台不同的 Windows PC 运行 Chrome 68 或 69 上重现了相同的行为。一位同事在 Mac 运行 Chrome 69,并在 Windows VM 运行 中的 Chrome 69 上 Mac.
触发问题:
- 用户试图 select 文本框中的所有文本输入,使用鼠标,将鼠标从文本框的末尾移向开头。
- 不经意间,用户将鼠标指针移过左边缘,因此离开 iframe 进入外部文档。
- 用户在鼠标指针离开 iframe 后释放鼠标左键。
- 只在鼠标用于select文本时发生,并且仅当指针在 iframe 之外结束时发生左键释放的时间。 selecting 文本的其他方法不会导致此症状:
- ctrl-A 至 select 全部
- 进入字段
- 使用 shift-arrows 到 select 文本
- 使用鼠标 select 文本但从左到右
- 使用鼠标 select 文本,但要注意释放鼠标按钮时指针位于 iframe 内
另一种反向插入文本的方法:
- 将鼠标指针放在文本框的左上角。
- 按住鼠标左键。
- 输入文字。它是反向插入的,因为每次击键后插入点都会重新定位到刚键入的字符之前。
- 这只是为了说明不良行为。这显然不是错误,因为它是一种人为的显示方式。
感知症状:
- 松开左键后输入的文本以相反的顺序插入:即输入“abcde”将显示为“edcba”,插入点位于第一个字符的左侧。
相关症状:
- 如果正在使用 javascript,例如用于调整对象大小的功能,或将其拖动到 canvas 周围,则即使在 canvas 外释放左键后拖动仍将继续框架。即使将指针移回 iframe 内,拖动仍在继续。
- 确实是
mouseup
事件丢失的事实通过在 iframe 文档中将 alert()
附加到 body
上的 mouseup 来证明。如果在指针位于 iframe 内时释放鼠标按钮,则会发生警报;如果在指针位于 iframe 之外时释放鼠标按钮,则不会发生这种情况。
再次强调,只有CHROME有这种行为。在 Firefox、Edge 或 IE 中执行完全相同的操作,无论鼠标指针位于何处,都会立即检测到鼠标按钮释放。
尝试过的解决方法:
- 建议用户注意鼠标位置。不是一个流行的解决方案。
当文本框获得焦点时,- Javascript 应用于文本框 select 全部。这使得 selecting 不需要使用鼠标,因此可以防止用户 运行 进入问题。但是,这使得无法 select 文本的一小部分而不是整个文本。
- 移动文本框使其不靠左边缘。这使得用户不太可能在指针位于 iframe 之外时松手。
捕获丢失的 mouseup 事件:
通过将事件处理程序附加到外部文档中的 <body>
,我可以捕获 mouseup。然后我可以使用标准 post 消息技术来告诉内部 iframe window 发生了鼠标弹起。内部 iframe 知道在拖动过程中哪个元素处于活动状态,所以这很好。但是,我在实际模拟 mouseup 事件时没有任何运气。我已经尝试了 triggerMouseEvent
技术 here。它运行没有错误,但它显然没有做任何事情。
此处的演示有上面的最小示例,加上在外部文档中捕获 mouseup 的管道,post 向内部文档发送消息,并调用 triggerMouseEvent
:Demo2 LINK不再有效
另一种奇怪的可能性
在尝试创建最小示例时,我发现可能以某种方式涉及盒模型。 Demo1a LINK NO LONGER VALID 与上面的 demo1 相同,只是 iframe 元素的高度改为 710px 700 像素。 在我的测试机器上 这消除了错误。在同事的测试机上,bug依旧。
可能相关的已跟踪 Chromium 问题:
- 269917 preventDefault on mousedown prevents proper handling of mouse events in iframes
- 2013 年 8 月 8 日开业;最后评论 2018 年 6 月 18 日
- 我提到它是因为它涉及 iframe 之外的 mouseup。如上所述,即使根本没有使用 javascript,我们的问题也会发生。
编辑 2018-09-25
我已经提交了Chromium issue #882491。目前还没有看到任何真正的activity.
编辑 2020-08-31
由于我离开了我工作的公司,演示链接不再有效。
此错误已在 Chrome 70 中修复,已宣布将于 2018 年 10 月 16 日发布。我已经在 Beta 频道中使用 Chrome 70 进行了测试,我确认它是确实修复了。
TL;DR 问题:
某些 javascript 如何告诉 window 鼠标按钮已被释放?由于跨域 iframe,mouseup 事件正在丢失。我可以检测到问题已经发生,但我不知道如何解决它。如果我可以强制鼠标指针定位,问题就会消失;但不允许 javascript 更改鼠标指针位置。如果我可以“启动 mouseup”,那么问题就会消失,因为它将替换丢失的 mouseup 事件;但是在新的 mouseup 事件上使用 dispatchEvent 什么都不做。
情况:
- 任何最新版本的 Chrome,任何操作系统。
- 包含位于内部的 iframe 的外部文档。根本不需要javascript。
- 外部文档和内部 iframe 文档托管在不同的域上,均为 https。不是同一基域的不同子域,而是实际上不同的域。我的示例使用 www.pressero.com 和 client-prototype.dev2.edocbuilder.com。无论证书是否有效(我的都是),问题仍然存在。
- iframe 中的文本框输入,位于或靠近左边缘。标准 LTR 文本方向。
- 几乎是最小的示例:Demo1LINK不再有效。 为了方便更改 iframe src,在外部文档中有一小部分 javascript。删除此 javascript 根本没有任何效果。
- 仅与Chrome和基于Chromium的浏览器发生;不是 Firefox、Safari、Edge 或 IE。
- 一些 不确定它是否对所有 Chrome 客户端都相同。我个人在大约五台不同的 Windows PC 运行 Chrome 68 或 69 上重现了相同的行为。一位同事在 Mac 运行 Chrome 69,并在 Windows VM 运行 中的 Chrome 69 上 Mac.
触发问题:
- 用户试图 select 文本框中的所有文本输入,使用鼠标,将鼠标从文本框的末尾移向开头。
- 不经意间,用户将鼠标指针移过左边缘,因此离开 iframe 进入外部文档。
- 用户在鼠标指针离开 iframe 后释放鼠标左键。
- 只在鼠标用于select文本时发生,并且仅当指针在 iframe 之外结束时发生左键释放的时间。 selecting 文本的其他方法不会导致此症状:
- ctrl-A 至 select 全部
- 进入字段
- 使用 shift-arrows 到 select 文本
- 使用鼠标 select 文本但从左到右
- 使用鼠标 select 文本,但要注意释放鼠标按钮时指针位于 iframe 内
另一种反向插入文本的方法:
- 将鼠标指针放在文本框的左上角。
- 按住鼠标左键。
- 输入文字。它是反向插入的,因为每次击键后插入点都会重新定位到刚键入的字符之前。
- 这只是为了说明不良行为。这显然不是错误,因为它是一种人为的显示方式。
感知症状:
- 松开左键后输入的文本以相反的顺序插入:即输入“abcde”将显示为“edcba”,插入点位于第一个字符的左侧。
相关症状:
- 如果正在使用 javascript,例如用于调整对象大小的功能,或将其拖动到 canvas 周围,则即使在 canvas 外释放左键后拖动仍将继续框架。即使将指针移回 iframe 内,拖动仍在继续。
- 确实是
mouseup
事件丢失的事实通过在 iframe 文档中将alert()
附加到body
上的 mouseup 来证明。如果在指针位于 iframe 内时释放鼠标按钮,则会发生警报;如果在指针位于 iframe 之外时释放鼠标按钮,则不会发生这种情况。
再次强调,只有CHROME有这种行为。在 Firefox、Edge 或 IE 中执行完全相同的操作,无论鼠标指针位于何处,都会立即检测到鼠标按钮释放。
尝试过的解决方法:
- 建议用户注意鼠标位置。不是一个流行的解决方案。 当文本框获得焦点时,
- Javascript 应用于文本框 select 全部。这使得 selecting 不需要使用鼠标,因此可以防止用户 运行 进入问题。但是,这使得无法 select 文本的一小部分而不是整个文本。
- 移动文本框使其不靠左边缘。这使得用户不太可能在指针位于 iframe 之外时松手。
捕获丢失的 mouseup 事件:
通过将事件处理程序附加到外部文档中的 <body>
,我可以捕获 mouseup。然后我可以使用标准 post 消息技术来告诉内部 iframe window 发生了鼠标弹起。内部 iframe 知道在拖动过程中哪个元素处于活动状态,所以这很好。但是,我在实际模拟 mouseup 事件时没有任何运气。我已经尝试了 triggerMouseEvent
技术 here。它运行没有错误,但它显然没有做任何事情。
此处的演示有上面的最小示例,加上在外部文档中捕获 mouseup 的管道,post 向内部文档发送消息,并调用 triggerMouseEvent
:Demo2 LINK不再有效
另一种奇怪的可能性
在尝试创建最小示例时,我发现可能以某种方式涉及盒模型。 Demo1a LINK NO LONGER VALID 与上面的 demo1 相同,只是 iframe 元素的高度改为 710px 700 像素。 在我的测试机器上 这消除了错误。在同事的测试机上,bug依旧。
可能相关的已跟踪 Chromium 问题:
- 269917 preventDefault on mousedown prevents proper handling of mouse events in iframes
- 2013 年 8 月 8 日开业;最后评论 2018 年 6 月 18 日
- 我提到它是因为它涉及 iframe 之外的 mouseup。如上所述,即使根本没有使用 javascript,我们的问题也会发生。
编辑 2018-09-25
我已经提交了Chromium issue #882491。目前还没有看到任何真正的activity.
编辑 2020-08-31
由于我离开了我工作的公司,演示链接不再有效。
此错误已在 Chrome 70 中修复,已宣布将于 2018 年 10 月 16 日发布。我已经在 Beta 频道中使用 Chrome 70 进行了测试,我确认它是确实修复了。