Polymer 中多态对象集合的模式?

Patterns for collections of polymorphic objects in Polymer?

假设我有两个单独的多态对象列表:Shape -> Circle 和 Shape -> Rectangle。 Shape 包含 "name" 和 "description" 属性,而 Circle 包含 "center" 和 "radius" 属性,而 rectangle 包含 "length" 和 "width" 属性。我想要一个单一的 Polymer 组件,"shape-list",它能够处理圆列表或矩形列表的显示,并显示列表中每种类型的特定属性。

"shape-list" 的模板可能如下所示:

<template>
  <ul>
    <template is="dom-repeat" items="[[shapes]]" as="shape">
      <li>
        <shape-entry shape="[[shape]]">
          <!-- The user of shape-list knows whether we want to display
               Rectangles or Circles.  We want to customize the display
               of each shape-entry with information specific to each
               shape by using some sort of prototype element supplied
               to the shape-list tag. -->
          <content select="..."></content>
        </shape-entry>
      </li>
    </template>
  </ul>
</template>

"shape-entry" 的模板看起来像这样:

<template>
  Name: <span>[[shape.name]]</span>
  Description: <span>[[shape.description]]</span>
  <!-- Ideally we would take the passed-in prototype element and
       stamp it out here. -->
  <content select="...?"></content>
</template>

此外,我们还有 "shape-circle" 和 "shape-rect" 的模板:

形状圆:

<template>
  Center: <span>[[shape.center]]</span>
  Radius: <span>[[shape.radius]]</span>
</template>

矩形形状:

<template>
  Length: <span>[[shape.length]]</span>
  Width: <span>[[shape.width]]</span>
</template>

理想情况下,用法如下所示:

我可以看到两种实现上述目标的方法:

  1. 不使用"content"标签,而是在shape-list和shape-entry元素上设置属性为实际原型对象引用或特定形状的名称,然后使用一些魔法 JavaScript 创建基于 属性 的特定形状元素的实例,并手动将所有数据绑定在一起。这会给 assemble 元素和数据绑定带来额外的复杂性。

  2. 将"shape-list"和"shape-entry"复制到"rect-list"、"circle-list"和"rect-entry"、"circle-entry",并共享样式和子类型之间的行为。这会导致一些代码重复。

是否有更好的方法来实现上述目标?我(理想情况下)更喜欢完全声明式的方法!

您可以有一个形状列表组件,它使用 "if" 模板来显示适当的形状组件(矩形条目、圆形条目)。每个形状条目都应声明一个共享行为,例如具有所有共享形状行为的 ShapeBehavior 以避免口是心非。

.. inside the dom-repeat
  <template is="dom-if" if="{{_isRect(item)}}" >
    <rect-entry shape={{item}} ></rect-entry>
  </template>
  <template is="dom-if" if="{{_isCircle(item)}}" >
    <circle-entry shape={{item}} ></circle-entry>
  </template>

如果要动态传递应使用的元素,则需要一个编程解决方案。