focus()方法和事件顺序(在纯JavaScript中)

Bin*_*rus 6 javascript events asynchronous focus synchronous

我目前正在开发一个具有复杂帮助系统的大型Web项目,因此需要深入了解何时同步或异步触发事件.

实际上,我正在使用我在很多地方使用的focus()方法,而且它似乎并不像所有地方都记录的那样工作.我已阅读(某些部分)W3C DOM规范和许多文章和教程,所有这些都说明了相同的内容.当我们调用element.focus()时,应该发生以下情况:

1)光标(插入符号)设置为相应的元素.

2)以同步(阻塞)方式调用处理相应元素的焦点事件的所有事件处理程序,即保证在elem.focus()返回之前调用所有这些处理程序.换句话说,它保证了没有,这些处理器将被称为 elem.focus()返回.

在开发我的应用程序时,我依赖于这种行为,但现在似乎(至少)IE11和Chrome不遵守这些规则.如果有人能按照以下步骤回答我的最后一个问题,我想我能理解发生了什么.

首先,请考虑以下HTML文档:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">

<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
<title>Test</title>
</head>

<body>

    <input type="button" value="click me" />
    <input type="text" />

    <script>

    function ButtonHandler(e) {

      alert('in onclick')
      text.focus()
      alert('out onclick')    
    }

    function FieldHandler(e) {

      alert('onfocus')
      text.onfocus = null
    }

    var button = document.body.children[0]
    var text = document.body.children[1]

    button.onclick = ButtonHandler
    text.onfocus = FieldHandler

  </script>

</body>

</html>
Run Code Online (Sandbox Code Playgroud)

我从这里获得了部分代码:http://javascript.info/tutorial/events-and-timing-depth.作者使用该代码来证明elem.focus()确实同步工作.为了简单起见,让我们使用IE11来显示我的问题.

请将如上所示的HTML文档加载到IE11中.然后单击页面白色区域的任意位置以获得文本输入的焦点,然后点击重新加载.您现在应该有一个新加载的文档,文本输入未聚焦.

现在,当您单击该按钮时,您将收到三个警报:onclick,onfocus,out onclick(按此顺序).这似乎证明了elem.focus()的行为是同步的.

现在考虑以下HTML文档:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">

<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
<title>Test</title>
</head>

<body>

    <input type="button" value="click me" />
    <input type="text" />

    <script>

    function ButtonHandler(e) {

      console.log('in onclick')
        text.focus()
        console.log('out onclick')    
    }

    function FieldHandler(e) {

      console.log('onfocus')
        text.onfocus = null
    }

    var button = document.body.children[0]
      var text = document.body.children[1]

      button.onclick = ButtonHandler
      text.onfocus = FieldHandler

  </script>

</body>

</html>
Run Code Online (Sandbox Code Playgroud)

它与第一个文档完全相同,但有以下例外:我已通过console.log()替换了alert().

现在,请将该文档加载到IE11并打开IE11的控制台.再次,将焦点从文本输入中移开并重新加载文档,然后单击按钮.控制台现在显示以下行(按此顺序):

in onclick
out onclick
onfocus

这似乎证明了对elem.focus()的调用是异步完成的( elem.focus()返回显然调用了焦点处理程序),这对我的应用程序来说是一个很大的问题.

可以请任何人向我解释为什么elem.focus()似乎在第一个文档中是同步的,但在第二个文档中是异步的?

顺便说一句,我在这里使用IE11,因为我已经能够找到上面的例子,这很容易理解.我希望有人会对我的问题给出一般性答案,并且我不会被告知这只是IE11的错误行为.

Firefox似乎是唯一能够做到正确的浏览器,即使使用第一个文档,Chrome也会失败.我已经知道浏览器不遵守DOM规范,因为在许多情况下事件顺序和调用事件处理程序的顺序是错误的.但我一直非常肯定(到现在为止)至少指定为阻塞的方法确实以同步方式调用...