برای نمایش مقدار کنترل سفارشی در فرم، به <input> پنهان برنگردید. از عناصر سفارشی مرتبط با فرم (FACE) استفاده کنید: با formAssociated و ElementInternals، عنصر مقدار خودش را ارسال میکند، در اعتبارسنجی شرکت میکند، و وضعیت فرم را بهصورت بومی منعکس میکند.
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);
نکات کلیدی:
static formAssociated = trueاجباری است؛ این روشهای مربوط به فرمElementInternalsو چرخه حیاتformXxxCallbackرا باز میکند.setFormValue(value)چیزی است که ارسال میشود و به ورودی پنهان نیاز ندارد. برای کنترلهای چندمقداری،FormDataرا ارسال کنید.setValidity(flags, message, anchor)با اعتبارسنجی محدودیت بومی ادغام میشود: فرم درصورت نامعتبر بودن ارسال نمیشود،:invalid/:validاعمال میشود، و عنصر لنگر در گزارش فوکوس دریافت میکند. برای پاک کردن، باsetValidity({})تماس بگیرید. کلاسهای کاذب:user-valid/:user-invalidتعاملآگاه بهطور یکسان برای عناصر مرتبط با فرم در مرورگرها متصل نشدهاند — قبلاز تکیه بر آنها، پشتیبانی را تأیید کنید و فرض نکنید که تعامل کاربر را به همان شیوهای که برای کنترلهای بومی انجام میدهند، ردیابی میکنند.formResetCallback،formDisabledCallback، وformStateRestoreCallbackرا پیادهسازی کنید تا عنصر در بازنشانی،fieldset[disabled]، و بازیابی تکمیل خودکار عقب/جلو مانند کنترل بومی رفتار کند. درformDisabledCallback(disabled)، بهجای تنظیمdisabledدر میزبان، کنترلهای داخلی را غیرفعال کنید (یا آنها را از ترتیب برگه بردارید و ورودی را نادیده بگیرید) — تنظیم مشخصه میزبان در بازخوانی مانع از فعالسازی مجدد هنگام فعالسازی مجدد<fieldset>میشود، و میزبان ازقبل بهطور خودکار با:disabledمطابقت دارد.- قراردادهای پلاتفرم را برای رویدادهای ارسالشده دنبال کنید و رویدادهای داخلی
inputوchangeرا به رویدادهای سفارشی ترجیح دهید.inputزمانی فعال میشود که مقدار درنتیجه مستقیم کنش کاربر (تایپ کردن، کشیدن لغزنده) تغییر کند؛changeیکبار در هر جریان تغییرات، زمانی که کاربر کنش را نهایی میکند (رها کردن لغزنده، محو کردن فیلد) فعال میشود. آنها را بهترتیب باInputEventوEventبسازید.
راهبردهای جایگزین
قبلاز تکیه بر آن، با پشتیبانی static formAssociated ویژگی را شناسایی کنید: 'attachInternals' in HTMLElement.prototype && 'setFormValue' in ElementInternals.prototype. جایی که دردسترس نیست، به <input> بومی پنهانشده ازنظر بصری که با مقدار کنترل همگامسازی شده است برگردید تا فرم همچنان ارسال شود — تنها موردی که الگوی ورودی پنهان توجیه میشود.