如何从模板元素中获取 child 元素?

How to get child element from template element?

dom-change event object e in Polymer.dom(e).localTarget 给了我 <template is="dom-if" 它应该的。但是如何访问 child <div id="uploadedImage1"firstChildfirstElementChild 为空。

  <template is="dom-if" if="[[uploadedImage1]]">
    <div id="uploadedImage1" class="row-image horizontal layout">
      foo
    </div>
  </template>

我想也许我需要从 localTarget 执行另一个查询 object 但没有成功:

    this.$['images-container'].addEventListener('dom-change', (e)=> {
      var bob = Polymer.dom(e).localTarget;
      var sue = Polymer.dom(bob).querySelector('div')
      console.log(sue);
    });

我也试过这些都没有成功:

    this.$['images-container'].addEventListener('dom-change', (e)=> {
      var bob = Polymer.dom(e).localTarget;
      var sue = this.queryEffectiveChildren(bob);
      console.log(sue);
    });

    this.$['images-container'].addEventListener('dom-change', (e)=> {
      var bob = Polymer.dom(e).localTarget;
      var sue = bob.getEffectiveChildNodes();
      console.log(sue);
    });
  }

来自 children length documentation example,甚至 Polymer.dom(this).children.length 返回 0:

<dom-module id="image-uploader">
  <template>
    <style include="iron-flex iron-flex-factors iron-flex-alignment">


    <div id="images-container" class="horizontal layout center wrap">

      <div hidden="[[uploadedImage1]]" class="layout vertical center-center">
        <div class="row-image horizontal layout">
          <input
            type="file"
            name="file"
            data-uploaded="uploadedImage1"
            id="image1"
            accept="image/jpeg"
            class="inputfile" />
          <label
            for="image1"
            id="image1"
            class="image-show horizontal layout center center-justified">
            <iron-icon icon="add" prefix></iron-icon>
            Upload Image
          </label>
        </div>
        <i>*Main Image</i>
      </div>

      <template is="dom-if" id="foo" if="[[uploadedImage1]]">
        <div id="uploadedImage1">
          foo
        </div>
      </template>

    </div>

  </template>

  <script>
    Polymer({
      is: 'image-uploader',
      properties: {
        uploadedImage1: {
          type: Boolean,
          value: false
        }
      },
      ready: function(e) {
          console.log(Polymer.dom(this).children.length);

我看到了一些问题,所以我会讨论它们并在最后给出一个工作示例。

理解template

就组件的本地 DOM 而言,<div id="uploadedImage1" ... 元素可以而且永远不会是 dom-if 模板的子元素。

根据 W3C Living Documenttemplate 标签定义了一大块标记(称为 DocumentFragment),它实际上并不存在于主文档中,并且可以被克隆并放入文档中在运行时。它不包含任何呈现的标记,因此您不能询问 template 它在文档的其余部分中的用途。

用一个真实世界的例子来说明,考虑一个橡皮图章(模板)和一张 sheet 纸(文档)。如果您在邮票上涂上墨水并将其按在纸上一次或多次,您无法通过查看橡皮图章来了解它在纸上印了什么、印在哪里或印了多少次图像。要获得该信息,您必须查看论文本身。

如果您在模板周围添加一个容器元素,并将其记录到控制台,您会从文档的角度非常清楚地看到它的样子:

<div id="container" class="style-scope my-el">
  <div id="uploadedImage1" class="style-scope my-el">
    foo
  </div>
  <template is="dom-if" id="foo" class="style-scope my-el"></template>
</div>

了解 dom-change 事件背景

您有一个合理的想法使用 Polymer 的 DOM 方法来查找您想要的元素,但是在您的所有尝试中,您都是从事件目标的上下文开始的,它是模板。

同样,模板实际上并不包含您要查找的元素,因此您永远不会在此处找到它。

了解 Polymer 的 DOM 基础知识

您引用的文档用于访问标记为 <container> 的 Light DOM 个子级。在你的例子中,你没有将任何光 DOM 子元素标记到你的元素阴影 DOM 中。您正在使用 dom-if 模板根据状态有条件地 show/hide 内容。


解决方案

您只需使用 $$ shorthand 方法要求您的组件在组件的本地 DOM 中查找元素,即可实现您想要的效果。需要考虑的一件事是出于性能原因,一旦条件变为真,Polymer 就会标记 dom-if 模板的内容,然后随后使用 CSS 来显示和隐藏它,因此模板可能是这样的在 DOM 但未显示。

这是一个工作示例(参见 fiddle)的摘录,它通过让 dom-change 侦听器访问组件对象(通过 bind())来实现您的目标,因此它可以a) 访问组件的本地 DOM 以查找元素 b) 考虑 dom-if 条件是否为真。

this.$.foo.addEventListener('dom-change', function() {
  if (this.prop1) {
    console.log(this.$$('#uploadedImage1'));
  } else {
   console.log(null);
  }
}.bind(this));

Polymer.dom(e).localTarget.content 让我可以访问 documentFragment,至少它在 Chrome.

上有效