LitElement: Когда Template определяется как const, как вызывать функции - PullRequest
0 голосов
/ 25 апреля 2020

Когда шаблон определен в отдельном файле, невозможно вызвать функцию в компоненте. Но если шаблон определен непосредственно как return render htmlcall this.funct, это работает. Как вызвать функцию, если шаблон определен в отдельном файле.

Component.ts

import { LitElement, html} from 'lit-element';
import { cTemplate } from './template/ctemplate';

@customElement('card-form')
export class cardFormComponent extends LitElement {

  constructor() {
    super();
  }

  render() {
    return cTemplate;
  }

  createRenderRoot() {
    return this;
  }

  validateForm() {
    alert('ok');
  }
}


**tempalate.ts**


import {  html } from 'lit-element';

export const cTemplate = html`
 <div>
        <button class="button" @click="${this.validateForm}">Validate</button>
      </div>
';

1 Ответ

0 голосов
/ 29 апреля 2020

Я не уверен, почему вы помещаете шаблон в другой файл, но я думаю, что ваш реальный вариант использования более сложный или вы пытаетесь повторно использовать один и тот же шаблон в нескольких компонентах.

В любом случае, прежде чем пытаться ответить на вопрос, как вы могли бы привести свой конкретный пример в действие, я бы порекомендовал почитать умные против тупых компонентов. Короче говоря, этот шаблон знает слишком много, он знает, что должна быть такая функция, как validateForm, которая будет вызываться при нажатии кнопки (это тесно связывает шаблон с компонентом, поэтому он как бы лишает смысла хранить его в разных файлах) , Возможно, лучшим подходом (если вы хотите отделить вещи) является предоставление обратного вызова для запуска при нажатии кнопки. Обратным вызовом может быть любое действие, которое нужно выполнить при нажатии кнопки.

Теперь, чтобы исправить ваш пример (а также, возможно, сделать его более гибким), вы должны понять, что означает this в JavaScript. this - это текущий контекст вашей функции, и в зависимости от того, как ваша функция создается и вызывается, для нее будут заданы разные вещи.

В вашем файле template.ts у вас нет функции (хотя способ переноса модулей становится единым), но у вас все еще есть this, в этом контексте this является контекстом самого модуля. Итак, внутри вашего шаблона вы пытаетесь вызвать module.validateForm, которого не существует. Причина этого в том, что вы создаете фрагмент при загрузке модуля, а не тогда, когда он необходим для render.

Первый шаг в решении - создать вместо этого фрагмент в функции и экспортировать его, чтобы его можно было вызывать из render для подготовки фрагмента. Таким образом, вы можете начать контролировать, что this находится внутри функции. Я не уверен, нужен ли следующий шаг, но если this все еще не является контекстом вашего класса компонентов, вам нужно будет использовать bind, чтобы this стал классом компонента.

См. Полный пример ниже:
Component.ts

import { LitElement, html} from 'lit-element';
import { cTemplate } from './template/ctemplate'; // cTemplate is now a function, not a const

@customElement('card-form')
export class cardFormComponent extends LitElement {

  constructor() {
    super();
    this.cTemplate = cTemplate.bind(this); // This step forces this inside of the cTemplate function to be the component class. This might not be needed.
  }

  render() {
    return this.cTemplate(); // .bind() returns a new function, which we save on the component class so we use this in order to call the new version which has this = component class
  }

  validateForm() {
    alert('ok');
  }
}


**tempalate.ts**


import {  html } from 'lit-element';

export function cTemplate() {
    return html`
        <div>
            <button class="button" @click="${this.validateForm}">Validate</button>
        </div>
    ';
}

Для улучшения:
BetterComponent.ts

import { LitElement, html} from 'lit-element';
import { cTemplate } from './template/ctemplate';

@customElement('card-form')
export class cardFormComponent extends LitElement {

  constructor() {
    super();
    this.cTemplate = cTemplate.bind(this);
  }

  render() {
    return this.cTemplate(this.validateForm, 'Validate');
  }

  validateForm() {
    alert('ok');
  }
}


**tempalate.ts**


import {  html } from 'lit-element';

export function cTemplate(onClick, label) {
    // cTemplate is now a function that creates a snippet for a button that calls a function when the button is clicked (or, a button "component")
    return html`
        <div>
            <button class="button" @click="${onClick}">${label}</button>
        </div>
    ';
}

Я бы все же подчеркнул, что это похоже на странную картину. Если вы хотите создать компонент кнопки, который вы можете использовать повторно, я бы вместо этого сделал его полноценным веб-компонентом. Где render возвращает то, что cTemplate делает прямо сейчас, и внутри cardForm я бы сделал render, просто создав что-то вроде:

html`<my-button label="${'Validate'}" .onClick="${this.validateForm}"></my-button>`

Вы также можете заставить my-button запускать событие click как настоящая кнопка и вместо нее используйте @click.

...