HTML Forms and Form Elements


Overview

<form> 定义了一个HTML表单,用于收集用户输入。是用户操作网页与服务器之间交互的主要方式之一。

表单包含 form element,由不同类型的输入元素组成,可以是 input elements(是最重要的表单元素,将在专门的章节写),多选框,单选框,提交按钮等。

The action Attribute

该特性定义了当表单被提交后要执行的动作。通常表单被提交到服务器端的一个带有处理脚本的网页上(称为form-handler)。要提交表单,通常使用一个 submit 按钮。

如果该特性 omitted 缺省,则动作 is set to the current page。

The method Attribute

该特性指定了在提交表单时使用的 HTTP 的方法 (GET or POST),默认是 GET

<form action="action_page.php" method="GET">

什么时候使用 GET 方法呢?

If the form submission is passive (如:搜索引擎查询), 且 without sensitive information.

使用 GET 方法,表单的数据将会在URL上可见。

 action_page.php?firstname=Mickey&lastname=Mouse

这种方适合小量数据提交。

Size limitation is set in your browser(不同浏览器max length不同,2KB-8KB)。

什么时候用 POST 方法呢?

如果需要更新 database 数据,或者包含敏感信息(如:password),POST 方法较为安全。提交的数据在地址栏里不可见。

再看 GET、POST 区别

GET 只接受 ASCII 字符(参看 HTML-Entities-Charset-URL-Encode 章节),为什么呢?因为 GET 从 URL 的 query string 里获取参数,而 URL 是 HTTP 的一个首部,一定是 ASCII 字符的。如果 GET 请求中包含非 ASCII 字符,在发送请求前使用 URL 编码方法对其转码。

POST 不限制,因为数据是 HTTP 的实体,且使用 MIME(Multipurpose Internet Mail Extensions 多用途互联网邮件扩展)可传输非 ASCII 字符。

The name Attribute

为了正确地提交数据,表单里每一个 输入域都必须包含 name 特性。

注意:没有设定 name 特性的 input field 的值将不被提交

Grouping Form Data

使用 <fieldset> 元素将表单里相关的数据分组,and create a border around the elements。使用 <legend> 元素为前者定义一个 caption 说明文字标题。

表单 <form>元素上可使用的特性还有:

  • accept-charset, 设置提交表单的字符集,默认 page charset
  • autocomplete, 设置是否让浏览器自动填充表单,默认 on
  • enctype, 设置提交数据的编码方式,默认 url-encoded
  • name, 用来身份识别表单,比如DOM操作里 document.forms['formName'] 可以得到 name 特性值为 formName 的 <form> 元素
  • novalidate, 设置浏览器不要确认表单(初始化表单是没有通过验证的)

The <select> Element (Drop down list)

该元素定义了一个下拉菜单:

<select>
  <optgroup label="Swedish Cars">
    <option value="volvo">Volvo</option>
    <option value="saab">Saab</option>
  </optgroup>
  <optgroup label="German Cars">
    <option value="mercedes">Mercedes</option>
    <option value="audi">Audi</option>
  </optgroup>
</select>
Options 分组: 指定默认被选值:
自定义默认显示文本(而不是某个 Option 文本):


通常 <select> 显示的文本是第一个选项的文本。可以通过在指定的 <option> 元素上添加 selected 特性,让它作为默认被选项。

与之相关的还有 <optgroup> 元素,用来把下拉列表里相关的 options 分组到一起。

Multiple 属性

设置 multiple 属性,可以同时选择多个选项。方式:鼠标选中一个选项,按住 ctrl 键再点击其他选项。

The <textarea> Element

该元素定义了一个 multi-line 多行文本输入区域。

<textarea name="message" rows="10" cols="30">
The cat was playing in the garden.
</textarea>

The size of a text area can be specified by the cols and rows attributes, or even better; through CSS’ height and width properties.

The <button> Element

该元素定义了一个可以点击的按钮。

<button type="button">Click me!</button>

该元素的内容可以是文字或图片,有别与使用 <input> 元素创建的按钮

Tips: 记住指定该元素的 type 特性(buttonresetsubmit),因为不同的浏览器针对 <button> 元素使用不同的默认类型。如果你想点击按钮执行特定脚本,而又没有指定它的类型是 button,谷歌浏览器会当作表单 submit 处理。

HTML5 <datalist> Element

该元素为传统的 <input> 单行输入区域元素提供了一列 pre-defined options,方便用户从下拉列表里选择其中一个作为输入数据。用户仍可以在输入框中键入自己想要的值,区别与 <select> 元素。

<input list="browsers">
<datalist id="browsers">
  <option value="Internet Explorer">
  <option value="Firefox">
  <option value="Chrome">
  <option value="Opera">
  <option value="Safari">
</datalist>

注意:

  • IE9 之前版本目前不支持这个元素
  • <input>list 特性值必须指向 <datalist>id 特性(保持一致)。

HTML5 <output> Element

该元素显示一个运算的结果,就像被一段脚本执行。

<form action="action_page.asp" oninput="x.value=parseInt(a.value)+parseInt(b.value)">
  0
  <input type="range"  id="a" name="a" value="50">
  100 +
  <input type="number" id="b" name="b" value="50">
  =
  <output name="x" for="a b"></output>
  <input type="submit">
</form>

针对像 range 这样的控件(改变 range 的值,并没有显示效果)可像下面这样用:

<label for="age">Age</label>
<input id="age" type="range" min="18" max="120" value="18" onchange="ageDisplay.value=value">
<output id="ageDisplay>18</output>

Bonus

如何用表单发送email,点击提交,弹出默认邮件客户端,各个定义了 name 特性的输入域的值,将被自动写入邮件内容区域。

<form action="MAILTO:someone@example.com" method="post" enctype="text/plain">
  Name:<br>
  <input type="text" name="name" value="your name"><br>
  E-mail:<br>
  <input type="text" name="mail" value="your email"><br>
  Comment:<br>
  <input type="text" name="comment" value="your comment" size="50"><br>
  <input type="submit" value="Send">
  <input type="reset" value="Reset">
</form>

Best Practise

  1. 当表单中只有唯一的input输入区域,Enter 键盘事件(keycode为13)将自动提交表单
  2. 提交方法为 post、patch 等,设置禁止连续点击按钮效果
  3. 用户手动输入的值要做 trim 处理,去掉首尾的空格
  4. 指定表单里某个输入域获取光标焦点 form['myName'].focus(),采用的是指定元素获得焦点的方法 HTMLElement.focus()
  5. 输入框的 input 事件实时反应输入值,而 change 事件只有在光标再次失去焦点时才反应输入值
  6. 非 input 元素如果想触发 focus 事件,必须指定 tabindex 属性,即该元素支持使用 keyboard 进行切换
  7. 横向表单:采用label、input为一个form-group(通过 col-* 指定 width)。单行表单:label宽不固定;多行表单:label和输入框分行显示
  8. 表单提交时,判断输入项是否有error并拦截(通过标识或状态,避免重复判断),因为用户可能不改错直接提交
  9. 键盘事件只能由 input、textarea,等任何拥有 contentEditable 属性,或者 tabindex=’-1’ 的元素
  10. 针对编辑复杂数据,建议一个 field 修改完,失焦即提交server保存

submit Event

最近被一个form提交的问题困扰了1、2个小时,希望的效果是拦截表单 type 为 submit 元素触发的默认form提交行为。

经过验证,得出以下结论:

  1. 函数绑定写在form后面
  2. 以下4种方式都可以
  3. 执行顺序:3-》2-》4,且当这三个函数执行时,1不执行
<html>
  <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
  <body>
    <form id="myform" action="" onsubmit="return myFunction()">
      Enter name: <input type="text" name="fname">
      <input type="submit" value="Submit">
    </form>
    <script>
      function myFunction() {
        alert("1 The form was submitted");
        return false
      }
      function myFunction2() {
        alert("2 The form was submitted");
        return false
      }
      function myFunction3() {
        alert("3 The form was submitted");
        return false
      }
      function myFunction4() {
        alert("4 The form was submitted");
        return false
      }
      // $('#myform').on('submit', myFunction2);
      // document.getElementById('myform').onsubmit = myFunction3
      // document.getElementById('myform').addEventListener("submit", myFunction4);
    </script>
  </body>
</html>

iOS Safari 搜索框唤起键盘确认按键显示为“搜索”

<form action="/" method="get">
  <input type="search"/>
</form>
  1. input 元素类型为 “search”
  2. 隐藏浏览器默认样式(如:输入框里显示搜索icon),设置 input 样式 -webkit-appearance: none;
  3. input 元素要包含在 form 元素内,且 form 要有 actionmethod 属性

其他:

  • 页面首次渲染完时,通过 js focus 到输入框没有效果,这是 Safari 设计如此。切换应用重新回到浏览器页面自动 focus 可生效
  • 隐藏 Chrome 浏览器默认 cancel 按钮样式,设置如下:

      input[type="search"]::-webkit-search-cancel-button{display: none;}
    

网站接入 Google search

<form action="https://www.google.com/search" method="get">
  <input type="text" name="q" placeholder="使用 Google 搜索">
  <button type="submit">搜索</button>
</form>

获取表单提交的数据

FormData 是 HTML5 新增的接口,可以模拟表单数据,向服务器上传数据。不仅支持字符串传输,还支持文件的二进制传输。可用于视频、图片、音频的上传。

new FormData() 创建的对象会自动将 form 中的表单值包含进去,文件内容会被编码之后包含进去。注意:所有的输入元素都需要有 name 属性,否则无法访问到值。

var formData = new FormData(document.getElementById("myForm"));
var data = Objec.fromEntries(formData.entries());

FormData.entries() 返回一个包含 FormData 里所有键值对的 iterator。浏览器 console 直接打印是 {}Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。 Object.fromEntries() 方法是 Object.entries() 的逆操作,用于将一个键值对数组转为对象。