对象数组Prop Decorator StencilJS

时间:2019-11-04 16:53:32

标签: typescript stenciljs

我想传递一个对象数组,然后遍历该数组并渲染每个对象。

我有以下html文件:

<stencil-component 
   cards = '[{"cardTitle"="placeholder", "copy"="copy1"},{"cardTitle"="placeholder2", "copy"="copy3"}]'>
</stencil-component>

在我的tsx文件中,我有以下内容:

@Prop() cards: Array<object> = [];

render(){
    return  (
      {this.cards.map(card) => {

        return (
          <div>
            <h1>{card.cardTitle}</h1>
            <p>{card.copy}</p>
          </div>
        );
      })}    
    )
}

我什至无法显示数组。我试图使用JSON.parse函数来解析数据,但这也不起作用。如果有人可以帮忙,我将不胜感激!

2 个答案:

答案 0 :(得分:2)

HTML属性只能包含字符串,因此,如果在Stencil之外使用组件,则必须将所有属性作为字符串传递。

在Stencil(可能还有一些框架)中,您可以这样传递它:

<stencil-component 
   cards={[{"cardTitle":"placeholder", "copy":"copy1"},{"cardTitle":"placeholder2", "copy":"copy3"}]}>
</stencil-component>

注意:您的JSON不正确,您需要将=替换为:

如果您需要使用纯HTML格式的组件,则必须手动解析 属性字符串或使用javascript进行设置。

examples of this in the docs

  

手动设置道具

import { Prop } from '@stencil/core';

export class TodoList {
  @Prop() myObject: object;
  @Prop() myArray: Array<string>;
}
     

HTML

<todo-list></todo-list>
<script>
  const todoListElement = document.querySelector('todo-list');
  todoListElement.myObject = {};
  todoListElement.myArray = [];
</script>
     

观看道具更改

import { Prop, State, Watch } from '@stencil/core';

export class TodoList {
  @Prop() myObject: string;
  @Prop() myArray: string;
  @State() myInnerObject: object;
  @State() myInnerArray: Array<string>;

  componentWillLoad() {
    this.parseMyObjectProp(this.myObject);
    this.parseMyArrayProp(this.myArray);
  }

  @Watch('myObject')
  parseMyObjectProp(newValue: string) {
    if (newValue) this.myInnerObject = JSON.parse(newValue);
  }

  @Watch('myArray')
  parseMyArrayProp(newValue: string) {
    if (newValue) this.myInnerArray = JSON.parse(newValue);
  }
}
     

HTML

<todo-list my-object="{}" my-array="[]"></todo-list>

答案 1 :(得分:1)

您的问题是JSON实际上不是JSON(将 = 替换为),并且在共享数据时,数据不会自动解析为对象数组通过组件的属性。我将使用getDataFromProperty之类的通用函数,并将其外包到另一个文件中,您可以在所有Web组件中使用它。但是,让它暂时保持简单:

@Prop() cards: Array<object> = [];

private getDataFromProperty(toParse):any{
 try(JSON.parse(toParse)){
  return JSON.parse(toParse);
 }catch(e){
  //some different conversations you wanna try e.g.
   console.error('Couldnt JSON parse', e);
   if(toParse.split(',').length > 0) return toParse.split(',');
 }
}

render(){
 if(!this.cards) this.cards = this.getDataFromProperty(this.cards);
    return  (
      {this.cards.map(card) => {

        return (
          <div>
            <h1>{card.cardTitle}</h1>
            <p>{card.copy}</p>
          </div>
        );
      })}    
    )
}

<stencil-component 
   cards = '[{"cardTitle": "placeholder", "copy": "copy1"},{"cardTitle": "placeholder2", "copy": "copy3"}]'>
</stencil-component>

Try and Catch将防止某些硬错误,并为您提供无法解析的情况。也许您需要针对您的需求进行微调,但是这个概念有效。在catch条件下,您可以尝试其他一些数据对话技术。

第二,我想分享一种完全不同的方法,该方法取决于您使用的环境,但是您可以使用公共方法。比起您可以直接将数据共享到Web组件:

@Prop() cards: Array<object> = [];

@Method() setData(data){
  this.cards = data;
}

render(){
  //your render function as it was
}

在HTML内

    <stencil-component id="web-component"></stencil-component>
    <script>
     let data = '[{"cardTitle": "placeholder", "copy": "copy1"},{"cardTitle": "placeholder2", "copy": "copy3"}]';

     document.getElementById("web-component").setData(data);
     //just call the setData function from outside works with jquery too
    </script>

但是在这种方法中您需要注意一点。也许将不会调用您的render函数,因为您可以仅使用this.render();在该函数中手动进行操作,也可以在变量前面使用@State装饰器。