使用ElementInternals创建自定义表单控件
长期以来,开发者一直渴望对表单元素拥有更多控制权。虽然这说法略显夸张,但创建或自定义表单组件多年来一直是前端网页开发的圣杯。
自定义元素(例如 <my-custom-element></my-custom-element>
)最强大的功能之一,自 Google Chrome 77 版本起已悄然问世,并逐步应用于其他浏览器。ElementInternals 标准是一套功能强大的功能集,其名称却十分低调。其功能包括参与表单以及围绕辅助功能控件的 API。
本文将探讨如何创建自定义表单控件,集成约束验证,介绍内部辅助功能的基础知识,并展示如何将这些功能结合起来创建高度可移植的宏表单控件。
让我们从创建一个与我们的设计系统匹配的简单自定义元素开始。我们的元素将把所有样式保存在 shadow DOM 中,并确保一些基本的辅助功能。我们将使用来自 Google Polymer 团队的出色 LitElement 库作为我们的代码示例,虽然您绝对不需要它,但它确实为编写自定义元素提供了很好的抽象。
在这个示例中,我们创建了一个 <rad-input></rad-input>
,它具有一些基本设计。我们还在表单中添加了第二个输入,这是一个普通的 HTML 输入,并添加了默认值(因此您可以直接按提交并查看其工作方式)。
当我们单击提交按钮时,会发生几件事。首先,调用提交事件的 preventDefault
方法,在本例中,是为了确保我们的页面不会重新加载。之后,我们创建一个 FormData 对象,它使我们可以访问有关表单的信息,我们用它来构造一个 JSON 字符串并将其附加到 <output></output>
元素。但是,请注意,添加到我们的输出中的唯一值来自名为“basic”的元素。
这是因为我们的元素还不知道如何与表单交互,所以让我们使用 ElementInternals 实例设置我们的 <rad-input></rad-input>
,以帮助它名副其实。首先,我们需要在元素的构造函数中调用我们的方法的 attachInternals
方法,我们还将把 ElementInternals polyfill 导入到我们的页面中,以便与尚不支持该规范的浏览器一起使用。
attachInternals
方法返回一个新的元素内部实例,其中包含一些我们可以在我们的方法中使用的新 API。为了让我们的元素能够利用这些 API,我们需要添加一个返回 true
的静态 formAssociated
getter。
class RadInput extends LitElement { static get formAssociated() { return true; } constructor() { super(); this.internals = this.attachInternals(); } }
让我们来看看元素的 internals
属性中的一些 API:
-
setFormValue(value: string|FormData|File, state?: any): void
— 此方法将在存在父表单的情况下设置元素在其父表单上的值。如果值为 null,则元素将不参与表单提交过程。 -
form
— 如果存在,则为元素的父表单的引用。 -
setValidity(flags: Partial<validitystate>, message?: string, anchor?: HTMLElement): void</validitystate>
—setValidity
方法将帮助控制元素在表单中的有效性状态。如果表单无效,则必须存在验证消息。 -
willValidate
— 如果在提交表单时将评估元素,则为 true。 -
validity
— 一个有效性对象,与附加到HTMLInputElement.prototype.validity
的 API 和语义匹配。 -
validationMessage
— 如果使用setValidity
将控件设置为无效,则这是描述错误的消息。 -
checkValidity
— 如果元素有效,则返回 true,否则返回 false 并触发元素上的无效事件。 -
reportValidity
— 与checkValidity
相同,如果事件未取消,则会向用户报告问题。 -
labels
— 使用label[for]
属性标记此元素的元素列表。 - 其他一些用于在元素上设置 aria 信息的控件。
设置自定义元素的值
让我们修改我们的 <rad-input></rad-input>
以利用其中一些 API:
在这里,我们修改了元素的 _onInput
方法以包含对 this.internals.setFormValue
的调用。这告诉表单我们的元素想要使用其给定的名称(在我们的 HTML 中设置为属性)在表单中注册一个值。我们还添加了一个 firstUpdated
方法(在不使用 LitElement 时与 connectedCallback
类似),该方法在元素完成渲染时将元素的值设置为空字符串。这是为了确保我们的元素始终具有表单的值(虽然不是必需的,但您可以通过传入 null 值来将元素从表单中排除)。
现在,当我们向输入添加值并提交表单时,我们将在我们的 <output></output>
元素中看到一个 radInput
值。我们还可以看到我们的元素已添加到 HTMLFormElement
的 radInput
属性中。但是,您可能已经注意到的一件事是,尽管我们的元素没有值,它仍然允许表单提交。接下来,让我们向我们的元素添加一些验证。
添加约束验证
为了设置字段的验证,我们需要稍微修改一下元素,以便使用元素内部对象上的 setValidity
方法。此方法将接受三个参数(如果元素无效,则仅需要第二个参数,第三个参数始终是可选的)。第一个参数是部分 ValidityState
对象。如果任何标志设置为 true,则控件将被标记为无效。如果内置有效性键之一不满足您的需求,则可以使用通用的 customError
键。最后,如果控件有效,我们将传入一个对象字面量 ({}) 来重置控件的有效性。
第二个参数是控件的有效性消息。如果控件无效,则需要此参数,如果控件有效,则不允许此参数。第三个参数是一个可选的验证目标,如果表单提交无效或调用 reportValidity
,则它将控制用户的焦点。
我们将向我们的 <rad-input></rad-input>
引入一个新方法来处理此逻辑:
_manageRequired() { const { value } = this; const input = this.shadowRoot.querySelector('input'); if (value === '' && this.required) { this.internals.setValidity({ valueMissing: true }, 'This field is required', input); } else { this.internals.setValidity({}); } }
此函数获取控件的值和输入。如果值等于空字符串并且元素被标记为必需,我们将调用 internals.setValidity
并切换控件的有效性。现在我们需要做的就是在我们的 firstUpdated
和 _onInput
方法中调用此方法,我们就可以向我们的元素添加一些基本验证了。
在未向我们的 <rad-input></rad-input>
输入值之前单击提交按钮,现在将在支持 ElementInternals 规范的浏览器中显示错误消息。不幸的是,polyfill 仍然不支持显示验证错误,因为在不支持的浏览器中没有可靠的方法来触发内置的验证弹出窗口。
我们还通过使用我们的 internals
对象向我们的示例添加了一些基本的辅助功能信息。我们向元素添加了一个附加属性 _required
,它将充当 this.required
的代理以及 required
的 getter/setter。
get required() { return this._required; } set required(isRequired) { this._required = isRequired; this.internals.ariaRequired = isRequired; }
通过将 required
属性传递给 internals.ariaRequired
,我们正在提醒屏幕阅读器我们的元素当前需要一个值。在 polyfill 中,这是通过添加 aria-required
属性来完成的;但是,在支持的浏览器中,不会将属性添加到元素中,因为该属性是元素固有的。
创建微型表单
现在我们已经有了一个符合我们设计系统的有效输入,我们可能想要开始将我们的元素组合成可以在多个应用程序中重复使用的模式。ElementInternals 最引人注目的功能之一是 setFormValue
方法不仅可以采用字符串和文件数据,还可以采用 FormData 对象。因此,假设我们想要创建一个可能在多个组织中使用的通用地址表单,我们可以使用我们新创建的元素轻松做到这一点。
在这个示例中,我们在元素的 shadow root 内创建了一个表单,我们在其中组合了四个 <rad-input></rad-input>
元素来创建一个地址表单。这次我们没有使用字符串调用 setFormValue
,而是选择传递表单的整个值。结果,我们的元素将其子表单内每个单独元素的值传递到外部表单。
向此表单添加约束验证将是一个相当简单的过程,提供额外的样式、行为和内容插槽也是如此。使用这些较新的 API 最终允许开发人员在自定义元素中释放大量潜力,并最终让我们可以自由控制用户体验。
以上是使用ElementInternals创建自定义表单控件的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

在本周的平台新闻综述中,Chrome引入了一个用于加载的新属性,Web开发人员的可访问性规范以及BBC Move

有很多分析平台可帮助您跟踪网站上的访问者和使用数据。也许最著名的是Google Analytics(广泛使用)
