Polymer focus() 必须包含在 setTimeout() 中才能工作?

Polymer focus() has to be wrapped in setTimeout() to work?

在尝试将焦点放在聚合物元素上时,我总是必须将其包装在 setTimout 中,在本例中它是聚合物 paper-input 元素。像这样:

setTimeout(function() {
   paperInput.focus(); 
}, 10);

我阅读了关于主题 focus() 聚合物元素的不同 Whosebug posts,我发现其中一些有同样的问题。 我真的不能接受这样一个事实,它在我包裹它的时候就起作用了我想知道为什么当我不包裹它的时候它就不起作用。

所以我的问题是,为什么?为什么我必须将它包装在 setTimeout 中?

目前使用 Polymer 1.4。但我注意到旧版本中有相同的行为。

谢谢!

更新

我已尝试重现该问题,但这确实有效。所以我敢打赌问题出在我自己的环境中:jsbin

如果我找到问题的解决方案,我会保持此 post 更新。 感谢您的帮助。

在简单的情况下,页面上除了 <paper-input> 之外没有其他元素,focus() 似乎没有问题。

<head>
  <base href="https://polygit.org/polymer+1.4.0/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="paper-input/paper-input.html">
</head>
<body>
  <paper-input></paper-input>
  <paper-input></paper-input>
  <paper-input id="my-input"></paper-input>
  <paper-input></paper-input>

  <script>
    HTMLImports.whenReady(function() {
      document.getElementById('my-input').focus();
    });
  </script>
</body>

jsbin

但我可以在 <paper-input> 位于 <iron-pages> 内的稍微复杂的情况下重现该问题。在以下示例中,第 2 页上的第三个 <paper-input> 应该已获得焦点。

<head>
  <base href="https://polygit.org/polymer+1.4.0/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="paper-input/paper-input.html">
  <link rel="import" href="paper-tabs/paper-tabs.html">
  <link rel="import" href="paper-tabs/paper-tab.html">
  <link rel="import" href="iron-pages/iron-pages.html">
</head>
<body>
  <x-foo></x-foo>

  <dom-module id="x-foo">
    <template>
      <paper-tabs selected={{selected}}>
        <paper-tab>PAGE 1</paper-tab>
        <paper-tab>PAGE 2</paper-tab>
        <paper-tab>PAGE 3</paper-tab>
      </paper-tabs>
      <iron-pages selected=[[selected]]>
        <section>
          <h3>empty page 1</h3>
        </section>
        <section>
          <h3>page 2 inputs</h3>
          <paper-input></paper-input>
          <paper-input></paper-input>
          <paper-input id="my-input"></paper-input>
          <paper-input></paper-input>
        </section>
        <section>
          <h3>empty page 3</h3>
        </section>
      </iron-pages>
    </template>
    <script>
      Polymer({
        is: 'x-foo',
        properties: {
          selected: {
            type: Number,
            value: function() { return 1; }
          }
        },
        ready: function() {
          this.$['my-input'].focus();
        }
      });
    </script>
  </dom-module>
</body>

jsbin

如果我使用您的变通方法将 focus() 调用与 setTimeout() 包装起来(这有效地将工作推迟到执行队列的末尾),焦点就会正确出现:

setTimeout(function() {
  this.$['my-input'].focus();
}.bind(this), 0);

<head>
  <base href="https://polygit.org/polymer+1.4.0/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="paper-input/paper-input.html">
  <link rel="import" href="paper-tabs/paper-tabs.html">
  <link rel="import" href="paper-tabs/paper-tab.html">
  <link rel="import" href="iron-pages/iron-pages.html">
</head>
<body>
  <x-foo></x-foo>

  <dom-module id="x-foo">
    <template>
      <paper-tabs selected={{selected}}>
        <paper-tab>PAGE 1</paper-tab>
        <paper-tab>PAGE 2</paper-tab>
        <paper-tab>PAGE 3</paper-tab>
      </paper-tabs>
      <iron-pages selected=[[selected]]>
        <section>
          <h3>empty page 1</h3>
        </section>
        <section>
          <h3>page 2 inputs</h3>
          <paper-input></paper-input>
          <paper-input></paper-input>
          <paper-input id="my-input"></paper-input>
          <paper-input></paper-input>
        </section>
        <section>
          <h3>empty page 3</h3>
        </section>
      </iron-pages>
    </template>
    <script>
      Polymer({
        is: 'x-foo',
        properties: {
          selected: {
            type: Number,
            value: function() { return 1; }
          }
        },
        ready: function() {
          setTimeout(function() {
            this.$['my-input'].focus();
          }.bind(this), 0);
        }
      });
    </script>
  </dom-module>
</body>

jsbin

这对我来说意味着当我们尝试聚焦它时 <paper-input> 实际上还没有准备好(尽管在这个自定义元素的 ready 回调中),我不确定这是否是一个错误.要解决此问题,我们可以为 WebComponentsReady 设置一个事件处理程序,当系统中的所有组件都已完全初始化时将调用该事件处理程序:

document.addEventListener('WebComponentsReady', function() {
   this.$['my-input'].focus();
}.bind(this));

<head>
  <base href="https://polygit.org/polymer+1.4.0/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="paper-input/paper-input.html">
  <link rel="import" href="paper-tabs/paper-tabs.html">
  <link rel="import" href="paper-tabs/paper-tab.html">
  <link rel="import" href="iron-pages/iron-pages.html">
</head>
<body>
  <x-foo></x-foo>

  <dom-module id="x-foo">
    <template>
      <paper-tabs selected={{selected}}>
        <paper-tab>PAGE 1</paper-tab>
        <paper-tab>PAGE 2</paper-tab>
        <paper-tab>PAGE 3</paper-tab>
      </paper-tabs>
      <iron-pages selected=[[selected]]>
        <section>
          <h3>empty page 1</h3>
        </section>
        <section>
          <h3>page 2 inputs</h3>
          <paper-input></paper-input>
          <paper-input></paper-input>
          <paper-input id="my-input"></paper-input>
          <paper-input></paper-input>
        </section>
        <section>
          <h3>empty page 3</h3>
        </section>
      </iron-pages>
    </template>
    <script>
      Polymer({
        is: 'x-foo',
        properties: {
          selected: {
            type: Number,
            value: function() { return 1; }
          }
        },
        ready: function() {
          document.addEventListener('WebComponentsReady', function() {
            this.$['my-input'].focus();
          }.bind(this));
        }
      });
    </script>
  </dom-module>
</body>

jsbin

我认为 WebComponentsReady 事件处理程序优于 setTimeout,因为我认为假设 WebComponentsReady 始终出现在该执行队列的末尾是不安全的。 setTimeout 可能只是偶然。