聚合物就绪函数仅调用一次

Polymer ready function called only once

我正在测试 Polymer 以开发一个我想在 html 中多次重复使用的组件(见下图)。我开发了以下元素:

<link rel="import" href="bower_components/polymer/polymer.html">
<script src="js/fabric.js"></script>

<dom-module id="tooth-element">
  <template>
    <style>
      #labelWrapper {
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 35px;
        font-weight: bold;
        height: 40PX;
      }
    </style>

    <div id="toothWrapper">
      <div id="upperRootWrapper">
        <canvas id="upperRoot" />
      </div>

      <div>
        <canvas id="tooth" />
      </div>

      <div id="lowerRootWrapper">
        <canvas id="lowerRoot" />
      </div>

      <div id="labelWrapper">
        <p>{{toothLabel}}</p>
      </div>
    </div>
  </template>

  <script>
  var TOOTH_SIZE = 50;
  var TOOTH_GAP = 5;

  var UPPERROOTID = 'upperRoot';
  var LOWERROOTID = 'lowerRoot';
  var TOOTHID = 'tooth';

  Polymer({
    is: "tooth-element",
    properties: {
      // declare the owner property
      showUpperRoot: {
        type: Boolean,
        value: true
      },
      showLowerRoot: {
        type: Boolean,
        value: true
      },
      toothLabel: {
        type: String,
        value: 30
      }
    },
    ready: function() {
      drawUpperRoot(this.showUpperRoot);
      drawTooth();
      drawLowerRoot(this.showLowerRoot);
      initLabel(this.toothLabel);
    }
  });

  function initLabel (label) {
    document.getElementById("labelWrapper").style.width = new String(3*TOOTH_SIZE)+'px';
  }

  function drawUpperRoot (isVisible) {
    var canvas = new fabric.Canvas(UPPERROOTID);
    if (isVisible) {
      canvas.setHeight(TOOTH_SIZE+TOOTH_GAP);
      canvas.setWidth(TOOTH_SIZE*3+TOOTH_GAP);
      canvas.renderAll();
      canvas.add(drawFace(1));
    } else {
      document.getElementById("upperRootWrapper").style.display = "none";
    }
  }

  function drawTooth () {
    var canvas = new fabric.Canvas(TOOTHID);
    canvas.setHeight(TOOTH_SIZE*3+TOOTH_GAP*2);
    canvas.setWidth(TOOTH_SIZE*3+TOOTH_GAP*2);
    canvas.renderAll();
    canvas.add(drawFace(2));
    canvas.add(drawFace(3));
    canvas.add(drawFace(4));
    canvas.add(drawFace(5));
    canvas.add(drawFace(6));
    //canvas.add(drawFace(7));
  }

  function drawLowerRoot (isVisible) {
    var canvas = new fabric.Canvas(LOWERROOTID);
    if (isVisible) {
      canvas.setHeight(TOOTH_SIZE+TOOTH_GAP*2);
      canvas.setWidth(TOOTH_SIZE*3+TOOTH_GAP*2);
      canvas.renderAll();
      canvas.add(drawFace(7));
    } else {
      document.getElementById("lowerRootWrapper").style.display = "none";;
    }
  }

  function drawFace(face) {
    var coordinates;
    switch (face) {
      case 1:
      coordinates = getFace1Coordinates();
      break;
      case 2:
      coordinates = getFace2Coordinates();
      break;
      case 3:
      coordinates = getFace3Coordinates();
      break;
      case 4:
      coordinates = getFace4Coordinates();
      break;
      case 5:
      coordinates = getFace5Coordinates();
      break
      case 6:
      coordinates = getFace6Coordinates();
      break;
      case 7:
      coordinates = getFace7Coordinates();
      break;
      default:
      coorddinates = null;
    }

    face = new fabric.Polygon(coordinates, {
      fill: '#E1E1E1',
      selectable: false,
      stroke: 'green'
    });
    face.on('mousedown', function () {
      if (face.fill == '#E1E1E1') {
        face.fill = '#878787';
      } else {
        face.fill = '#E1E1E1';
      }
    });
    return face;
  }

  function getFace1Coordinates() {
    return [{x: TOOTH_SIZE, y: 0}, {x: TOOTH_SIZE*2+TOOTH_GAP, y: 0}, {x: TOOTH_SIZE*3+TOOTH_GAP, y: TOOTH_SIZE}, {x: 0, y: TOOTH_SIZE}];
  }

  function getFace2Coordinates() {
    return [{x: 0, y: TOOTH_GAP}, {x: TOOTH_SIZE, y: TOOTH_SIZE+TOOTH_GAP}, {x: TOOTH_SIZE, y: TOOTH_SIZE*2+TOOTH_GAP}, {x: 0, y: TOOTH_SIZE*3}];
  }

  function getFace3Coordinates() {
    return [{x: 0, y: 0}, {x: TOOTH_SIZE, y: TOOTH_SIZE}, {x: TOOTH_SIZE*2, y: TOOTH_SIZE}, {x: TOOTH_SIZE*3, y: 0}];
  }

  function getFace4Coordinates() {
    return [{x: TOOTH_SIZE*3+TOOTH_GAP, y: 0}, {x: TOOTH_SIZE*2+TOOTH_GAP, y: TOOTH_SIZE}, {x: TOOTH_SIZE*2+TOOTH_GAP, y: TOOTH_SIZE*2+TOOTH_GAP}, {x: TOOTH_SIZE*3+TOOTH_GAP, y: TOOTH_SIZE*3}];
  }

  function getFace5Coordinates() {
    return [{x: 0, y: TOOTH_SIZE*3+TOOTH_GAP}, {x: TOOTH_SIZE+TOOTH_GAP, y: TOOTH_SIZE*2+TOOTH_GAP}, {x: TOOTH_SIZE*2, y: TOOTH_SIZE*2+TOOTH_GAP}, {x: TOOTH_SIZE*3+TOOTH_GAP, y: TOOTH_SIZE*3+TOOTH_GAP}];
  }

  function getFace6Coordinates() {
    return [{x: TOOTH_SIZE+TOOTH_GAP, y: TOOTH_SIZE+TOOTH_GAP}, {x: TOOTH_SIZE*2, y: TOOTH_SIZE+TOOTH_GAP}, {x: TOOTH_SIZE*2, y: TOOTH_SIZE*2}, {x: TOOTH_SIZE+TOOTH_GAP, y: TOOTH_SIZE*2}];
  }

  function getFace7Coordinates() {
    return [{x: 0, y: 0}, {x: TOOTH_SIZE, y: TOOTH_SIZE}, {x: TOOTH_SIZE*2, y: TOOTH_SIZE}, {x: TOOTH_SIZE*3, y: 0}];
  }
  </script>
</dom-module>

我正在尝试将其导入到 index.html 文件中:

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
        <link rel="import" href="tooth-element.html">
    </head>

    <body>
        <div id="line1">
            <tooth-element></tooth-element>
            <tooth-element></tooth-element>
        </div>
    </body>
</html>

当我在 div 行 1 中放置两个牙齿元素时出现问题。第二个元素从不显示,因为从不为它调用 ready 函数。我不知道我应该怎么做才能解决这个问题。任何帮助将不胜感激

我想在 html 中重复的组件布局如下所示(我得到的是第一个牙齿元素的图像,但不是第二个牙齿元素):

(解决方案) 我没有正确使用 DOM(正如 Neil John Ramal 所解释的)。使用 Glenn 和 Neil 关于使用 Poly.dom API 的建议,我能够得到我想要的行为

在处理本地 DOM(即 document.getElementByIddocument.querySelector 等)时,请尽量避免使用常规 DOM API .请改用 Polymer.dom。请注意,当您将 Polymer 设置为使用 Shadow DOM 而不是 Shady DOM 时,您的代码可能会失败,因为常规 DOM 访问器无法穿透 Shadow DOM (封装是它的特征之一,Shady DOM 试图接近它)。

代码中的一个问题是生成的元素与某些全局对象紧密耦合(例如 drawUpperRoot)。这实质上破坏了您的元素封装,因为此代码也将被该元素的其他实例使用,因此您基本上是让它们依赖于全局范围,而不是使用它们自己的范围。

还有这个代码:

function initLabel (label) {
  document.getElementById("labelWrapper").style.width = new String(3*TOOTH_SIZE)+'px';
}

意味着当您创建两个 tooth-element 时,第二个元素基本上会引用第一个元素的 labelWrapper 而不是它自己的。

https://www.polymer-project.org/1.0/docs/devguide/local-dom.html

document.querySelector() return 它在文档中找到的第一个元素,第二个被忽略。

将文档更改为此应该可以解决问题。

document.querySelector('#labelWrapper') -> this.querySelector(#labelWrapper)

document.querySelector('#labelWrapper') -> Polymer.dom(this).querySelector('#labelWrapper')