0

有趣的问题,所以请阅读到最后。我想要实现的是在另一个 js 文件中分离模板并在需要时延迟加载它。在 React 生态系统中做同样的事情,但是模板不行!分类回购https://github.com/pranav-js/triage-repo

我在另一个 .js 文件中有我的 tsx 模板说

template-three.js有简单的 onClick ,它只会发出警报

import { h } from '@stencil/core';
export const template_three = () => {
  return <button onClick={() => alert()}>Template three here</button>;
};

当我尝试通过像这样导入 component-two.tsx 来调用此方法时

import { Component, Fragment, h, Host, State } from '@stencil/core';

@Component({
  tag: 'component-two',
  styleUrl: 'component-two.css',
  shadow: true,
})
export class ComponentTwo {
  @State() showComponentOne: any;
  method: any;
  template: string = '';

  constructor() {}

  componentWillRender() {
    this.fetchComp(2);
  }

// lazy load template when needed based on type passed

  fetchComp(type) {
    let this_ = this;
    switch (type) {
      case 0:
        import('./template').then(module => {
          this.showComponentOne = module.template_one;
        });
        break;
      case 1:
        import('./template-two').then(module => {
          this.showComponentOne = module.template_two;
        });
        break;
      case 2:
          import('./template-three').then(module => {
            this.showComponentOne = module.template_three;
          );
        break;
      default:
        break;
    }
  }

  clicked() {
    alert();
  }

  methodHere() {}

// check if template received then simply call that method with this attached

  render() {
    let this_ = this;
    return this.showComponentOne ? this.showComponentOne.apply(this) : <div></div>;
  }
}

查看呈现,但事件侦听器不起作用:/,甚至不是简单的警报 :(。当我检查时,我没有看到任何附加到按钮的事件。但是,如果我保留在组件类中的相同功能,它可以工作:(! !!

在组件内部和外部定义模板时检查两个不同的对象。 当模板在 js 之外时,$elem 为空

你能告诉我我在这里做错了什么吗?

我不能只在组件中保留模板,因为我有许多 UI 用于相同的逻辑。到目前为止,我在互联网上没有任何方法,这个答案对将 自定义模板传递给模板组件也无济于事

4

2 回答 2

2

我认为问题是 Stencil 的 tree-shakable API 和动态导入的构建时分析问题的结合。

Stencil 尝试尽可能少地发布“Stencil”代码,因此它将分析您的项目以找出您实际使用的功能,并且仅将这些功能包含在最终捆绑包中。如果您检查第./build/index-{hash}.js2 行的(在 dev www 构建中),您会发现它检测到的功能列表。

我创建了自己的快速复制并在使用动态和静态导入时比较了这个文件。以下是不同之处:

动态导入

{ vdomAttribute: false, vdomListener: false }

静态导入

{ vdomAttribute: true, vdomListener: true }

因此,Stencil 似乎不知道您仅在动态导入的模板中使用的功能,因此不会将其包含在构建中。但是,如果您在任何组件(或静态导入到组件中的文件)中使用相同的功能,Stencil 应该包含它。

因此,一个简单的解决方法是将任何侦听器附加到项目的任何组件中的任何元素。而且您必须为当前仅在动态加载的模板中使用的每个 Stencil 功能执行此操作。

另一种选择是创建一个静态包含所有动态模板的 Stencil 组件。AFAIK 这将检测所有使用的功能并为项目启用它们,即使不必在任何地方使用这个新组件。

例子:

import { Component, Host, h } from '@stencil/core';
import { Template1 } from "../../templates/template1";
import { Template2 } from "../../templates/template2";
import { Template3 } from "../../templates/template3";

@Component({
  tag: 'template-imports',
})
export class TemplateImports {
  render() {
    return (
      <Host>
        <Template1></Template1>
        <Template2></Template2>
        <Template3></Template3>
      </Host>
    );
  }
}
于 2021-12-26T12:15:34.297 回答
0

我认为应该是

@Component({
  tag: 'component-two',
  styleUrl: 'component-two.css',
  shadow: true,
})
export class ComponentTwo {
  // omitting all code that didn't change ...

  render() {
    // probably not needed
    let this_ = this;

    /* ---------------------------------------------------- */
    /* Note the change in the following line:               */
    /* showComponentOne must be the template function here. */
    /* ---------------------------------------------------- */
    return this.showComponentOne ? <this.showComponentOne onclick={this.onClick.bind(this)} /> : <div></div>;
  }
}
于 2021-12-24T12:06:43.137 回答