Кастомные элементы форм

Stencil позволяет создавать кастомные элементы форм, которые легко интегрируются с другими элементами страницы и обеспечивают гибкость в работе с данными. Этот подход позволяет создавать более сложные, но в то же время повторно используемые компоненты, что особенно полезно при разработке больших приложений. В Stencil кастомные элементы реализуются как веб-компоненты, что позволяет им работать в различных браузерах без зависимости от фреймворков или библиотек.

Основы создания кастомных элементов формы

Для создания кастомного элемента формы в Stencil, необходимо определить новый компонент, который будет наследовать возможности стандартного элемента формы, например, <input>, <select> или <textarea>. Это даст возможность создать элемент с собственными стилями и логикой, при этом оставив возможность для использования стандартных механизмов, таких как привязка данных и валидация формы.

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

@Component({
  tag: 'custom-input',
  styleUrl: 'custom-input.css',
  shadow: true
})
export class CustomInput {
  @State() value: string = '';

  handleInput(event: Event) {
    const input = event.target as HTMLInputElement;
    this.value = input.value;
  }

  render() {
    return (
      <input
        type="text"
        value={this.value}
        onIn put={this.handleInput.bind(this)}
      />
    );
  }
}

В данном примере создается элемент custom-input, который будет работать как обычный текстовый input. Используется метод handleInput, чтобы обновлять состояние компонента при изменении текста в поле ввода.

Использование кастомных элементов в формах

После того как компонент кастомного элемента формы создан, его можно использовать внутри стандартных HTML-форм. Это особенно полезно, если необходимо заменить стандартные элементы ввода на более сложные и функциональные.

<form>
  <label for="custom-input">Custom Input:</label>
  <custom-input id="custom-input" name="customInput" />
</form>

В приведенном примере компонент custom-input используется внутри формы как обычный элемент HTML. Все стандартные механизмы работы с формами, такие как отправка данных и валидация, остаются работоспособными.

Валидация кастомных элементов формы

В Stencil можно легко интегрировать валидацию для кастомных элементов формы, используя стандартные механизмы валидации HTML или собственные методы. Стандартная валидация формы, такая как required, minlength, maxlength, работает и с кастомными элементами, если они реализуют соответствующие атрибуты.

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

@Component({
  tag: 'validated-input',
  styleUrl: 'validated-input.css',
  shadow: true
})
export class ValidatedInput {
  @Prop() required: boolean;
  @Prop() minLength: number;
  @Prop() maxLength: number;

  private inputElement: HTMLInputElement;

  validate() {
    const validity = this.inputElement.validity;
    return validity.valid;
  }

  render() {
    return (
      <input
        ref={(el) => (this.inputElement = el)}
        required={this.required}
        minlength={this.minLength}
        maxlength={this.maxLength}
        type="text"
      />
    );
  }
}

В этом примере компонент validated-input добавляет атрибуты валидации required, minlength, maxlength. Метод validate можно использовать для проверки, валиден ли ввод в поле.

Управление состоянием и привязка данных

Stencil использует концепцию реактивного состояния, что позволяет легко привязывать данные формы к состоянию компонента. Для этого можно использовать декораторы @State и @Prop, чтобы связать внутренние данные с атрибутами и состоянием компонента.

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

@Component({
  tag: 'data-bound-input',
  styleUrl: 'data-bound-input.css',
  shadow: true
})
export class DataBoundInput {
  @Prop() label: string;
  @State() value: string = '';

  handleInput(event: Event) {
    const input = event.target as HTMLInputElement;
    this.value = input.value;
  }

  render() {
    return (
      <div>
        <label>{this.label}</label>
        <input
          type="text"
          value={this.value}
          onIn put={this.handleInput.bind(this)}
        />
      </div>
    );
  }
}

Здесь value компонента привязано к полю ввода с помощью @State. Когда пользователь вводит текст, значение автоматически обновляется в состоянии компонента.

Интеграция с внешними библиотеками и API

Stencil позволяет кастомным элементам формы работать с внешними API и интегрировать сторонние библиотеки. Это может быть полезно для реализации сложных сценариев, таких как автозаполнение, обработка ошибок или взаимодействие с сервером для валидации данных.

Пример использования сторонней библиотеки для автозаполнения:

import { Component, h, Prop, State } from '@stencil/core';
import * as autoComplete from 'autocomplete-library';

@Component({
  tag: 'autocomplete-input',
  styleUrl: 'autocomplete-input.css',
  shadow: true
})
export class AutoCompleteInput {
  @State() value: string = '';
  @Prop() apiUrl: string;

  componentDidLoad() {
    autoComplete({
      selector: 'input',
      minChars: 2,
      source: (term, response) => {
        fetch(`${this.apiUrl}?query=${term}`)
          .then(res => res.json())
          .then(data => response(data));
      }
    });
  }

  render() {
    return (
      <input
        type="text"
        value={this.value}
        onIn put={(event) => (this.value = (event.target as HTMLInputElement).value)}
      />
    );
  }
}

В данном примере используется внешняя библиотека autocomplete-library для автозаполнения. При вводе текста данные загружаются с удаленного API и отображаются в поле ввода.

Заключение

Кастомные элементы форм в Stencil — это мощный инструмент для создания сложных и настраиваемых компонентов, которые можно интегрировать в любые веб-приложения. Используя возможности реактивного состояния, валидации, привязки данных и сторонних библиотек, можно создавать гибкие и повторно используемые элементы управления формами. Эти компоненты легко адаптируются под различные требования и могут быть использованы как в небольших проектах, так и в крупных веб-приложениях.