【问题标题】:Is this a bug? Tapping an element can result in a different element receiving keyboard focus这是一个错误吗?点击一个元素可能会导致不同的元素接收键盘焦点
【发布时间】:2012-06-19 08:24:36
【问题描述】:

我正在尝试确定在 Mobile Safari、Android 浏览器和 Firefox for Android(“Fennec”)中看到的效果是错误还是预期行为。基本上,问题在于 <input> 元素在某些情况下可以接收键盘焦点,即使 <input> 元素最初没有被用户点击。

这是一个可重现的测试用例:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, user-scalable=no">
<style>
#screenCover {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 0.3);
    z-index: 1;
}

#newItemInput {
    position: absolute;
    width: 200px;
    height: 20px;
}
</style>
</head>
<body>

<div id="screenCover"></div>
<input id="newItemInput" type="text">

<script type="text/javascript" language="JavaScript">
var screenCoverEl = document.getElementById("screenCover"),
    newItemInputEl = document.getElementById("newItemInput");

newItemInputEl.value = String(navigator.userAgent);

screenCoverEl.addEventListener("touchend", function (event) {
    // Move the <input> element in the way.
    newItemInputEl.style.top = (event.changedTouches[0].clientY - 10) + "px";
    newItemInputEl.style.left = (event.changedTouches[0].clientX - 10) + "px";

    // Hide the screen cover. Note that the screen cover was the original target of the tap.
    screenCoverEl.style.display = "none";
}, false);

newItemInputEl.addEventListener("click", function (event) {
    this.setSelectionRange(0, this.value.length);
}, false);
</script>
</body>
</html>

http://jsfiddle.net/f7TKc/2/

或直接在移动浏览器中:

http://fiddle.jshell.net/f7TKc/2/show/

在此示例中,屏幕封面位于文档顶部,但在 touchend 上,屏幕封面被隐藏,&lt;input&gt; 元素被移动到用户点击屏幕封面的位置。在 Mobile Safari、Android 浏览器和 Fennec 13.0b1 中,&lt;input&gt; 元素莫名其妙地获得了键盘焦点。

我无法在较新版本的 Fennec 中对此进行测试,因为它会在模拟器中崩溃。

这是错误还是预期行为?

【问题讨论】:

标签: android iphone mobile-safari touch-event fennec


【解决方案1】:

是的,我认为这是一个错误,这可能在同一行: http://code.google.com/p/android/issues/detail?id=6721 如果是这样,那么该链接有一些其他人已经尝试过的解决方法,您可以尝试

【讨论】:

  • 这个问题似乎与6721 不同,但是看到那个错误报告和相应的讨论让我相信这确实是一个错误。谢谢你的链接。
【解决方案2】:

触摸事件按以下顺序调用:touchstart、touchend、click。您需要知道您的触摸事件的 touchstart 是否发生在您的输入上。您可以隐式声明一个对象变量(这在 javascript 中是允许的)并将其初始化为 false。在 touchstart 事件中将其设置为 true。然后检查它在 touchend 和/或点击事件中的值。以下代码完全按预期工作。

    <script type="text/javascript" language="JavaScript">
    var screenCoverEl = document.getElementById("screenCover"),
    newItemInputEl = document.getElementById("newItemInput");

newItemInputEl.value = String(navigator.userAgent);


screenCoverEl.addEventListener("touchstart", function (event) {
    // Move the <input> element in the way.

    screenCoverEl.style.display = "none";

    newItemInputEl.style.top = (event.touches[0].clientY - 10) + "px";
    newItemInputEl.style.left = (event.touches[0].clientX - 10) + "px";

    // Hide the screen cover. Note that the screen cover was the original target of the tap.

}, false);

newItemInputEl.touchStartedHere = false; // remember if a touch event started on this input
newItemInputEl.addEventListener("touchstart", function (event) {

    this.touchStartedHere = true; //set true if did..

}, false);
newItemInputEl.addEventListener("click", function (event) {


    if(this.touchStartedHere){ // do what you want if touch started here
        this.setSelectionRange(0, this.value.length);  
    }else{  // prevent from receiving focus if touch didn't start here.
        this.blur();
    }
    this.touchStartedHere = false;  // reset to false to prepare for next touch event.

}, false);
</script>

【讨论】:

  • 我修改了这个想法,将最后一个 touchstart 事件保存在全局中。每当newItemInputEl 接收到focus 事件时,它都会检查最后一个touchstart 事件的目标是否是输入元素。如果不是,则调用 blur() 以放弃键盘焦点:jsfiddle.net/f7TKc/3 此方法适用于 iOS 5.0、5.1 和 6.0,但不适用于 iOS 4.3.2。事实证明,iOS 4.3.2 Mobile Safari 没有向输入元素发送触摸事件:jsfiddle.net/3zjQW/1 所以我添加了一个click 捕获监听器来重置全局,它起作用了:jsfiddle.net/f7TKc/4
【解决方案3】:

我想这是预期的行为。

移动网络浏览器的开发人员需要针对小显示器上设计不佳的网页进行特殊调整。

如果网页不能正确缩放,UI 元素很容易被另一层覆盖。

允许点击事件通过层向下传播将防止 UI 元素不可用。

我没有任何文件支持这个理论。

--------编辑--------

在玩弄了您的代码之后,我意识到屏幕覆盖已被移除,并且输入被移动到“touchstart”处的触摸位置。然后输入在“touchend”处获得焦点。

您可以通过在输入移动之前设置延迟来验证这一点。如果您的手指在输入之前已经移开,它将不会获得焦点。如果移动输入时您仍在触摸屏幕,它将获得焦点。

screenCoverEl.addEventListener("touchstart", function (event) {

screenCoverEl.style.display = "none";
setTimeout(function() {
        newItemInputEl.style.top = (event.touches[0].clientY - 10) + "px";
        newItemInputEl.style.left = (event.touches[0].clientX - 10) + "px";
    },250);


}, false);

【讨论】:

  • 对于我遇到此问题的实际网页(以几种不同的方式),我使用 Google 的 fast button technique 来避免 touchend 和 click 之间约 300 毫秒的延迟。所以,实际的网页实际上是在更新touchend上的文档,但是我在准备测试用例时出错了。我已经更新了这个问题。在touchend 上设置超时,然后进行更改似乎无法解决问题。
猜你喜欢
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
  • 2016-06-08
  • 1970-01-01
  • 2015-01-18
  • 2017-04-16
  • 1970-01-01
相关资源
最近更新 更多