如何将聚合物自定义元素绑定到内容?

how to bind polymer custom element to the contents?

我正在尝试创建一个元素,该元素具有动态数量的选项卡,具体取决于为该元素提供的内容。我想出如何做到这一点的唯一方法是在 JS 中,但我觉得这不是 Polymer 方式,我错过了什么?你能给我指出一些可以帮助我入门的文档或其他元素吗?

这是我目前拥有的:

使用我的自定义元素

<code-file-set>
   <a href="#" tabTitle="onelink">onelink</a>
   <a href="#" tabTitle="twolink">twolink</a>
   <a href="#" tabTitle="threelink">threelink</a>
</code-file-set>

自定义元素的实现

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/core-pages/core-pages.html">
<link rel="import" href="/bower_components/paper-tabs/paper-tabs.html">

<polymer-element name="code-file-set">
  <template>

      <paper-tabs id="tabs" selected={{selected}}>
      </paper-tabs>

      <core-pages selected="{{selected}}">
        <content id="codecontent" select="a"></content>
      </core-pages>
  </template>

<script>

  Polymer('code-file-set', {
    domReady: function() {
      var codeNodes = this.$.codecontent.getDistributedNodes();

      for (var i = 0; i < codeNodes.length; i++) {
        var name = codeNodes[i].getAttribute('tabTitle');
        var tab = document.createElement('paper-tab');
        tab.innerHTML = name;
        this.$.tabs.appendChild(tab);
      }    
      this.selected = 0;
    },
  });
</script>
</polymer-element>

这行得通,但看起来很难看。也就是说,是否可以不在 JS 中创建选项卡,而是在 HTML 中以更具声明性的方式创建选项卡(请注意,我为内容中找到的每个元素创建一个选项卡)。

正确的数据绑定解决方案是将数组 (tabs) 定义为 published property 并使用 template repeat 遍历数组并将每个项目填充到 UI.

<polymer-element name="code-file-set" attributes="tabs">
    <template>
        <paper-tabs style="background-color:limegreen" selected="0">
            <template repeat="{{tab in tabs}}">
                <paper-tab>
                    <a href="{{tab.link}}">{{tab.tabTitle}}</a>
                </paper-tab>
            </template>
        </paper-tabs>
    </template>

    <script>
        Polymer('code-file-set', {
            ready: function () {
                this.tabs = [];

                for (var i = 0; i <= 3; i++) {
                    this.tabs.push({ link: '#', tabTitle: 'title ' + i });
                }
            },
        });
    </script>
</polymer-element>

将此 jsbin 视为工作示例。

我想添加一个答案,因为即使已经接受了一个答案,因为您不限于使用数据绑定。在许多情况下,使用内容可能更可取。这需要更多工作,但如果您愿意,它可以让您在其中组合其他元素。

如果您使用 <content> 元素,您可以使用 getDistributedNodes() 获得分布式 children。如果将 select 属性添加到 <content> 元素,它将忽略文本节点并创建仅包含所需元素的 NodeList。例如:<content select="a">。然后创建一个内部变量以指向那些 children,并对该变量使用模板重复。

代码示例:

<polymer-element name="x-menu">
  <template>
    <style>
      ::content > * {
        display: none;
      }
    </style>
    <content id="content" select="a"></content>
    <paper-tabs link>
      <template repeat="{{tab in tabs}}">
        <paper-tab>
          <a href="{{tab.href}}" horizontal center-center layout> 
            {{tab.textContent}}
          </a>
        </paper-tab>        
      </template>
    </paper-tabs>
  </template>
  <script>
    Polymer({
      domReady: function() {
        this.tabs = this.$.content.getDistributedNodes().array();
      }
    });
  </script>
</polymer-element>

<x-menu>
  <a href="#foo">Foo</a>
  <a href="#bar">Bar</a>
  <a href="#baz">Baz</a>
</x-menu>

示例 jsbin:http://jsbin.com/duzapu/6/edit

需要注意的一点是,如果您希望 children 的数量随时发生变化,您应该使用 onMutation 观察并相应地更新您的内部变量。