将自定义模板传递给模具组件

2022-05-09 00:00:00 javascript web-component stenciljs

我正在使用模具创建自定义组件以复制UI-select

该组件的用法如下:

let items = [{name:"Abc", age: 10}, {name:"Xyz", age: 10}];
let itemString = JSON.stringify(items);

<dropdown-search placeholder="Select User" item-string='${itemString}'>
</dropdown-search>

则组件定义为

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

@Component({
  tag: 'dropdown-search',
})
export class DropdownSearch {
  @Element() dropdownEl: HTMLElement;
  @State() isOpen: boolean = false;
  @State() items: any = [];
  @Prop() itemString: string = '';
  @Prop() placeholder: string = '';

  componentDidLoad() {
    try {
      this.items = JSON.parse(this.itemString);
    } catch(e) {}
  }

  onClickDropdownHandler = (e: UIEvent) => {
    e.preventDefault();
    this.toggleDropdown();
  }

  toggleDropdown = () => {
    this.isOpen = !this.isOpen;
    if (this.isOpen) {
      window.setTimeout(
        () => {
          this.dropdownEl.querySelector('input').focus();
        },
        0,
      );
    }
  }

  renderOptions = () => {
    if (!Array.isArray(this.items) || !this.items.length) {
      return null;
    }

    return this.items.map((item) => (
      <li
      >
        <a href="javascript:" title="{item.name}">
         {item.name}
         <small class="d-block">age: {item.age}</small>
        </a>
      </li>
   ));
 }

 render() {
   let dropdownClassName = (this.isOpen ? 'open' : '');
   return (
    <form name="myForm">
      <div class="form-group">
        <div
          class={`btn-group dropdown ${dropdownClassName}`}
        >
          <button
            class="btn btn-default dropdown-toggle"
            onClick={this.onClickDropdownHandler}
          >
            {this.placeholder}
          </button>
          <ul class="dropdown-menu" role="menu">
            <li>
              <div class="input-group input-group-search">
                <input
                  class="form-control"
                  type="search"
                />
              </div>
            </li>
            {this.renderOptions()}
          </ul>
        </div>
      </div>
    </form>
  );
 }
}

这些项目呈现得很好。由于用户可以传递自定义对象数组,因此我需要自定义选项模板。以便用户可以在使用组件时传递它。

现在,我对组件中的选项使用静态模板,如

<a href="javascript:" title="{item.name}">
  {item.name}
  <small class="d-block">age: {item.age}</small>
</a>

但我需要一种方法从我使用模板的位置传递该模板。我不能在那里使用槽,因为我在循环中运行的所有选项中使用相同的模板。


解决方案

我是模具新手,但我只是尝试使用@Prop函数来执行此操作,它起作用了:

组件

@Component({
  tag: 'dropdown-search',
  styleUrl: 'dropdown-search.css',
  shadow: true,
})
export class DropdownSearch {
  // allow template function to be passed from outside
  @Prop template!: (item: SelectItem) => any;
  @State items!: SelectItem[] = [{name: 'dog'}, {name: 'cat'}, {name: 'elephant'}];

  render() {
    return (
      <Host>
        <p>Before Template</p>
        {/* render the custom template here: */}
        {this.items.map(item => this.template(item))}
        <p>After Template</p>
      </Host>
    );
  }
}

为该组件提供自定义模板:

class AppComponent {
  render() {
    // Here we define our custom template to be rendered in MyComponent
    const CustomTemplate = (item: SelectItem) => <p key={item.name}>Hi, I am {item.name}</p>;

    return (
      <div class="app-home">
        <dropdown-search template={CustomTemplate} />
      </div>
    );
  }
}

结果如下:

相关文章