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

3

当尝试将焦点放在聚合物元素上时,我总是不得不将其包装在setTimeout中,这种情况下是一个聚合物paper-input元素。像这样:

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

我已经阅读了关于焦点(focus())的Polymer元素的不同Stackoverflow帖子,发现其中一些存在相同的问题。 我真的无法接受只有在包装时才能正常工作这个事实。我想知道为什么当我不包装它时它不能工作。
所以我的问题是,为什么?为什么我必须用setTimeout来包装它?
目前使用的是Polymer 1.4。但我注意到旧版本中也有相同的行为。
谢谢!
更新
我尝试复制该问题,但实际上它可以正常工作。 所以我打赌问题出在我的环境中:jsbin 如果我找到解决方案,我将继续更新此帖子。感谢您的帮助。

1
有趣的问题,但是如果不知道这段代码在你的应用程序中的位置以及包含 paper-input 的组件的外观,就很难说。你能创建一个 Plunker 来重现吗? - Günter Zöchbauer
嗯,我会看看能否在Plunker中重现这个问题。希望今天稍后能在更新的帖子中发布它。 - Jonathan Andersson
在我对Polymer 1.4.0的测试中,不需要使用setTimeout来使用focus()。我同意我们需要查看您的代码以帮助解决您的错误。您能否更新您的问题,包括SO帖子的链接? - tony19
@JonathanAndersson 我能够重现这个问题。 - tony19
@tony19 非常感谢。昨天没有时间做这件事。 - Jonathan Andersson
1个回答

2
在简单的情况下,页面上除了<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>内部。在下面的例子中,第二页中的第三个<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>

如果我使用你的解决方法,将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

这对我来说意味着尽管在自定义元素的ready回调中,<paper-input>实际上还没有准备好,我们尝试将其聚焦,我不确定这是否是一个错误。为了解决这个问题,我们可以为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>

我认为WebComponentsReady事件处理程序比setTimeout更好,因为我认为不能安全地假设WebComponentsReady总是发生在此执行队列的末尾。setTimeout可能只是偶然起作用。


实际上,如果你将 this.$['my-input'].focus(); 改为 this.$['my-input'].$.input.focus();,输入框将会正确地获得焦点。你只需要直接调用 input 的 focus() 方法即可。 - LoveAndHappiness
@LoveAndHappiness 在这个jsbin中仍然不起作用。 - tony19
@tony19 不错的代码片段。我的问题不在准备回调函数上。问题出现在所有组件都准备好并且用户按下按钮将焦点切换到paper-input时。jsbin这个确实有效。所以我很难复制它。 (在可编辑内容中按B键切换焦点) - Jonathan Andersson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接