利用 HTML 的 form 属性安排表单控件的位置

最近学会了 HTML 的 form 属性的使用方式,在此分享。

需求

应用有这样一个页面:

无标题-2023-08-30-1536.png

需求是提交按钮、主体字段、次要字段放在布局的三个位置,点击保存按钮的时候,主体字段和次要字段一起提交。

原始的想法是用一个大的 <form> 标签包含整个页面,实现如下:

<form action="...">
  <nav>
    <button type="submit">Save</button>
  </nav>
  <main>
    <input type="text" name="title">
    <textarea name="content">
  </main>
  <aside>
    <input type="text" name="tags">
  </aside>
</form>

如果页面只有一个表单,那这个实现没问题。如果有其他小的表单,例如发布文章、删除文章等,就会遇到 form 不能嵌套的问题。

一种解决思路是使用前端 JavaScript 提交,那么能不能通过 HTML 原生功能实现呢?

解决

经过搜索我发现 HTML 原生控件有个 form 属性可以做这件事。它的用法是:

<form id="some-form"></form>

<input form="some-form">

即使 <input><form> 的外部,也可以通过 form 属性把表单和控件关联起来。在表单提交的时候,外部的 <input> 也会作为表单的一部分一起提交。

所以我把上面的代码修改为:

<nav>
  <button type="submit" form="editor-form">Save</button>
</nav>
<main>
  <form id="editor-form" action="...">
    <input type="text" name="title">
    <textarea name="content">
  </form>
</main>
<aside>
  <input type="text" name="tags" form="editor-form">
</aside>

现在编辑器的表单只包含主要部分,次要内容都是通过 form 属性关联。这样页面也可以放下其他表单而不用担心嵌套。

其他

虽然 form 属性可以把表单和外部控件关联起来,但在 DOM 树上外部控件不是 form 的子节点,如果之前有前端逻辑依赖于元素的父子关系,或者依赖事件冒泡,那么这部分逻辑会需要改写。例如:

// 不可用
const form = input.closest("form")

// 可用
const form = input.form

如果你使用 Rails 的 ActiveStorage,那么内置 helper 的 direct_upload: ture 不可用,因为它依赖于 form.querySelector("input"),需要另外处理。

0
所有评论 0
Avatar
@Rei
Ruby 程序员,Ruby China 管理员,GeekNote 创建者。