【问题标题】:Polymer 2 dynamically merging templatesPolymer 2 动态合并模板
【发布时间】:2017-10-21 14:01:57
【问题描述】:

我正在尝试构建呈现 JSON 对象集合的通用 Web 组件,例如树视图和多列表视图(在两个列表之间移动项目)。我想复制 iron-list 使用的模式,其中包含单个项目表示的模板被传递到组件中以供重用。

例如,给定这个 Web 组件模板:

<dom-module id="intworkspace-tree">  
  <template>
    <style include="iron-flex iron-flex-alignment">

      paper-icon-item {
        --paper-item-min-height: var(--intworkspace-tree-margin,30px);
        --paper-item-icon-width : var(--intworkspace-tree-margin,30px);
      }

      paper-icon-item:focus::before,
      paper-icon-item:focus::after {
        color: inherit;
        opacity: 0;
      }

     .node {
        margin-left: var(--intworkspace-tree-margin,30px);;
      }
    </style>

    <slot id="labelView"></slot>

    <template id="nodeView">
      <div class="layout vertical">
      <paper-icon-item on-tap="nodeSelected">
        <iron-icon icon="expand-less" slot="item-icon" hidden$="[[!hasNodes(node)]]"></iron-icon>
        <!-- label goes here-->
      </paper-icon-item>

      <iron-collapse class="node" opened hidden$="[[!hasNodes(node)]]">
        <intworkspace-tree tree="[[node.nodes]]" embedded></intworkspace-tree>
      </iron-collapse>
      </div>
  </template>

  </template>
	...
  </dom-module>

还有这个用法:

 <intworkspace-tree tree="{{testTree}}">
      <template><paper-item-body>[[node.name]]</paper-item-body>  </template>
  </intworkspace-tree>
  
我想在层次结构中呈现 JSON 树数组,该层次结构结合了 Web 组件的模板以及通过插槽提供的模板来呈现不透明的 JSON 对象。到目前为止,我已经确定了两种组合模板的方法:
  1. 利用 Polymer.Templatize.templatize API 加载模板,创建/标记新实例,并使用 DOM API 将它们附加在一起并将它们添加到 Web 组件的影子 DOM。

    李>
  2. 访问模板内容,将它们组合在一起,创建并导入新模板,然后根据需要进行克隆。

在经历了很多逆境之后,我能够成功地实现 #1 但不是 #2,这就是我提出问题的动机。 #2 对我更有吸引力,因为我更容易合并模板一次,而不是合并它们生成的标记实例,而且这种方法似乎是我可以重用嵌套模板(如 dom-repeat)的唯一方法。

我的主要障碍是,一旦加载了 Polymer 或者它的 polyfill,模板就会变得不透明,并且只能由 Polymer 模板化功能使用。例如,此代码无需任何 Polymer 导入即可正常工作:

<template>
  <div>Template Contents</div>
</template>
<div>
  Template Test
</div>
  <script>
  let template = document.querySelector("template");
  let clone = document.importNode(template.content,true);
  document.querySelector("div").appendChild(clone);
  </script>

在 Polymer 之外,template.content DOMFragment 有子元素,并且设置了 innerHTML。然而,一旦使用了 Polymer,template.content 就没有子元素,并且 innerHTML 是空的。这使我无法使用 DOM API 创建一个将可用模板混合在一起的新模板,即

let newTemplate = document.createElement("template");
newTemplate.content = ... // combine #labelView > template.content with #nodeView.content 
let nodeView = document.importNode(newTemplate.content,true);
nodeView.tree=...

也许通过设计使用标准 HTML 机制导入模板对我不起作用。是否有另一种方法可以在运行时使用 Polymer 动态创建/合并模板?同样,我的主要动机是我想重用嵌套在模板中的 dom-if 和 dom-repeat Web 组件,而无需重新实现它们的所有功能。

【问题讨论】:

    标签: polymer polymer-2.x


    【解决方案1】:

    我在这里对 Aaron 的解决方案添加一个观察,因为我没有足够的声誉来添加评论。

    注意这一行有双重导入

    let nodeTemplate = document.importNode(Polymer.DomModule.import(IntTree.is, "#nodeView"), true);
    

    这不是必需的。由于某种原因,在 chrome 和 safari 中有效,但在 FF 中无效。

    所以使用 Polymer,只使用 DomModule 导入就足够了

    let nodeTemplate = Polymer.DomModule.import(IntTree.is, '#nodeView');
    

    希望这对某人有所帮助

    【讨论】:

      【解决方案2】:

      经过进一步研究,我发现了 Polymer 2.0 的三个特性,使我能够产生令人满意的解决方案:

      1. 每当 Polymer 处理 DOM 模板时,它都会默认记住它们。此模板缓存可防止昂贵的克隆操作并简化模板绑定。 Polymer 2.0 DOM 模板文档解释说,可以将 preserve-content 属性添加到模板中以绕过允许使用原生 DOM 操作操作模板的优化。

      2. DOM 模板文档还描述了获取自定义元素的原始模板的多种方法。一种选择是调用元素的静态 template() 方法,另一种选择是使用 Polymer.DomModule.import() 函数。我对第二种方法很感兴趣,因为它允许管理默认模块模板之外的多个模板。

      3. Polymer.TemplateStamp API 类有一个内部 _stampTemplate() 函数,用于将模板标记到自定义元素的 DOM 中。我本来希望使用有据可查的 Polymer.Templatize.templatize() 函数,但它会在模板本身上查找属性和方法,在我的例子中,它不是具有定义行为的自定义元素。

        李>

      将这三个功能放在一起,我能够根据需要使用嵌套的 dom-if 和 dom-repeats 准备一个动态的可重用合并模板。

      这是函数结果:

      组件:

      <link rel="import" href="../polymer/polymer-element.html">
      <link rel="import" href="../iron-collapse/iron-collapse.html">
      <link rel="import" href="../paper-item/paper-icon-item.html">
      <link rel="import" href="../paper-item/paper-item-body.html">
      <link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
      <link rel="import" href="../iron-icons/iron-icons.html">
      <link rel="import" href="../iron-icon/iron-icon.html">
      
      
      <dom-module id="intworkspace-tree">
        <template>
          <!-- style includes don't work in stamped template, only in the shadowRoot -->
          <style include="iron-flex iron-flex-alignment">
      
          paper-icon-item {
            --paper-item-min-height: var(--intworkspace-tree-margin,30px);
            --paper-item-icon-width : var(--intworkspace-tree-margin,30px);
          }
      
          paper-icon-item:focus::before,
          paper-icon-item:focus::after {
            color: inherit;
            opacity: 0;
          }
      
         .node {
            margin-left: var(--intworkspace-tree-margin,30px);;
          }
        </style>
      
          <slot id="labelView"></slot>
        </template>
      
        <template id="nodeView">
      
       
      
          <template is="dom-repeat" items="{{tree}}" as="node" index-as="n">
              <div class="layout vertical">
                <!--<div>index: [[n]]</div>
                <div>name: [[node.name]]</div>-->
                <paper-icon-item on-tap="nodeSelected">
                  <template is="dom-if" if="[[hasNodes(node)]]">
                    <iron-icon icon="expand-more" slot="item-icon" hidden$="[[!hasNodes(node)]]"></iron-icon>
                  </template>
                  <!-- label goes here-->
                </paper-icon-item>
                <template is="dom-if" if="[[hasNodes(node)]]">
                  <iron-collapse class="node" opened>
                    <intworkspace-tree tree="[[node.nodes]]" node-template="[[nodeTemplate]]" embedded></intworkspace-tree>
                  </iron-collapse>
                </template>
              </div>
          </template>
        </template>
      
        <script>
          class IntTree extends Polymer.TemplateStamp(Polymer.Element) {
      
            static get is() {
              return 'intworkspace-tree';
            }
      
            static get properties() {
              return {
                tree: {
                  type: Array,
                  value: []
                },
                nodeTemplate: {
                  type: Object,
                }
              };
            }
      
            ready() {
              super.ready();
              if (!this.hasAttribute("embedded")) {
                let labelTemplate = this.$.labelView.assignedNodes().find((e) => {
                  return e instanceof HTMLTemplateElement;
                });
                let nodeTemplate = document.importNode(Polymer.DomModule.import(IntTree.is, "#nodeView"), true);
                let repeatTemplate = nodeTemplate.content.querySelector("template[is='dom-repeat']");
                let iconItem = repeatTemplate.content.querySelector('paper-icon-item');
                iconItem.appendChild(labelTemplate.content);
                this.nodeTemplate = nodeTemplate;
              }
              let nodeInstance = this._stampTemplate(this.nodeTemplate);
              this.shadowRoot.appendChild(nodeInstance);
            }
      
            hasNodes(node) {
              return node.nodes != null && node.nodes.length > 0;
            }
      
            nodeSelected(e) {
              let collapse = e.currentTarget.parentNode.querySelector("iron-collapse");
              let nodeIcon = e.currentTarget.parentNode.querySelector("iron-icon");
              if (collapse && nodeIcon) {
                collapse.toggle();
                if (collapse.opened) {
                  nodeIcon.icon = "expand-more";
                } else {
                  nodeIcon.icon = "expand-less";
                }
              }
            }
          }
      
          window.customElements.define(IntTree.is, IntTree);
        </script>
      </dom-module>

      用法:

      <intworkspace-tree tree="{{testTree}}">
            <template preserve-content><paper-item-body>[[node.name]]</paper-item-body></template>
        </intworkspace-tree>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-19
        相关资源
        最近更新 更多