1

我想创建一个控件,将数据转换为我需要的东西。

目前,我用一个全局变量来解决这个问题。代码看起来像这样:(小写功能只是为了以简单的方式演示它。通常我想将它用于对象数组。例如,获取某些名称和 id 的不同值)

<dom-module id="my-tolower">
  <script>
    "use strict";
    Polymer({
      is: 'my-tolower',
      properties: {
        input: {
          type: String,
          value: "",
        },
        output:{
          type: String,
          value: "",
          notify: true,
        }
      },
      observers:[
        "_inputChanged(input)",
      ],
      _inputChanged: function(newInput, oldInput){
        this.set("output", newInput.toLowerCase());
      }
    });
  </script>
</dom-module>

用法:

<my-tolower input="[[output.name]]" output="{{lower}}">[[lower]]</my-tolower>

如果我只使用该变量lower一次,此解决方案效果很好。在 a 内部<dom-repeat>,我遇到了问题。

如何轻松制作仅在内部可用的自定义变量my-tolower?和Polymer的dom-repeat完全一样吗?

我查看了Polymer 的<dom-repeat>代码,但我不知道它是如何工作的。这甚至可以在自定义元素中实现吗?我需要创建自定义模板吗?


为了更好地解释我的问题,我添加了一个更大的示例来详细解释我的问题。

HTMLImports.whenReady(() => {
  Polymer({
    is: 'my-app',
    ready: function(){
      //In my real Problem this value comes from a websocket...
      this.devices = [{
        name: "PC 1",
        components: [
          {
            name: "HDD1",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor1", usage: "DontKnow2"},
              { type: "Processor2", usage: "DontKnow3"}
            ]
          },
          {
            name: "Another Piece Of Hardware",
            processors: [
              {
                type: "Processor4",
                usage: "Dont Know 1"
              },
              { type: "Processor3", usage: "DontKnow2"},
              { type: "Processor4", usage: "DontKnow3"}
            ]
          }
        ]
      },
      {
        name: "PC 2",
        components: [
          {
            name: "My third piece of hardware",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor2", usage: "DontKnow2"},
              { type: "Processor3", usage: "DontKnow3"}
            ]
          }
        ]
      }];
      //this.devices must not be changed!
    }
  });
  
  
  Polymer({
    is: 'my-distinct',
    properties: {
      inputs: {
        type: String
      },
      outputs:{
        computed: '_getDistincts(inputs, path)',
        notify: true
      },
      path: {
        type: String,
        value: ""
      }
    },
    _getDistincts(inputs, path){
      let result = [];
      
      for(let key in inputs){
        if(inputs.hasOwnProperty(key)){
          let x = inputs[key];
          if(path && path != ""){
            x = x[path];
          }
          
          if(result.indexOf(x) < 0){
            result.push(x);
          }
          else{
            //Already Exists
          }
        }
      }
      
      return result;
    }
    
  });
  
 
});
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <my-app></my-app>
  As you can see, there is always "Processor1", "Processor2" and "Pocessor3" available although this is only the result of the last computers component. You can see the right result (but with duplicates) if you use the comment I made instead.
  
  <dom-module id="my-app">
    <template>
      <ul>
        <template is="dom-repeat" items="[[devices]]" as="device">
          <li>[[device.name]]
          <ul>
            <template is="dom-repeat" items="[[device.components]]" as="component">
              <li>[[component.name]]
                <ul>
                  <!-- This is my code with using distinct -->
                  <my-distinct inputs="[[component.processors]]" 
                      outputs="{{distinctProcessorNames}}" 
                      path="type">
                    <template is="dom-repeat" items="[[distinctProcessorNames]]" as="processorName">
                      <li>[[processorName]]
                        <!-- Here I could iterate over all processors (filtered) and list their usages-->
                      </li>
                    </template>
                  </my-distinct>
                  
                  <!-- This is my code without using distinct. -->
                  <!--template is="dom-repeat" items="[[component.processors]]" as="processor">
                    <li>[[processor.type]]
                      <ul>
                        <li>Used for [[processor.usage]]</li>
                      </ul>
                    </li>
                  </template-->
                </ul>
              </li>
            </template>
          </ul>
          </li>
        </template>
      </ul>
    </template>
  </dom-module>
</body>

演示

4

2 回答 2

1

You are using 2 different Polymer custom elements <my-app> and <my-distinct>. Therefore you should declare the second one with its proper <dom-module> statement:

<dom-module id="my-distinct">
    <template>
        <template is="dom-repeat" items="[[outputs]]" as="processorName">
            <li>[[processorName]]
        </template>
    </template>
</dom-module>

Then use your computed property (based on the attribute value) outputs as the items value of <template is="dom-repeat">.

Demo below:

HTMLImports.whenReady(() => {
  Polymer({
    is: 'my-app',
    ready: function(){
      //In my real Problem this value comes from a websocket...
      this.devices = [{
        name: "PC 1",
        components: [
          {
            name: "HDD1",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor1", usage: "DontKnow2"},
              { type: "Processor2", usage: "DontKnow3"}
            ]
          },
          {
            name: "Another Piece Of Hardware",
            processors: [
              {
                type: "Processor4",
                usage: "Dont Know 1"
              },
              { type: "Processor3", usage: "DontKnow2"},
              { type: "Processor4", usage: "DontKnow3"}
            ]
          }
        ]
      },
      {
        name: "PC 2",
        components: [
          {
            name: "My third piece of hardware",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor2", usage: "DontKnow2"},
              { type: "Processor3", usage: "DontKnow3"}
            ]
          }
        ]
      }];
      //this.devices must not be changed!
    }
  });
  
  Polymer({
    is: 'my-distinct',
    properties: {
      inputs: {
        type: String
      },
      outputs:{
        computed: '_getDistincts(inputs, path)', notify: true
      },
      path: {
        type: String,
        value: ""
      }
    },
    _getDistincts(inputs, path){
      let result = [];
      
      for(let key in inputs){
        if(inputs.hasOwnProperty(key)){
          let x = inputs[key];
          if(path && path != ""){
            x = x[path];
          }
          
          if(result.indexOf(x) < 0){
            result.push(x);
          }
        }
      }
      //console.log( result )
      return result;
    } 
  });  
});
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <my-app></my-app>
  
  <dom-module id="my-app">
    <template>
      <ul>
        <template is="dom-repeat" items="[[devices]]" as="device">
          <li>[[device.name]]
          <ul>
            <template is="dom-repeat" items="[[device.components]]" as="component">
              <li>[[component.name]]
                <ul>
                  <my-distinct inputs="[[component.processors]]" path="type">
                  </my-distinct>
                
                </ul>
              </li>
            </template>
          </ul>
          </li>
        </template>
      </ul>
    </template>
  </dom-module>

  <dom-module id="my-distinct">
    <template>
        <template is="dom-repeat" items="[[outputs]]" as="processorName">
            <li>[[processorName]]
        </template>
    </template>
  </dom-module>
</body>

于 2017-03-23T23:12:26.083 回答
1

正如您所发现的,在 a 中声明的属性<dom-repeat>(即,lower在本例中)并非仅限于 the<dom-repeat>或其迭代。因此,每次迭代都会覆盖先前的lower值,并且lower<dom-repeat>.

但是,您可以通过将输出属性附加到if is anitem中的每个迭代器来实现类似的作用域效果。<dom-repeat>itemObject

例如,考虑一个<x-foo>元素,它接受一个输入数组Objects 并将每个输入传递给<my-tolower>,它将一个新值写入_output(迭代器上的附加属性):

<template is="dom-repeat" items="[[inputs]]" as="x">
  <!-- Attach output to a new property on item (i.e., "_output") -->
  <my-tolower input="[[x.input]]" output="{{x._output}}"></my-tolower>
</template>

HTMLImports.whenReady(() => {
  Polymer({
    is: 'x-foo',
    properties: {
      inputs: Array
    },

    _toObjArray: function(inputs) {
      // Map inputs into objects so that we can attach properties to each iterator in a dom-repeat
      return inputs.map(input => ({input}));
    }
  });

  Polymer({
    is: 'my-tolower',
    properties: {
      input: {
        type: String,
        value: "",
      },
      output: {
        computed: '_computeOutput(input)',
        notify: true,
      }
    },
    _computeOutput: function(input) {
      return input.toLowerCase();
    }
  });
});
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <x-foo inputs='["aLPha", "brAVo", "CHarLiE", "DelTA", "epSiLoN"]'></x-foo>

  <dom-module id="x-foo">
    <template>
      <template is="dom-repeat" items="[[_toObjArray(inputs)]]">
        <!-- Attach output to a new property on item (i.e., "_output") -->
        <my-tolower input="[[item.input]]" output="{{item._output}}"></my-tolower>

        <div>
          <span>[[item.input]] -> [[item._output]]</span>
        </div>
      </template>
    </template>
  </dom-module>
</body>

演示

在您的代码中,您有一个嵌套对象,用于嵌套dom-repeats。上面的相同技术可以应用于每个嵌套级别,但您的示例只需要在最内层使用它。您可以<my-distinct>.outputs通过将输出附加到迭代器(即 )来提供自己的“本地”变量component

<my-distinct outputs="{{component.distinctProcessorNames}}" ...>

然后,你会dom-repeat像这样在你的内心使用它:

<template is="dom-repeat" items="[[component.distinctProcessorNames]]" ...>

HTMLImports.whenReady(() => {
  Polymer({
    is: 'my-app',
    ready: function(){
      this.devices = [{
        name: "PC 1",
        components: [
          {
            name: "HDD1",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor1", usage: "DontKnow2"},
              { type: "Processor2", usage: "DontKnow3"}
            ]
          },
          {
            name: "Another Piece Of Hardware",
            processors: [
              {
                type: "Processor4",
                usage: "Dont Know 1"
              },
              { type: "Processor3", usage: "DontKnow2"},
              { type: "Processor4", usage: "DontKnow3"}
            ]
          }
        ]
      },
      {
        name: "PC 2",
        components: [
          {
            name: "My third piece of hardware",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor2", usage: "DontKnow2"},
              { type: "Processor3", usage: "DontKnow3"}
            ]
          }
        ]
      }];
    }
  });
  
  
  Polymer({
    is: 'my-distinct',
    properties: {
      inputs: {
        type: String
      },
      outputs:{
        computed: '_getDistincts(inputs, path)',
        notify: true
      },
      path: {
        type: String,
        value: ""
      }
    },
    _getDistincts(inputs, path){
      let result = [];
      
      for(let key in inputs){
        if(inputs.hasOwnProperty(key)){
          let x = inputs[key];
          if(path && path != ""){
            x = x[path];
          }
          
          if(result.indexOf(x) < 0){
            result.push(x);
          }
          else {
            //Already Exists
          }
        }
      }
      
      return result;
    }
    
  });
  
 
});
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <my-app></my-app>
  
  <dom-module id="my-app">
    <template>
      <ul>
        <template is="dom-repeat" items="[[devices]]" as="device">
          <li>[[device.name]]
            <ul>
              <template is="dom-repeat" items="[[device.components]]" as="component">
                <li>[[component.name]]
                  <ul>
                    <my-distinct inputs="[[component.processors]]" outputs="{{component.distinctProcessorNames}}" path="type">
                    </my-distinct>

                    <template is="dom-repeat" items="[[component.distinctProcessorNames]]" as="processorName">
                      <li>[[processorName]]</li>
                    </template>                  
                  </ul>
                </li>
              </template>
            </ul>
          </li>
        </template>
      </ul>
    </template>
  </dom-module>
</body>

您的演示与更新

您评论说您不想克隆任何对象或修改输入。不幸的是,使用上面描述的迭代器属性技术是不可能的。在这种情况下,更好的选择是为 提供一个模板<my-distinct>,它将封装任何转换而不影响输入。

于 2017-03-17T13:17:44.643 回答