如何使用TSX使StencilJS组件在没有组件标签本身的情况下呈现?

时间:2020-07-22 17:33:38

标签: dom jsx web-component stenciljs tsx

虽然我知道这可能是一个糟糕的做法,但我需要构建StencilJS组件,以便在render()内,由于已经存在样式指南,我不想呈现组件标签本身,并且它希望在其中构建DOM。某种方式。这是我想要实现的-组件代码(从HTML或在另一个组件内):

<tab-header-list>
  <tab-header label="tab 1"></tab-header>
  <tab-header label="tab 2"></tab-header>
</tab-header-list>

渲染时,我希望生成的DOM类似于:

<tab-header-list>
  <ul>
    <li>tab 1</li>
    <li>tab 2</li>
  </ul>
</tab-header-list>

所以在tab-header-list render()函数中,我正在做

return (
  <ul>
    <slot/>
  </ul>
);

我可以在tab-header render()函数中完成此操作

@Element() el: HTMLElement;
@Prop() label: string;

render() {
  this.el.outerHTML = `<li>${this.label}</li>`;
}

得到我想要的东西,但是如何使用 TSX 做到这一点? (为简单起见,以上代码确实很简单,但是我真正需要构建的是带有事件等的更复杂的li标签,因此我想使用TSX)

试图将DOM存储到变量中,但是我不确定如何将其分配为this.el(outerHTML似乎是我可以提出的唯一方法,但是我觉得必须有更好的方法)

@Element() el: HTMLElement;
@Prop() label: string;

render() {
  var tabheaderDOM = (<li>{this.label}</li>);

  // how can I assign above DOM to this.el somehow?
  //this.el.outerHTML = ?
}

感谢您能提供的任何帮助-在此先感谢您的宝贵时间!

2 个答案:

答案 0 :(得分:1)

不幸的是,您不能使用没有标签的自定义元素,但是有一种解决方法:

您可以使用Host元素作为结果标签的引用。

render () {
  return (
    <Host>....</Host>
  )
}

然后,您可以在样式表中为其设置display属性:

:host {
  display: contents;
}

显示:内容使元素的子代看起来像是元素父代的直接子代,而忽略了元素本身

当心:它不适用于IE,Opera mini ... https://caniuse.com/#feat=css-display-contents

UPD:

如果您不使用shadowDOM,则需要用以下标记名替换:host

tab-header {
  display: contents;
}

答案 1 :(得分:0)

功能组件可能可以帮助您实现这一目标。它们只是返回TSX元素的函数的语法糖,因此它们与常规Stencil组件完全不同。主要区别在于它们不编译为Web组件,因此仅在TSX内工作。但是它们也不会导致多余的DOM节点,因为它们只是返回函数返回的模板。

让我们举个例子:

@Element() el: HTMLElement;
@Prop() label: string;

render() {
  this.el.outerHTML = `<li>${this.label}</li>`;
}

您可以将其编写为功能组件:

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

interface ListItemProps {
  label: string;
}

export const ListItem: FunctionalComponent<ListItemProps> = ({ label }) => (
  <li>{label}</li>
);

然后您可以像使用它

import { ListItem } from './ListItem';

@Component({ tag: 'my-comp' })
export class MyComp {
  render() {
    return (
      <ul>
        <ListItem label="tab 1" />
        <ListItem label="tab 2" />
      </ul>
    );
  }
}

将呈现为

<ul>
  <li>tab 1</li>
  <li>tab 2</li>
</ul>

除了标签属性,您还可以编写功能组件以将标签作为子代接受:

export const ListItem: FunctionalComponent = (_, children) => (
  <li>{children}</li>
);

并像使用它

<ListItem>tab 1</ListItem>

BTW Host实际上是一个功能组件。要了解有关功能组件(及其局限性)的更多信息,请参见https://stenciljs.com/docs/functional-components