Nie używaj ukrytego elementu <input>, aby wyświetlić wartość elementu niestandardowego w formularzu. Używaj elementów niestandardowych powiązanych z formularzem (FACE): dzięki formAssociated i ElementInternals element przesyła własną wartość, uczestniczy w walidacji i odzwierciedla stan formularza w sposób natywny.
class RatingInput extends HTMLElement {
// MANDATORY: opt in. Without this, attachInternals() form APIs are unavailable.
static formAssociated = true;
#internals;
#value = '';
constructor() {
super();
this.#internals = this.attachInternals();
this.attachShadow({ mode: 'open', delegatesFocus: true });
}
connectedCallback() {
// Validate initial state once attributes (such as `required`) are present.
this.#validate();
}
get value() { return this.#value; }
set value(v) {
this.#value = v;
// Push the value into the owning <form> for submission.
this.#internals.setFormValue(v);
this.#validate();
}
#validate() {
if (this.hasAttribute('required') && !this.#value) {
// Mark invalid and supply the native validation message + anchor.
this.#internals.setValidity(
{ valueMissing: true },
'Please choose a rating.',
this.shadowRoot.querySelector('[tabindex]'),
);
} else {
this.#internals.setValidity({}); // clear
}
}
// Optional FACE lifecycle hooks:
formResetCallback() { this.value = ''; }
formDisabledCallback(disabled) {
// Disable internal controls so they leave the tab order and ignore clicks.
// Do NOT toggle `disabled` on `this`, or a `<fieldset disabled>` toggle will
// leave the host permanently stuck with its own `disabled` attribute.
for (const el of this.shadowRoot.querySelectorAll('button')) {
el.disabled = disabled;
}
}
formStateRestoreCallback(state) { this.value = state; }
}
customElements.define('rating-input', RatingInput);
Najważniejsze kwestie:
static formAssociated = truejest WYMAGANY; odblokowuje metodyElementInternalszwiązane z formularzem i cykl życiaformXxxCallback.setFormValue(value)to element, który przesyła dane, bez konieczności podawania ukrytych danych wejściowych. W przypadku elementów sterujących z wieloma wartościami przekażFormData.setValidity(flags, message, anchor)integruje się z natywną walidacją ograniczeń: formularz nie zostanie przesłany, jeśli jest nieprawidłowy, stosowane są:invalid/:valid, a element kotwicy otrzymuje fokus w raporcie. Zadzwoń pod numersetValidity({}), aby wyjaśnić sprawę. Pseudoklasy:user-valid/:user-invaliduwzględniające interakcje nie są spójnie powiązane z elementami powiązanymi z formularzem w różnych przeglądarkach. Zanim zaczniesz na nich polegać, sprawdź, czy są obsługiwane, zamiast zakładać, że śledzą interakcje użytkownika w taki sam sposób jak w przypadku elementów natywnych.- Zaimplementuj
formResetCallback,formDisabledCallbackiformStateRestoreCallback, aby element zachowywał się jak natywny element sterujący podczas resetowania,fieldset[disabled]i przywracania autouzupełniania wstecz/do przodu. WformDisabledCallback(disabled)wyłącz elementy sterujące (lub usuń je z kolejności tabulacji i ignoruj dane wejściowe), zamiast ustawiaćdisabledna hoście – ustawienie atrybutu hosta w wywołaniu zwrotnym uniemożliwia ponowne włączenie, gdy element nadrzędny<fieldset>zostanie ponownie włączony, a host już automatycznie pasuje do:disabled. - Postępuj zgodnie z konwencjami platformy dotyczącymi wysyłanych zdarzeń i preferuj wbudowane zdarzenia
inputichangezamiast niestandardowych.inputjest wywoływane, gdy wartość zmienia się w bezpośrednim wyniku działania użytkownika (wpisywanie, przeciąganie suwaka);changejest wywoływane raz na strumień zmian, gdy użytkownik zatwierdza zmianę (zwolnienie suwaka, rozmycie pola). Utwórz je odpowiednio za pomocąInputEventiEvent.
Strategie zastępcze
Zanim zaczniesz korzystać z funkcji, sprawdź, czy jest obsługiwana przez static formAssociated: 'attachInternals' in HTMLElement.prototype && 'setFormValue' in ElementInternals.prototype. Jeśli jest niedostępny, użyj ukrytego wizualnie natywnego elementu <input> zsynchronizowanego z wartością elementu sterującego, aby formularz nadal był przesyłany – to jedyny przypadek, w którym wzorzec ukrytego pola wejściowego jest uzasadniony.