ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Lit 如何用 @lit-labs/forms 的 FormControl 混合基类构建表单关联自定义元素

Lit 如何用 @lit-labs/forms 的 FormControl 混合基类构建表单关联自定义元素 Lit 如何用 lit-labs/forms 的 FormControl 混合基类构建表单关联自定义元素【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit如果你正在用 Lit 写自定义元素并希望它能像原生input一样参与表单提交、约束校验和浏览器表单状态恢复前进/后退时恢复填写内容那么lit-labs/forms的FormControlmixin 就是为此设计的。它会接管ElementInternals的接入设置 ARIA role、表单值、禁用状态等让你只关心渲染和业务逻辑。本文基于仓库中 packages/labs/forms/README.md 和 源码实现 说明如何完成一个表单关联元素以及如何用FormData、checkValidity()等真实方式验证它工作正常。需要先说明一点适用边界该包位于packages/labs/下当前版本为0.1.0见 package.json属于 Lit Labs 包README 明确警告其may receive breaking changes or stop being supported在生产环境使用前应阅读 Lit Labs 相关文档。安装在项目目录内执行npm install lit-labs/forms该包依赖lit/reactive-element^2.0.0开发示例使用lit^3.0.0。装饰器写法基于标准装饰器包的主构建 tsconfig.json 中experimentalDecorators为falselib包含ESNext.Decorators因此字段需要声明为accessor。仓库为实验性装饰器单独维护了 测试配置在实验性装饰器模式下formValue必须用在 accessor 字段上否则源码会抛出formValue must be used on an accessor错误见 form-associated.ts。用 FormControl 定义第一个表单元素README 给出的主路径示例如下一个包装原生input的simple-inputimport {LitElement, html} from lit; import {customElement} from lit/decorators.js; import {FormControl, formValue} from lit-labs/forms; customElement(simple-input) export class SimpleInput extends FormControl(LitElement) { formValue() accessor value ; override render() { return html input .value${this.value} input${(e: Event) (this.value (e.target as HTMLInputElement).value)} / ; } }关键点是两处FormControl(LitElement)mixin 返回一个继承自LitElement的新基类。README 建议大多数开发者使用FormControl而非更底层的FormAssociated前者会额外提供表单控件的惯用 API只有需要完全自定义 API 时才直接用FormAssociated。formValue()标记哪个字段是表单值。每当该字段变化mixin 会自动调用ElementInternals.setFormValue()并向浏览器注册值变化。在form中使用该元素时通过name属性提供提交用的键名这一点与仓库测试一致测试中即以namefoo的方式渲染在form内见 form-associated_test.tsform simple-input nameusername/simple-input /formmixin 提供的公共 APIFormControl添加的字段和方法模仿原生表单控件来自 README 及 form-control.ts成员说明form只读返回关联的表单元素labels只读返回关联的label节点name读写反映name属性disabled读写反映disabled属性validity只读返回元素的ValidityStatevalidationMessage只读校验失败时会展示的报错信息willValidate只读提交时该元素是否会被校验如 disabled 元素不会checkValidity()无效时返回false并触发invalid事件reportValidity()同checkValidity()但还会向用户展示校验信息一个容易踩坑的地方disabled只反映元素自身的disabled属性。当元素被父级fieldset disabled禁用时该属性返回false但元素仍匹配:disabled伪类。此时应使用包提供的isDisabled()工具函数即element.matches(:disabled)它同时覆盖两种情况仓库测试 form-control_test.ts 中对 fieldset 场景有完整断言。表单值不是字符串时converterformValue()的字段默认类型必须是string | File | FormData | null。如果元素内部使用其他类型例如数值传入自定义 converterformValue({ converter: { toFormValue(value: number) { return String(value); }, fromFormValue(value: string) { return Number(value); }, }, }) accessor value 23;toFormValue在注册到浏览器前把内部值转成表单值fromFormValue在浏览器恢复表单状态时把恢复值转回内部类型。校验实现 _getValidity()FormAssociated的行为中包括当表单值变化时调用元素自定义的_getValidity()方法并用其结果更新internals.setValidity()。返回结构为{flags, message?, anchor?}其中flags是PartialOmitValidityState, valid见 form-associated.ts。仓库测试中的用法示例override _getValidity() { if (this.value invalid) { return { flags: {customError: true}, message: Invalid value, }; } return {flags: {}}; }如果状态变化会影响有效性但表单值本身没有变化应调用 mixin 提供的_validate()方法它调用_getValidity()后设置 validity 并返回internals.checkValidity()的结果。源码注释还建议在构造函数中调用_validate()以设置初始有效性状态测试类InitiallyInvalidElement正是这样做的——构造函数中this._validate()之后checkValidity()返回false。表单状态与重置表单状态form state是浏览器随表单值一起存储的额外数据值提交给服务器状态则用于用户前进/后退或浏览器会话恢复时还原界面。mixin 的formStateRestoreCallback()会区分restore浏览器恢复状态可拿到之前传给setFormValue的第二个参数和autocomplete自动填充直接更新值两种模式。提供状态有三种写法class CustomStateElement extends FormAssociated(LitElement) { formValue() accessor value bar; formState() property() accessor count 0; formStateGetter() // ts-expect-error #getFormState is called dynamically #getFormState() { return this.value # this.count; } formStateSetter() // ts-expect-error #setFormState is called dynamically #setFormState(state: string) { const [value, count] state.split(#); this.value value; this.count Number(count); } }formState()标记字段作为表单状态的一部分其值会包含在传给internals.setFormValue()的状态里。formStateGetter()/formStateSetter()用于更复杂的序列化/反序列化逻辑。README 提示 TypeScript 会抱怨私有 getter 未被调用需要ts-expect-error注释抑制。表单重置方面mixin 实现了formResetCallback()没有显式默认值时恢复元素构造时的初始值也可以通过formDefaultValue()标记一个字段作为重置目标测试中DefaultElement设置了.default${foo}form.reset()后FormData中的值变为foo。如果元素需要自定义 ARIA role可在类上声明静态role属性mixin 会在构造时把它写入internals.role测试用例CustomRoleElement使用static override role button。验证元素是否工作正常仓库测试form-associated_test.ts、form-control_test.ts使用的判断方式可以直接作为你自己的验证手段值已注册到表单渲染元素到form并设置.value后执行new FormData(form)断言formData.get(foo)等于预期值。测试中元素.value${bar}、namefoo时formData.get(foo)返回bar。converter 场景下内部值123会被提交为字符串123而el.value仍是数字123。校验生效设置有效值后el.checkValidity()为true把值改为invalid后变为false触发invalid事件。重置行为form.reset()后重新读取FormData值回到初始值测试中bar重置为有formDefaultValue时重置为该默认值。name 属性反映el.name bar并等待el.updateComplete后el.getAttribute(name)为bar。状态恢复测试通过直接调用formStateRestoreCallback(state, mode)模拟浏览器行为。restore模式配合formStateSetter时bar#0会被拆回value bar、count 0autocomplete模式只更新值不改动状态字段。这些断言跑在 mocha web-test-runner 环境里test:dev/test:prod脚本配置见 package.json可以在你自己的测试中照搬同样的检查逻辑。限制与边界该包是 Labs 包0.1.0设计可能在收集反馈阶段发生破坏性变更README 要求生产使用前阅读 Lit Labs 文档。formValue/formState只能用于 accessor 字段且formValue字段类型默认为string | File | FormData | null其他类型必须提供 converter。disabled属性不覆盖 fieldset 继承禁用判断禁用请用isDisabled()。私有状态 getter/setter 需要ts-expect-error注释README 注明该写法未来可能变化。完成上述步骤后你的元素就具备了与原生控件一致的表单行为值随表单提交、约束校验触发invalid事件、form.reset()恢复初始值、浏览器恢复时还原状态。若需要继续深入可以阅读 form-associated.ts 中FormAssociated各回调formResetCallback、formStateRestoreCallback、formDisabledCallback的实现注释。【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表