<input type="reset"> - HTML（超文本标记语言）

<input type="reset">
====================

**`reset`** 类型的 `<input>` 元素将渲染为按钮，且带有默认的 `click` 事件，用于将表单中的所有输入重置为其初始值。

尝试一下
----

**备注：** 你应该尽量避免在表单中包含重置按钮。它们很少具有实用性，事实上更有可能使用户因误点而感到沮丧（通常是在尝试单击提交按钮时）。

|  |  |
| --- | --- |
| **值** | 用做按钮标签的字符串 |
| **事件** | `click` |
| **支持的常用属性** | `type` 和 `value` |
| **IDL 属性** | `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | 无 |

值
-

`<input type="reset">` 元素的 `value` 属性包含一个用做按钮标签的字符串，诸如 `reset` 之类的按钮没有其他值。

### 设置 value 属性

```html
<input type="reset" value="Reset the form" />
```

### 省略 value 属性

如果你未指定 `value`，则会获得一个带有默认标签的按钮（通常为“重置”，但这将根据用户代理而有所不同）：

```html
<input type="reset" />
```

使用重置按钮
------

`<input type="reset">` 按钮用于重置表单。如果要创建自定义按钮，并使用 JavaScript 自定义行为，你需要使用 `<input type="button">`，或者最好使用 ``<button>`` 元素。

### 一个简单的重置按钮

我们将从创建一个简单的重置按钮开始：

```html
<form>
  <div>
    <label for="example">Type in some sample text</label>
    <input id="example" type="text" />
  </div>
  <div>
    <input type="reset" value="Reset the form" />
  </div>
</form>
```

上述代码会渲染成这样：

尝试在文本字段中输入一些文本，然后点击重置按钮。

### 添加重置键盘快捷键

像对 `<input>` 元素所做的那样，向重置按钮添加一个快捷键是非常有意义的，且可以通过 `accesskey` 全局属性来实现。

在这个例子中， `r` 被指定为访问键（需要按下 `r` 键与浏览器或操作系统的特定键相组合；关于这些命令的详细列表请参见 `accesskey`）。

```html
<form>
  <div>
    <label for="example">Type in some sample text</label>
    <input id="example" type="text" />
  </div>
  <div>
    <input type="reset" value="Reset the form" accesskey="r" />
  </div>
</form>
```

上面的示例的问题在于，用户无法知道访问键是什么！事实上，是因为修饰符通常是非标准的，以避免与系统和软件快捷键冲突。在构建网站时，请确保以不干扰网站设计的方式提供此信息（例如，通过提供易于访问的链接来指向有关网站访问键的信息）。向按钮添加提示（也可以使用 `title` 属性），尽管这并不是出于无障碍目的的完善的解决方案。

### 禁用和启用重置按钮

要禁用重置按钮，只需在其上指定 `disabled` 全局属性，如下所示：

```html
<input type="reset" value="Disabled" disabled />
```

你可以在运行时通过简单地将 `disable` 设置为 `true` 或 `false` 来启用和禁用按钮。在 JavaScript 中，使用 `btn.disabled = true` 或 `btn.disabled = false`。

**备注：** 有关启用和禁用按钮的更多概念，请参见 `<input type="button">` 页面。

验证
--

按钮并不参与约束性验证，它们并没有实际的约束价值。

示例
--

我们在上面已经提供了一些简单的示例。实际上关于重置按钮并没有更多的内容了。

规范
--

| Specification |
| --- |
| HTML Standard # reset-button-state-(type=reset) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `<input>` 和 `HTMLInputElement` 实现接口
* 表单和按钮
* HTML 表单
* `<button>` 元素
* 表单控件 CSS 兼容性列表


<input type="week"> - HTML（超文本标记语言）

<input type="week">
===================

`<input>` 类型为 **`week`** 的元素会创建输入字段，以便轻松输入年份以及该年（即第 1 周到第 52 或 53 周）的 ISO 8601 星期数

尝试一下
----

控件的用户界面因浏览器而异；跨浏览器的支持目前受到限制，目前只有 Chrome/Opera 和 Microsoft Edge 支持。在不支持的浏览器中，该控件会优雅降级至与 `<input type="text">` 相同的功能。

在 Chrome/Opera 中，`week` 控件提供了用于填写星期和年的插槽，弹出式日历界面（可以更直观地选择它们）以及“X”按钮以清除控件的值。

![An input reading 'week 01, 2017'. The background of the 2017 is the same blue as the focus ring. There are 3 icons in the input: x or clear, a spinner with small up and down arrows, and a larger down arrow. A calendar is a pop-up below the input set to January 2017. The first column of the calendar is the week: 52, 1, 2, 3, 4, 5. the full month calendar is to the right of that. The row with Week 1 and January 2 to 8 is highlighted. On the same line as the month, there are buttons to move right and left for the next and previous months.](/zh-CN/docs/Web/HTML/Element/input/week/week-control-chrome.png)

Edge 的 `week` 控制更加精细，使用滚动的滚轮打开星期和年的选择器。

![An input reading 'week 01, 2017'. A popup is open below with two columns. The left column has a list of weeks, from week 48 to Week 52, continuing with week 01 to week 05. The right side has years, from 2012 to 2022. Week 01 and 2017 are in the middle, highlighted with a blue background. At the bottom, there is a row with a checkbox and an X; likely buttons.](/zh-CN/docs/Web/HTML/Element/input/week/week-control-edge.png)

|  |  |
| --- | --- |
| **值** | 代表周数和年份的字符串，或为空字符串 |
| **事件** | `change` 和 `input` |
| **支持的常用属性** | `autocomplete`、`list`、`readonly` 和 `step` |
| **IDL 属性** | `value`、`valueAsDate`、`valueAsNumber` 和 `list` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()`、`stepDown()` (en-US) 和 `stepUp()` (en-US) |

值
-

一个字符串代表所输入的星期/年的值。星期字符串中描述了此输入类型使用的日期和时间值的格式。

你可以通过在 `value` 属性中包含一个值来为输入设置默认值，如下所示：

```html
<label for="week">What week would you like to start?</label>
<input id="week" type="week" name="week" value="2017-W01" />
```

要注意的一件事是，显示的格式可能与实际的 `value` 不同，后者始终采用 `yyyy-Www` 格式。当将上述例子中的值提交给服务器时，浏览器可能会将其显示为 `Week 01, 2017`，但是提交的值始终为 `week=2017-W01`。

你还可以使用输入元素的 `value` 属性获取并设置 JavaScript 中的值，例如：

```js
const weekControl = document.querySelector('input[type="week"]');
weekControl.value = "2017-W45";
```

其他属性
----

除了 `<input>` 元素共有的属性外，星期输入还提供以下属性：

### max

接受以上值部分中讨论的字符串格式的按时间最新年份和星期数。如果输入到该元素中的 `value` 超过此值，则元素将无法通过约束验证。如果 `max` 属性的值不是有效的星期字符串，则该元素没有最大值。

此值必须大于或等于 `min` 属性指定的年和星期。

### min

最早接受的年和星期数。如果输入到该元素中的 `value` 小于此值，则该元素将无法通过约束验证。如果 `min` 属性的值不是有效的星期字符串，则输入没有最小值。

该值必须小于或等于 `max` 属性的值。

### readonly

布尔属性值，如果存在，说明此字段不能由用户编辑。然而，其 `value` 值仍然可以通过 JavaScript 代码直接设置 `HTMLInputElement` 的 `value` 属性来改变。

**备注：** 由于只读字段不可以拥有值，`required` 不会对指定了 `readonly` 属性的字段起作用。

### step

`step` 属性指定了值必须满足的粒度，或者是下文描述的特殊值 `any`。值必须满足基础的步进值，才有效。如果指定了 `min` 属性，则由 `min` 属性决定，否则，使用 `value` 属性的值，如果上述两个值都不存在，则提供适当的默认值。

字符串值 `any` 意味着不使用步进值，任意值都可以接受（除其他制约因素如 `min` 或 `max` 之外）。

**备注：** 当用户输入的数据不符合步进配置时，用户代理可能会四舍五入到最近的有效值，当有两个同样接近的选项时，更倾向于正方向的数字。

对于 `week` 输入，`step` 的值以周为单位，比例因子为 604,800,000（因为基础数值以毫秒为单位）。`step` 的默认值为 1，表示 1 周。默认的步进基数是 -259,200,000，这是 1970 年第一周的开始（`"1970-W01"`）。

*目前，尚不清楚当与 `week` 输入一起使用时，`"any"` 的值对 `step` 意味着什么。确定该信息后，将对其进行更新。*

使用星期输入
------

乍看之下，星期输入听起来很方便，因为它们提供了用于选择星期的简单 UI，并且标准化了发送到服务器的数据格式，而与用户的浏览器或区域设置无关。但是，`<input type="week">` 存在问题，因为不能保证所有浏览器都支持该特性。

我们将研究 `<input type="week">` 的基本和更复杂的用法，然后在以后提供有关缓解浏览器支持问题的建议（请参阅处理浏览器支持）。

### 星期的基本用途

`<input type="week">` 的最简单用法涉及基本的 `<input>` 和 `<label>` 元素组合，如下所示：

```html
<form>
  <label for="week">What week would you like to start?</label>
  <input id="week" type="week" name="week" />
</form>
```

### 控制输入框大小

`<input type="week">` 不支持诸如 `size` 的表单大小属性。你必须依靠 CSS 来确定大小。

### 使用 step 属性

你应该能够使用 `step` 属性来更改每次递增或递减的跳转周数，但是这似乎对支持浏览器没有任何影响。

验证方式
----

默认情况下，`<input type="week">` 不会对输入的值应用任何验证。UI 实现通常不允许指定不是有效的星期或年的任何内容，尽管这很有用，但是仍然可以在字段为空的情况下提交，并且你可能希望限制可选择的周数范围。

### 设置最大和最小星期

你可以使用 `min` 和 `max` 属性来限制用户可以选择的有效周数。在以下示例中，我们设置了可供选择的最小值 `Week 01, 2017` 和最大值 `Week 52, 2017`：

```html
<form>
  <label for="week">What week would you like to start?</label>
  <input id="week" type="week" name="week" min="2017-W01" max="2017-W52" />
  <span class="validity"></span>
</form>
```

这是上面示例中使用的 CSS。在这里，我们利用 `:valid` 和 `:invalid` CSS 伪类属性根据当前值是否有效来设置输入的样式。我们必须将图标放在输入旁边的 `<span>` 而不是输入本身上，因为在 Chrome 中，生成的内容位于表单控件内，无法设置样式或显示有效性。

```css
div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

结果是，在支持的浏览器中，2017 年 W01 到 W52 之间只有几周才被视为有效，并且可以选择。

### 使星期值成为必需值

另外，你可以使用 `required` 属性来强制填写星期。因此，如果你尝试提交空白的星期字段，则支持的浏览器将显示错误。

让我们看一个例子；在这里，我们设置了最小和最大星期，并令该字段必填：

```html
<form>
  <div>
    <label for="week">What week would you like to start?</label>
    <input
 id="week"
 type="week"
 name="week"
 min="2017-W01"
 max="2017-W52"
 required />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="Submit form" />
  </div>
</form>
```

如果你尝试提交不带任何值的表单，浏览器将显示错误。现在尝试使用示例：

这是使用不支持该控件的浏览器的屏幕截图：

![The week form control has two dashes where the week number should be. A popup with a yellow warning symbol and a 'Please fill out this field' is emanating from the two dashes, which are highlighted in blue, the same blue as the input's focus ring.](/zh-CN/docs/Web/HTML/Element/input/week/week-validation-chrome.png)

**警告：** HTML 表单验证*不能*代替脚本来确保输入的数据采用正确的格式。对于某人来说，对 HTML 进行调整以使其绕过验证或完全删除验证太容易了，甚至也可以完全绕开 HTML 并将数据直接提交到服务器。如果服务器端代码无法验证其接收到的数据，则在提交格式不正确的（或太大，类型错误……）的数据时，灾难可能会发生。

处理浏览器支持
-------

如上所述，现在使用星期输入的主要问题是浏览器支持：Safari 和 Firefox 在桌面上不支持它，而旧版本的 IE 不支持它。

诸如 Android 和 iOS 之类的移动平台确实很好地利用了这种输入类型，提供了专门的 UI 控件，使在触摸屏环境中选择值变得非常容易。例如，Android 版 Chrome 上的 `week` 选择器如下所示：

![A modal popup. The header reads 'set week'. There are two columns: the left has 36 in the middle at full opacity, with 35 above it and 37 below being semi-opaque. On the right side, 2017 is fully opaque. There are no other options. Three text links or buttons on the bottom include 'clear' on the 'left' and 'cancel' and 'set' on the right.](/zh-CN/docs/Web/HTML/Element/input/week/week-chrome-android.png)

不支持该控件的浏览器会优雅地降级为文本输入，但这在用户界面的一致性（所提供的控件将有所不同）和数据处理方面都产生了问题。

第二个问题是更严重的。如前所述，在输入一个 `week` 的情况下，实际值始终会归一化为 `yyyy-Www` 格式。当浏览器回退至通用文本输入时，没有什么可以指导用户正确格式化输入的格式（这肯定是不直观的）。人们可以通过多种方式来写星期值。例如：

* `Week 1 2017`
* `Jan 2-8 2017`
* `2017-W01`
* 等等。

目前，以跨浏览器方式处理星期/年的最佳方法是让用户在单独的控件中输入星期数和年份（特别是在 `<select>` 元素中，参见下面的示例），或使用 JavaScript 库（例如 jQuery 日期选择器）。

示例
--

在此示例中，我们创建了两组用于选择星期的 UI 元素：使用 `<input type="week">` 创建的原生选择器，以及为不支持 `week` 输入类型的旧版浏览器准备的两个用于选择星期/年的 `<select>` 元素。

HTML 看起来像这样：

```html
<form>
  <div class="nativeWeekPicker">
    <label for="week">What week would you like to start?</label>
    <input
 id="week"
 type="week"
 name="week"
 min="2017-W01"
 max="2018-W52"
 required />
    <span class="validity"></span>
  </div>
  <p class="fallbackLabel">What week would you like to start?</p>
  <div class="fallbackWeekPicker">
    <div>
      <span>
        <label for="week">Week:</label>
        <select id="fallbackWeek" name="week"></select>
      </span>
      <span>
        <label for="year">Year:</label>
        <select id="year" name="year">
          <option value="2017" selected>2017</option>
          <option value="2018">2018</option>
        </select>
      </span>
    </div>
  </div>
</form>
```

星期值由下面的 JavaScript 代码动态生成。
```

div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

该代码中可能有趣的另一部分是特性检测代码。要检测浏览器是否支持 `<input type="week">`，我们创建一个新的 `<input>` 元素，尝试将其 `type` 设置为 `week`，然后立即检查其 `type` 值。不支持的浏览器将返回 `text`，因为 `week` 类型将回退为 `text` 类型。如果不支持，`<input type="week">` 我们将隐藏原生选择器并显示后备选择器 UI（`<select>` 元素）。

```js
// 获取 UI 元素
const nativePicker = document.querySelector(".nativeWeekPicker");
const fallbackPicker = document.querySelector(".fallbackWeekPicker");
const fallbackLabel = document.querySelector(".fallbackLabel");

const yearSelect = document.querySelector("#year");
const weekSelect = document.querySelector("#fallbackWeek");

// 最初，隐藏回退元素
fallbackPicker.style.display = "none";
fallbackLabel.style.display = "none";

// 测试一个新的 date 输入框是否会回退至 text 输入框
const test = document.createElement("input");

try {
  test.type = "week";
} catch (e) {
  console.log(e.description);
}

// 如果回退了，运行 if 代码块中的代码
if (test.type === "text") {
  // 隐藏原生选择器，显示回退元素
  nativePicker.style.display = "none";
  fallbackPicker.style.display = "block";
  fallbackLabel.style.display = "block";

  // 动态生成星期数
  populateWeeks();
}

function populateWeeks() {
  // 生成含有 52 个选择的星期数
  for (let i = 1; i <= 52; i++) {
    const option = document.createElement("option");
    option.textContent = i < 10 ? `0${i}` : i;
    weekSelect.appendChild(option);
  }
}
```

**备注：** 请记住，有些年份有 53 周（请参阅每年的周数)！在开发生产应用程序时，需要考虑到这一点。

规范
--

| Specification |
| --- |
| HTML Standard # week-state-(type=week) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 通用 `<input>` 元素和用于操作该元素的接口 `HTMLInputElement`
* HTML 中使用的日期和时间格式
* `<input type="datetime-local">`、`<input type="date">`、`<input type="time">` 和 `<input type="month">`
* 表单控件 CSS 兼容性列表


<input type="time"> - HTML（超文本标记语言）

<input type="time">
===================

类型为 **`time`** 的 `<input>` 元素，旨在让用户轻松输入时间（小时和分钟，以及可选的秒）。

控件的用户界面因浏览器而异，请查阅浏览器兼容性以了解更多细节。在不支持该类型的浏览器中，它会优雅地降级为 `<input type="text">`。

尝试一下
----

外观
--

### Chrome 和 Opera

在 Chrome 或 Opera 中，`time` 选择控件很简单，根据操作系统区域设置，插槽以 12 或 24 小时格式输入小时和分钟，上下箭头用于递增和递减当前选定的组件。在某些版本中，会提供一个“x”按钮来清除控件的值。

![12 小时制输入格式](/zh-CN/docs/Web/HTML/Element/input/time/chrome_time.png) 12 小时制

![24 小时制输入格式](/zh-CN/docs/Web/HTML/Element/input/time/chrome-time.png) 24 小时制

### Firefox

Firefox 的 `time` 选择控件和 Chrome 非常相似，只是它没有上下箭头。它还基于系统区域设置使用 12 或 24 小时格式输入时间，也提供“X”按钮以清除控件的值。

![Firefox 的 12 小时制输入格式](/zh-CN/docs/Web/HTML/Element/input/time/firefox-time.png) 12 小时制

![Firefox 的 24 小时制输入格式](/zh-CN/docs/Web/HTML/Element/input/time/firefox-time-24.png) 24 小时制

### Edge

Edge 的 `time` 选择控件有点复杂，打开一个小时和分钟的滚动区域。它和 Chrome 一样，基于系统区域设置使用 12 或 24 小时格式输入时间：

![Edge 的 12 小时制输入格式](/zh-CN/docs/Web/HTML/Element/input/time/edge_time.png) 12 小时制

![Edge 的 24 小时制输入格式](/zh-CN/docs/Web/HTML/Element/input/time/edge-time.png) 24 小时制

|  |  |
| --- | --- |
| **值** | 一个代表时间的字符串，或为空字符串。 |
| **事件** | `change` 和
 `input` |
| **支持的常用属性** | `autocomplete`、`list`、`readonly` 和 `step` |
| **IDL 属性** | `value`、`valueAsDate`、`valueAsNumber` 和 `list` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()`、`stepDown()` (en-US) 和 `stepUp()` (en-US) |

值
-

输入到该控件中，包含时间值的一个字符串。

### 设置 value 属性

你可以通过在创建 `<input>` 元素时在 `value` 属性包含一个合法的时间来设置默认值，比如：

```html
<label for="appt-time">选择约定的时间：</label>
<input id="appt-time" type="time" name="appt-time" value="13:30" />
```

### 使用 JavaScript 设置 value

你也可以在 JavaScript 代码中通过 `HTMLInputElement` 的 `value` 属性获取和设置时间的值，比如：

```js
const timeControl = document.querySelector('input[type="time"]');
timeControl.value = "15:30";
```

### 时间格式

`time` 输入框无论输入何种格式的值（这可能由用户的区域设置，或用户代理决定），其 `value` 值总是带有前导零的 24 小时制时间：`hh:mm`。如果输入的时间包含秒数（参见使用 step 属性），则格式总是为 `hh:mm:ss`。你可以在时间字符串中了解到更多有关时间值的格式。

在此示例中，你可以通过输入时间并查看之后如何更改来查看时间输入的值。

首先，看一下 HTML。这很简单，带有我们之前看到的标签和输入控件，但添加了额外的元素 `<p>` 和 `<span>` 用来显示 `time` 控件的值：

```html
<form>
  <label for="startTime">开始时间：</label>
  <input type="time" id="startTime" />
  <p>
    <code>time</code> 输入框的值： <code> "<span id="value">n/a</span>"</code>.
  </p>
</form>
```

这段 JavaScript 代码将代码添加到时间 input 中，以监听 `input` 事件，每次 input 元素的内容发生变化时都会触发该事件。每次事件触发时，`<span>` 元素的内容都会替换为 input 元素的最新值。

```js
const startTime = document.getElementById("startTime");
const valueSpan = document.getElementById("value");

startTime.addEventListener(
  "input",
  () => {
    valueSpan.innerText = startTime.value;
  },
  false,
);
```

当包含 `time` 输入框的表单被提交后，该值在被包含在表单数据中之前被编码。表单的时间输入数据总是以 `name=hh%3Amm` 的形式出现，如果包含秒数，则以 `name=hh%3Amm%3Ass` 的形式出现（参见使用 step 属性）。

其他属性
----

除了 `<input>` 元素共有的属性外，时间输入还提供以下属性：

**备注：** 与许多数据类型不同，时间值有一个**周期域**，意味着数值达到可能的最高值之后，就会绕回起点。例如，指定 `min` 为 `14:00`，`max` 为 `2:00` 意味着允许的时间值从下午 2:00 开始，通过午夜运行到第二天，结束于凌晨 2:00。更多信息请参见本文的使最小值和最大值跨越午夜部分。

### list

列表属性的值是位于同一文档中的 `<datalist>` 元素的 `id`。`<datalist>` 提供了一个预定义的值列表，向用户建议这个输入。列表中任何与 `type` 不兼容的值都不包括在建议选项中。所提供的值是建议，不是要求：用户可以从这个预定义的列表中选择，或者提供不同的值。

### max

一个代表所接受的最迟时间的字符串，使用上述的时间格式指定。如果指定的字符串不是合法的时间表示，则不会设置最大值。

### min

一个代表所接受的最早时间的字符串，使用上述的时间格式指定。如果指定的字符串不是合法的时间表示，则不会设置最小值。

### readonly

如果该布尔属性存在，意味着用户将不能编辑此字段。然而其 `value` 值仍然可以直接通过 JavaScript 代码设置 `HTMLInputElement` 的 `value` 属性改变。

**备注：** 由于只读字段不可以拥有值，`required` 不会对指定了 `readonly` 属性的字段起作用。

### step

`step` 属性指定了值必须满足的粒度，或者是下文描述的特殊值 `any`。值必须满足基础的步进值，才有效。如果指定了 `min` 属性，则由 `min` 属性决定，否则，使用 `value` 属性的值，如果上述两个值都不存在，则提供适当的默认值。

字符串值 `any` 意味着不使用步进值，任意值都可以接受（除其他制约因素如 `min` 或 `max` 之外）。

**备注：** 当用户输入的数据不符合步进配置时，用户代理可能会四舍五入到最近的有效值，当有两个同样接近的选项时，更倾向于正方向的数字。

对于 `time` 输入， `step` 的值以秒为单位，比例因子为 1000（因为基础数值以毫秒为单位）。`step` 的默认值为 60，表示 60 秒（或 1 分钟、60000 毫秒）。

*目前，尚不清楚当与 `time` 输入一起使用时，`any` 的值对 `step` 意味着什么。确定该信息后，将对其进行更新。*

使用 time 输入
----------

### time 的基本用法

`<input type="time">` 的最简单用法涉及基本的 `<input>` 和 `<label>` 元素组合，如下所示：

```html
<form>
  <label for="appt-time">选择约定的时间：</label>
  <input id="appt-time" type="time" name="appt-time" />
</form>
```

### 控制输入框大小

`<input type="time">` 不支持诸如 `size` 的表单大小属性，因为时间字符串的长度总是相同的。你必须依靠 CSS 来确定大小。

### 使用 step 属性

你可以使用 `step` 属性来更改每次递增或递减的时间数（例如，点击箭头控件时时间值会以 10 分钟为单位变动）。

**备注：** 此属性在不同浏览器之间有一些怪异的行为，并不可靠。

它需要一个整数，相当于你要增加的秒数；默认值是 60 秒，或 1 分钟。如果你指定一个小于 60 秒（1 分钟）的值，`time` 输入将显示秒的输入区，同时显示小时和分钟。

```html
<form>
  <label for="appt-time">选择约定的时间：</label>
  <input id="appt-time" type="time" name="appt-time" step="2" />
</form>
```

在 Chrome 和 Opera 这两个为数不多显示上下迭代箭头的浏览器中，点击箭头可以将秒的数值改变两秒，但不会影响小时或分钟。分（或小时）只有在你指定了以秒为单位的分钟（或小时）数时，才能用于步进，比如 120 代表 2 分钟，7200 代表 2 小时）。

在 Firefox 浏览器中，没有箭头，所以没有使用 `step` 值。然而，提供它*会*在分钟部分的旁边增加秒数输入区。

在 Edge 浏览器中，step 值不起作用。

**备注：** 使用 `step` 可能会导致验证工作不正常（如下一节所见）。

验证方式
----

默认情况下，`<input type="time">` 不会对输入的值应用任何验证，用户代理接口会屏蔽所有非时间值的输入，尽管这很有用（假设用户代理完全支持 `time` 输入），但是仍然无法完全依赖于该值的合法性。它仍然允许空字符串（`""`），且可能允许那些看起来像，但并不正确的时间值（如 `25:05`）。

### 设置最大和最小时间

你可以使用 `min` 和 `max` 属性来限制用户可以选择的有效时间。在以下示例中，我们设置了可供选择的最小值 `12:00` 和最大值 `18:00`：

```html
<form>
  <label for="appt-time"> 选择约定的时间（开放时间为 12:00 到 18:00）： </label>
  <input id="appt-time" type="time" name="appt-time" min="12:00" max="18:00" />
  <span class="validity"></span>
</form>
```

下面是上述例子中使用的 CSS。这里我们使用了 `:valid` 和 `:invalid` 这两个 CSS 属性，根据当前值是否有效来为输入添加样式。我们不得不把图标放在 input 旁边的 `<span>` 上，而不是放在 input 框本身，因为在 Chrome 中，生成的内容被放在表单控件里面，无法有效地进行样式设计或显示。

```css
div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

运行的结果可以说明：

* 只有 12:00 和 18:00 之间的时间才会被视为有效，超出这个范围的时间将被表示为无效。
* 根据你使用的浏览器，你可能会发现指定范围之外的时间甚至无法在时间选择器中选择（例如 Edge）。

#### 使最小值和最大值跨越午夜

如果设置的 `min` 属性大于 `max` 属性，有效时间范围将环绕午夜，产生一个跨越午夜的有效时间范围。这个功能不被任何其他 input 类型所支持。虽然这个功能在 HTML 规范中，但它还没有被普遍支持。基于 Chrome 的浏览器从 82 版开始支持该功能，Firefox 在 76 版中加入了该功能。Safari 从 14.1 版开始不支持这个功能。要做好出现这种情况的准备。

```js
const input = document.createElement("input");
input.type = "time";
input.min = "23:00";
input.max = "01:00";
input.value = "23:59";

if (input.validity.valid && input.type === "time") {
  // <input type=time> reversed range supported
} else {
  // <input type=time> reversed range unsupported
}
```

### 使时间成为必需值

此外，你可以使用 `required` 属性来强制填写时间。因此，如果你试图提交一个超出设定范围的时间，或一个空的时间字段，支持的浏览器将显示一个错误。

让我们看一个例子；在这里，我们设置了最小和最大的时间，也使这个字段成为必需的：

```html
<form>
  <div>
    <label for="appt-time">
      选择约定的时间（开放时间为 12:00 到 18:00）：
    </label>
    <input
 id="appt-time"
 type="time"
 name="appt-time"
 min="12:00"
 max="18:00"
 required />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="提交表单" />
  </div>
</form>
```

如果你试图提交含有不完整的时间（或用超出设定范围的时间）的表单，浏览器会显示一个错误。现在试一试下面这个例子。

**警告：** HTML 表单验证并*不能*替代确保输入数据格式正确的脚本。很容易对 HTML 进行调整，使他们能够绕过验证，或完全删除验证。也有可能会完全绕过 HTML 代码，直接将数据提交给你的服务器。如果你的服务器端代码不能验证它所收到的数据，那么当提交的数据格式不当（或数据过大、类型错误等等）时，灾难就会降临。

处理浏览器支持
-------

如前所述，老版本的 Safari 和其他一些不太常见的浏览器并不支持时间输入。总的来说，除此之外，支持情况良好——特别是在移动平台上，这些平台往往有非常好的用户界面来指定时间值。例如，安卓版 Chrome 浏览器上的 `time` 选择器看起来是这样的：

![手机屏幕上显示了以 10:21 为标题的模态对话框。10 是完全不透明的。而 21 则不是。主区域有一个圆圈，数字 112 在一个环里，数字 1324 在一个内圈。数字 10 用一个蓝色的圆圈突出显示。底部的按钮分别用于清除、取消和设置。](/zh-CN/docs/Web/HTML/Element/input/time/chrome-android-time.png)

不支持时间输入的浏览器会优雅地降级为文本输入，但这在用户界面的一致性（呈现的控件会有所不同）和数据处理方面都会产生问题。

第二个问题更为严重；如前所述，`time` 输入的值总是被规范为 `hh:mm` 或 `hh:mm:ss` 的格式。另一方面，对于文本输入，默认情况下，浏览器不知道时间应该是什么格式，而且人们有多种写法，如：

* `3.00 pm`
* `3:00pm`
* `15:00`
* `3 o'clock in the afternoon`
* 等等

一个办法是在你的 `time` 输入上添加 `pattern` 属性。即使 `time` 输入不使用它，`text` 输入回退也会使用。例如，试着在一个不支持时间输入的浏览器中查看下面的演示：

```html
<form>
  <div>
    <label for="appt-time">
      选择约定的时间（开放时间为 12:00 到 18:00）：
    </label>
    <input
 id="appt-time"
 type="time"
 name="appt-time"
 min="12:00"
 max="18:00"
 required
 pattern="[0-9]{2}:[0-9]{2}" />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="提交表单" />
  </div>
</form>
```

如果你尝试提交，你会发现，如果你的输入不符合模式 `nn:nn`（其中 `n` 是 0 到 9 的数字），不支持的浏览器现在会显示一个错误信息（并突出显示输入无效）。当然，这并不能阻止人们输入无效的时间，或者不正确的遵循时间格式的时间。

然后还有一个问题，就是用户不知道到底应该输入什么格式的时间。
```

div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

目前，以跨浏览器方式处理时间的最佳方法是让用户在单独的控件中输入小时和分钟（如果需要，也有秒数）（特别是在 `<select>` 元素中，参见下面的示例），或使用 JavaScript 库（例如 jQuery 日期选择器）。

示例
--

在此示例中，我们创建了两组用于选择时间的接口元素：使用 `<input type="time">` 创建的原生选择器，以及为不支持 `time` 输入类型的旧版浏览器准备的两个用于选择小时/分钟的 `<select>` 元素。

HTML 看起来像这样：

```html
<form>
  <div class="nativeTimePicker">
    <label for="appt-time">
      选择约定的时间（开放时间为 12:00 到 18:00）：
    </label>
    <input
 id="appt-time"
 type="time"
 name="appt-time"
 min="12:00"
 max="18:00"
 required />
    <span class="validity"></span>
  </div>
  <p class="fallbackLabel">选择约定的时间（开放时间为 12:00 到 18:00）：</p>
  <div class="fallbackTimePicker">
    <div>
      <span>
        <label for="hour">时：</label>
        <select id="hour" name="hour"></select>
      </span>
      <span>
        <label for="minute">分：</label>
        <select id="minute" name="minute"></select>
      </span>
    </div>
  </div>
</form>
```

其 `<select>` 元素的小时和分钟值是动态生成的。
```

div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

该代码中可能有趣的另一部分是特性检测代码。要检测浏览器是否支持 `<input type="time">`，我们创建一个新的 `<input>` 元素，尝试将其 `type` 设置为 `time`，然后立即检查其 `type` 值。不支持的浏览器将返回 `text`，因为 `time` 类型将回退为 `text` 类型。如果不支持 `<input type="time">`，我们将隐藏原生选择器并显示后备选择器 UI（`<select>` 元素）。

```js
// 获取 UI 元素
const nativePicker = document.querySelector(".nativeTimePicker");
const fallbackPicker = document.querySelector(".fallbackTimePicker");
const fallbackLabel = document.querySelector(".fallbackLabel");

const hourSelect = document.querySelector("#hour");
const minuteSelect = document.querySelector("#minute");

// 最初，隐藏回退元素
fallbackPicker.style.display = "none";
fallbackLabel.style.display = "none";

// 测试一个新的 time 输入框是否会回退至 text 输入框
const test = document.createElement("input");

try {
  test.type = "time";
} catch (e) {
  console.log(e.description);
}

// 如果回退了，运行 if 代码块中的代码
if (test.type === "text") {
  // 隐藏原生选择器，显示回退元素
  nativePicker.style.display = "none";
  fallbackPicker.style.display = "block";
  fallbackLabel.style.display = "block";

  // 动态生成小时和分钟数
  populateHours();
  populateMinutes();
}

function populateHours() {
  // 生成含有 6 小时开放时间的 <select>
  for (let i = 12; i <= 18; i++) {
    const option = document.createElement("option");
    option.textContent = i;
    hourSelect.appendChild(option);
  }
}

function populateMinutes() {
  // 对每一小时动态生成 60 个代表分钟数的 <select>
  for (let i = 0; i <= 59; i++) {
    const option = document.createElement("option");
    option.textContent = i < 10 ? `0${i}` : i;
    minuteSelect.appendChild(option);
  }
}

// 如果小时数为 18，分钟数必须设置为 00
// 你不可以选择超过 18:00 的时间
function setMinutesToZero() {
  if (hourSelect.value === "18") {
    minuteSelect.value = "00";
  }
}

hourSelect.onchange = setMinutesToZero;
minuteSelect.onchange = setMinutesToZero;
```

规范
--

| Specification |
| --- |
| HTML Standard # time-state-(type=time) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 通用 `<input>` 元素和用于操作该元素的接口 `HTMLInputElement`
* HTML 中使用的日期和时间格式
* 日期时间选择器教程
* `<input type="datetime-local">`、`<input type="date">`、`<input type="week">` 和 `<input type="month">`
* 表单控件 CSS 兼容性列表


<input type="image"> - HTML（超文本标记语言）

<input type="image">
====================

**`image`** 类型的 `<input>` 元素用于创建图形化的提交按钮，即采用图像而非文本形式的提交按钮。

尝试一下
----

值
-

`<input type="image">` 元素不接受 `value` 属性。要显示的图像的路径在 `src` 属性中指定。

额外属性
----

除了所有 `<input>` 元素的共有属性外，`image` 按钮还支持以下属性。

### alt

`alt` 属性提供一个备用字符串，在图像无法加载的情况下作为按钮的标注（由于错误，一个不能或者被设置为不能显示图像的 user agent，或用户正在使用屏幕阅读设备）。如果它被提供，它必须为非空字符串，且适合作为按钮的标签。

例如，如果你有一个按钮，显示一个带有图标和/或图像文本“现在登录”的图片，你也应该设置 `alt` 属性为类似于 `现在登录` 的东西。

**备注：** 虽然 `alt` 属性在技术上是可选的，但是你总应该包含它，以最大限度地提高你的内容的可用性。在功能上，`<input type="image">` 元素的 `alt` 属性与 `<img>` 元素的 `alt` 属性相类似。

### formaction

一个字符串，指示要将数据提交到的 URL。这优先于拥有 `<input>` 的 `<form>` 元素上的 `action` 属性。

该属性也在 `<input type="submit">` 和 `<button>` 元素上可用。

### formenctype

一个字符串，标识在将表单数据提交到服务器时要使用的编码方法。有三个允许的值：

`application/x-www-form-urlencoded`

这是默认值，它将会将表单数据在使用 `encodeURI()` 等算法进行 URL 编码后发送。

`multipart/form-data`

使用 `FormData` API 来管理数据，允许向服务器提交文件。你*必须*使用该编码方式，如果你的表单包含 `type` 为 `file`（`<input type="file">`）的任何 `<input>` 元素。

`text/plain`

纯文本；通常只在调试时有作用，你可以很容易看到要被提交的数据。

如果该属性被指定，`formenctype` 属性的值将会覆盖表单的 `action` 属性。

该属性也在 `<input type="submit">` 和 `<button>` 元素上可用。

### formmethod

一个字符串，指定提交表单数据时使用的 HTTP 方法；该值将会覆盖所属表单上的任何 `method` 属性。允许的值如下：

`get`

以 `formaction` 或 `action` 属性给定的 URL 为前缀构造的一个 URL，在前缀后会附加一个问号（`?`）字符，然后附加表单数据，表单数据按照 `formenctype` 或表单的 `enctype` 属性的描述进行编码。构造的 URL 会通过 HTTP `get` 请求发送到服务器。此方法适用于仅包含 ASCII 字符，且没有副作用的简单表单。这是该属性的默认值。

`post`

表单数据包含在请求的主体（body）中，并使用 HTTP `post` 请求发送到 `formaction` 或 `action` 属性指定的 URL。此方法支持复杂数据和文件附件。

`dialog`

此方法用于指示关闭与该输入元素关联的对话框的一个按钮，其不会传输表单数据。

该属性也在 `<input type="submit">` 和 `<button>` 元素上可用。

### formnovalidate

一个布尔值，如果存在，则指定在提交给服务器之前不应对表单进行验证。这将会覆盖元素所属表单上的 `novalidate` 属性的值。

该属性也在 `<input type="submit">` 和 `<button>` 元素上可用。

### formtarget

一个字符串，指定一个名字或关键词来表示在提交表单后在何处显示响应数据。该字符串必须是一个**浏览上下文**的名字（即一个标签页、窗口，或 `<iframe>`）。在此处指定的值将会覆盖 `<form>` 上拥有该输入的 `target` 属性所给出的任何目标。

除了标签页、窗口或内联框架的实际名字，还有部分特殊关键词可用：

`_self`

将响应加载到与包含表单的浏览上下文相同的浏览上下文中。这将用接收到的数据替换当前文档。如果未指定，这将是默认值。

`_blank`

将响应加载到新的未命名浏览上下文中。这通常是一个与当前文档相同的窗口中的新选项卡，但是可能会因为用户代理的配置而有所不同。

`_parent`

将响应加载到当前浏览上下文的父浏览上下文中。若不存在父浏览上下文，该选项的行为将与 `_self` 相同。

`_top`

将响应加载到顶级浏览上下文中；它是当前浏览上下文的最顶层祖先。如果当前浏览上下文为最顶层上下文，该选项的行为将与 `_self` 相同。

该属性也在 `<input type="submit">` 和 `<button>` 元素上可用。

### height

一个表示绘制 `src` 属性指定图像的高度的数字，以 CSS 像素为单位。

### src

一个字符串，指定将要在提交按钮上显示的图像的 URL。当用户与该图像交互时，输入将会以和其他按钮输入相同的方式被处理。

### width

一个表示绘制图像宽度的数字，以 CSS 像素为单位。

已弃用的属性
------

下列属性是由 HTML 4 为 `image` 输入定义的，但未被所有浏览器实现，并且已被弃用。

### usemap

如果 `usemap` 被指定，它必须是一个图像映射元素的名字。`<map>` 用于定义一个和图像一同使用的图像映射。该用法已被弃用；当你需要使用图像映射时，你应该切换到使用 `<img>` 元素。

示例
--

### 一个登录表单

下面的例子显示和之前相同的按钮，但被包含在了一个典型登录表单的上下文中：

#### HTML

```html
<form>
  <p>登录到你的账户</p>
  <div>
    <label for="userId">用户 ID</label>
    <input type="text" id="userId" name="userId" />
  </div>
  <div>
    <label for="pwd">密码</label>
    <input type="password" id="pwd" name="pwd" />
  </div>
  <div>
    <input
 id="image"
 type="image"
 src="https://raw.githubusercontent.com/mdn/learning-area/master/html/forms/image-type-example/login.png"
 alt="Login"
 width="100" />
  </div>
</form>
```

#### CSS

下面是一些简单的 CSS 来让这些基本元素排列更整齐：

```css
div {
  margin-bottom: 10px;
}
label {
  display: inline-block;
  width: 70px;
  text-align: right;
  padding-right: 10px;
}
```

### 调整图像的位置和缩放

在这个例子里，我们调整了之前的例子，为图像留出了更多空间，并使用 `object-fit` 和 `object-position` 来调节图像的大小和位置。

#### HTML

```html
<form>
  <p>登录到你的账户</p>
  <div>
    <label for="userId">用户 ID</label>
    <input type="text" id="userId" name="userId" />
  </div>
  <div>
    <label for="pwd">密码</label>
    <input type="password" id="pwd" name="pwd" />
  </div>
  <div>
    <input
 id="image"
 type="image"
 src="https://raw.githubusercontent.com/mdn/learning-area/master/html/forms/image-type-example/login.png"
 alt="Login"
 width="200"
 height="100" />
  </div>
</form>
```

#### CSS

```css
div {
  margin-bottom: 10px;
}
label {
  display: inline-block;
  width: 70px;
  text-align: right;
  padding-right: 10px;
}
#image {
  object-position: right top;
  object-fit: contain;
  background-color: #ddd;
}
```

规范
--

| Specification |
| --- |
| HTML Standard # image-button-state-(type=image) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 实现它的 `<input>` 和 `HTMLInputElement` 接口。
* 在 `<input>` 元素的框架内改变图像的位置和大小：`object-position` 和 `object-fit`
* CSS 属性的兼容性


<input type="datetime-local"> - HTML（超文本标记语言）

<input type="datetime-local">
=============================

`<input>` 元素的 **`datetime-local`** 类型创建让用户便捷输入日期和时间的输入控件，包括“年”、“月”、“日”，以及“时”和“分”。

尝试一下
----

此控件的 UI 因浏览器而异。在不支持的浏览器中，其会优雅地降级为简单的 `<input type="text">` 控件。

该控件旨在表示*本地日期和时间*，不一定是*用户的本地日期和时间*。换句话说，其实现应该允许年、月、日、小时、分钟的任何有效的组合——即使某些组合在用户的本地时区是无效的（例如，夏令时的转换时差）。一部分手机浏览器（特别是 iOS 上的）目前没有正确地实现这一点。

由于 `datetime-local` 类型受限于浏览器支持，并且不同浏览器在输入方法上存在差异，目前最好是使用第三方框架或库来展示，或者实现一个自己的输入控件。另一个方法是拆分为 `date` 和 `time` 输入控件，这两个的支持都比 `datetime-local` 更广泛。

一部分浏览器可能会用一个普通的文本输入元素代替显示，并在输入内容提交到服务器之前验证它们是否是合法的日期/时间格式，但你不可信赖于此行为，因为用户使用的浏览器不可预知的。

|  |  |
| --- | --- |
| **取值** | 一个表示日期和时间的字符串（本地时区）或空值。 |
| **事件** | `change` 和
 `input` |
| **支持的通用属性** | `autocomplete`、`list`、`readonly`
 和 `step` |
| **IDL 属性** | `list`、`value`、`valueAsNumber`。 |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()`、`stepDown()` (en-US)、`stepUp()` (en-US) |

取值
--

一个输入到控件上的表示日期的字符串。本地日期时间字符串中描述了关于此类型的输入控件使用的日期和的输入格式。

你可以将一个包含日期和时间的值放在 `value` 属性中以为控件设置一个默认值，像这样：

```html
<label for="party">输入预订宴会的日期和时间：</label>
<input
 id="party"
 type="datetime-local"
 name="partydate"
 value="2017-06-01T08:30" />
```

需要注意的是：显示的日期和时间的格式与实际 `value` 中的格式不同，显示的日期和时间格式以用户操作系统所的区域设置信息为准，而控件的日期/时间值 `value` 总是 `yyyy-MM-ddThh:mm` 格式。例如，当上例中的值被提供到服务器之后，将会像这样 `partydate=2017-06-01T08:30`。

**备注：** 另外请注意，如果这样的数据以 HTTP `GET` 提交，时间部分的冒号需要编码之后才能放在 URL 参数中，例如 `partydate=2017-06-01T08%3A30`。编码方法请参见 `encodeURI()`。

你也可以在 JavaScript 中使用 `HTMLInputElement` 的 `value` 属性来获取和设置日期的值，例如：

```js
const dateControl = document.querySelector('input[type="datetime-local"]');
dateControl.value = "2017-06-01T08:30";
```

JavaScript 的 `Date` 提供了几种用于将数值类型的日期转换为格式化字符串的方法。例如：`Date.toISOString()` 方法返回 UTC 时区的日期和时间，带有表示该时区的 `Z` 前缀；删除 `Z` 后将可以提供用于 `datetime-local` input 的格式化的值。

额外的属性
-----

除了 `<input>` 元素通用的属性外，datetime-local 输入控件还提供了以下属性。

### max

接受的最晚日期和时间的值。如果 `value` 的值晚于这一时间戳，则该元素不会通过约束验证。如果 `max` 属性的值不是遵循 `YYYY-MM-DDThh:mm` 格式的有效字符串，则该元素没有最大值。

该属性指定的值必须晚于或等于 `min` 属性的值。

### min

接受的最早日期和时间的值。如果早于这一时间戳，则该元素不会通过约束验证。如果 `min` 属性的值不是遵循 `YYYY-MM-DDThh:mm` 格式的有效字符串，则该元素没有最小值。

该属性指定的值必须早于或等于 `max` 属性的值。

### step

`step` 属性是一个数字，用于指定值调整的步长；或使用特殊值 `any`。该属性的描述如下：仅能使用基础的调整步长（若 `min` 已指定，则从其开始；否则使用 `value`；若两者均未提供，则为某一适当的默认值）。

字符串值 `any` 表示没有步长约束，任何的值均可使用（除了其他的约束，如：`min` 和 `max`）。

**备注：** 当用户输入的数据不符合配置的步长限制时，用户代理可能会将其四舍五入到最近的有效值，当有两个差值相等的选项时，优先选择大于当前值的数值。

对于 `datetime-local` 输入控件，`step` 值的单位是秒，最小分度为 1/1000（因为底层的数值以毫秒为单位）。默认的 `step` 值为 60，表示 60 秒（或一分钟、60000 毫秒）。

*目前，关于 `step` 的 `any` 值与 `datetime-local` 输入控件一起使用的意义尚不明确。一旦确定该信息，文档会立即更新。*

使用 datetime-local 输入控件
----------------------

Date/time 输入控件乍看非常实用；它们提供了方便的用户接口来选择日期和时间，并且无论用户端是什么样的本地化设置，都会以标准化数据发送给服务器。但是受限于浏览器的支持，`<input type="datetime-local">` 也有不少问题。

我们先来看看 `<input type="datetime-local">` 基本的和高级的用法，之后在（参见处理浏览器支持）会提供一些减少浏览器兼容问题的建议。

### datetime-local 的基本用法

`<input type="datetime-local">` 最简单的用法是将 `<input>` 和 `<label>` 组合在一起，像下面这样：

```html
<form>
  <label for="party">输入预订宴会的日期和时间：</label>
  <input id="party" type="datetime-local" name="partydate" />
</form>
```

### 设定日期时间的最大值和最小值

你可以使用 `min` 和 `max` 属性来限制用户可选择的日期/时间。在下面的例子中我们设定最小的日期时间 `2017-06-01T08:30` 和最大的日期时间 `2017-06-30T16:30`：

```html
<form>
  <label for="party">输入预订宴会的日期和时间：</label>
  <input
 id="party"
 type="datetime-local"
 name="partydate"
 min="2017-06-01T08:30"
 max="2017-06-30T16:30" />
</form>
```

结果如下：

* 只有“2017 年 6 月”可供选择——只有“日期”部分的值可修改，并且 6 月以外的日期不能被选到日期控件内。
* 视你所使用的浏览器，你或许会发现时间选择控件中特定值以外的时间可能不可选（如 Edge），或是无效（参见校验）但仍可选（如 Chrome）

**备注：** 你可以使用 `step` 属性设置不同值来控制日期每次增减的天数（例如，或许你希望只有星期六可选）。但是，截止到本文档编写之时，好像还没有浏览器实现此功能。

### 控制输入框大小

`<input type="datetime-local">` 并不支持如 `size` 这样的表单大小属性。你可使用 CSS 来控制大小。

### 设置时区

`datetime-local` 控件并没有地方可以设置日期/时间的时区和/或区域属性。在 `datetime` 输入类型上提供过此功能，但这个类型现在已被废弃，也已从标准中移除。这项被移除的主要原因是缺少浏览器的支持，以及出于用户交互/用户体验方法的考量。相比之下，仅使用一个（或多个）控件来设置日期/时间，然后单独在另一控件处理时区，这样更容易一些。

例如，如果你在开发一套系统，某位用户可能已经登录进来，并且已经设置了时区，你可以把时区放在一个 `hidden` 输入控件里。例如：

```html
<input type="hidden" id="timezone" name="timezone" value="-08:00" />
```

另一方面，如果你被要求在用户输入日期时间时提供时区输入，你可以提供给用户一种输入方式，例如 `<select>` 元素：

```html
<select name="timezone" id="timezone">
  <option value="Pacific/Kwajalein">Eniwetok, Kwajalein</option>
  <option value="Pacific/Midway">Midway Island, Samoa</option>
  <option value="Pacific/Honolulu">Hawaii</option>
  <option value="Pacific/Marquesas">Taiohae</option>
  <!-- and so on -->
</select>
```

以上两例中，日期/时间和时区可以独立的数据提交到服务器，之后你需要做的就是把它们保存到服务器数据库恰当的位置。

校验
--

默认情况下 `<input type="datetime-local">` 不对输入内容进行验证。用户交互（UI）的实现通常不允许你输入不是日期/时间的值——这非常有用。但用户也仍会在不填写任何值的情况下提交数据，或者输入一个不无效的日期/时间（如：4 月 32 日）。

你可以使用 `min` 及 `max` 来限制可选择的日期（参见设定日期时间的最大值和最小值），并且使用 `required` 属性使日期/时间为强制的输入项。这样做的结果是，可以使相应的浏览器在你输入一个超出范围的日期或不输入时显示一个错误信息。

让我们来看个例子，这里我们设置日期/时间的最小值和最大值，并且设置该项为必填：

```html
<form>
  <div>
    <label for="party"
 >Choose your preferred party date and time (required, June 1st 8.30am to
      June 30th 4.30pm):</label
 >
    <input
 id="party"
 type="datetime-local"
 name="partydate"
 min="2017-06-01T08:30"
 max="2017-06-30T16:30"
 required />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="Book party!" />
  </div>
</form>
```

如果你试图提交一个不完整的日期（或者日期超出设定范围），浏览器会显示一条错误信息。来试试这个示例：

这里有以上示例的 CSS。在这里我们使用 `:valid` 和 `:invalid` CSS 属性来控制当前值正确和错误的样式。我们需要这两个图标放一个 `<span>` 到输入元素后面，而非使用输入元素本身，因为在 Chrome 下生成的内容会被放在表单控件里面，不能设置样式或显示出来。

```css
div {
  margin-bottom: 10px;
  display: flex;
  align-items: center;
}

label {
  display: inline-block;
  width: 300px;
}

input:invalid + span:after {
  content: "✖";
  padding-left: 5px;
}

input:valid + span:after {
  content: "✓";
  padding-left: 5px;
}
```

**警告：** HTML 表单验证并不能取代脚本校验输入数据是否符合格式要求。有人可以非常容易地修改 HTML 以绕过验证，亦或是完全删除这个元素。同样可能的是，有人可以非常轻易做到完全绕过 HTML 而直接向你的服务器提交数据。如果你服务器代码不对接收到的数据进行校验，灾难性的打击就可能发生在这些错误格式数据提交的时候（或是数据太大，或是格式错误，等等）。

处理浏览器支持
-------

正如前面所提到的，不支持的浏览器会优雅地降级显示为文件输入框，但这在用户界面的一致性方面（呈现的控件不一样），以及数据处理方面造成了问题。

第二个问题是最严重的。正如我们之前提到的，采用 `datetime-local` 输入，实际值总是会被转换成 `yyyy-mm-ddThh:mm` 格式。但换成文本输入框之后，浏览器默认情况下不知道应当输入什么格式的日期，人们有很多不同的书写日期和时间的方式，如：

* `DDMMYYYY`
* `DD/MM/YYYY`
* `MM/DD/YYYY`
* `DD-MM-YYYY`
* `MM-DD-YYYY`
* `MM-DD-YYYY hh:mm`（12 小时制）
* `MM-DD-YYYY HH:mm`（24 小时制）
* 等等

一个变通的方法是放一个 `pattern` 属性在 `datetime-local` 输入元素里。虽然 `datetime-local` 输入控件本身不使用这个属性，但降级显示的文本输入框将会用到。例如，在不支持的浏览器上试一下这个例子：

```html
<form>
  <div>
    <label for="party"
 >Choose your preferred party date and time (required, June 1st 8.30am to
      June 30th 4.30pm):</label
 >
    <input
 id="party"
 type="datetime-local"
 name="partydate"
 min="2017-06-01T08:30"
 max="2017-06-30T16:30"
 pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"
 required />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="Book party!" />
  </div>
  <input type="hidden" id="timezone" name="timezone" value="-08:00" />
</form>
```

你试一下提交数据，如果你输入的内容不满足 `nnnn-nn-nnTnn:nn` 格式（n 为 0 ~ 9 的数字），你会看到浏览器显示一条错误信息（并高亮输入框标记为无效），但这并不能妨碍用户输入无效的日期或是不正确的日期和时间。

然而什么样的用户会去理解这样一个他们要输入的日期和时间格式呢？

我们仍有问题待解决。
```

div {
  margin-bottom: 10px;
}

input:invalid + span {
  position: relative;
}

input:invalid + span:after {
  content: "✖";
  position: absolute;
  right: -18px;
}

input:valid + span {
  position: relative;
}

input:valid + span:after {
  content: "✓";
  position: absolute;
  right: -18px;
}
```

目前处理跨浏览器表单中输入日期的最好办法是让用户分别在不同的控件中输入年、月、日和时间（`<select>` 元素很流行——参见下面的实现），或者使用 JavaScript 库，如 jQuery date picker 及 jQuery timepicker plugin。

Y2K38 问题（通常是服务端）
----------------

JavaScript 使用双精度浮点数来存储日期（数值），这意味着 JavaScript 代码不会遇到 Y2K38 问题，除非使用强制转换为整数或位运算，因为所有 JavaScript 的位运算符都使用 32 位带符号二进制整数补码的形式。

问题出现在服务端：存储大于 2^31 - 1 的日期。要解决这个问题，你必须使用 32 位无符号整数、64 位带符号整数或双精度浮点数来存储所有的日期。如果你的服务端是用 PHP 编写的，那么修复只需要升级到 PHP 8 或 7，并升级硬件到 x86\_64 或 IA64。如果你有硬件方面的问题，你可以尝试在 32 位计算机的虚拟机中模拟 64 位硬件，但大部分 VM 都不支持这种虚拟化，因为存在稳定性和性能的问题。

Y10k 问题（通常是客户端）
---------------

在许多服务器中，日期存储为数字而非字符串——固定大小且与格式无关（大端对齐）。在 10000 年之后，这些数字只是会比以前更大一点，因此服务器上一般不会存在 10000 年之后提交表单的问题。

问题出现在客户端上：解析超过 4 位的年份。

```html
<!--midnight of January 1st, 10000: the exact time of Y10K-->
<input type="datetime-local" value="+010000-01-01T05:00" />
```

就是这么简单，你只需要为任意位数的日期编写代码。不要只准备 5 位数的。以下是使用编程方式设置值的 JavaScript 代码：

```js
function setValue(element, date) {
  const isoString = date.toISOString();
  element.value = isoString.substring(0, isoString.indexOf("T") + 6);
}
```

如果 Y10K 问题会在你离世以后的许多个世纪才发生，那为什么还要担心它呢？正因为你已经走了，且没有其他足够了解系统编码的人员去修复它，所以使用你的软件的公司将无法使用你的软件。

示例
--

在这个示例中，我们创建两套 UI 元素来选择日期时间——一套原生的 `<input type="datetime-local">`，另一套是一系列 `<select>` 元素以在不支持原生控件的浏览器下选择日期和时间。

HTML 代码如下：

```html
<form>
  <div class="nativeDateTimePicker">
    <label for="party">Choose a date and time for your party:</label>
    <input type="datetime-local" id="party" name="bday" />
    <span class="validity"></span>
  </div>
  <p class="fallbackLabel">Choose a date and time for your party:</p>
  <div class="fallbackDateTimePicker">
    <div>
      <span>
        <label for="day">Day:</label>
        <select id="day" name="day"></select>
      </span>
      <span>
        <label for="month">Month:</label>
        <select id="month" name="month">
          <option selected>January</option>
          <option>February</option>
          <option>March</option>
          <option>April</option>
          <option>May</option>
          <option>June</option>
          <option>July</option>
          <option>August</option>
          <option>September</option>
          <option>October</option>
          <option>November</option>
          <option>December</option>
        </select>
      </span>
      <span>
        <label for="year">Year:</label>
        <select id="year" name="year"></select>
      </span>
    </div>
    <div>
      <span>
        <label for="hour">Hour:</label>
        <select id="hour" name="hour"></select>
      </span>
      <span>
        <label for="minute">Minute:</label>
        <select id="minute" name="minute"></select>
      </span>
    </div>
  </div>
</form>
```

月份是固定写死的（它们是不变的），日期和年份的值是依据选中的月和年动态生成的，并且目前的年份顺序排列（代码的注释以详细解释了解这些函数是如何工作的），我们也决定动态生成小时和分种，它们的数量实在是多了点！
```

div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span:after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span:after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

代码的另一部分也许会引起一定的兴趣，那就是功能检查代码——检查浏览器是否支持 `<input type="datetime-local">`，我们可以创建一个新的 `<input>` 元素，设置它的 `type` 为 `datetime-local`，然后立即检查它被设置的类型。不支持 `datetime-local` 的浏览器返回 `text`，因为这就是 `datetime-local` 要回退的类型。如果 `<input type="datetime-local">` 不被支持，我们隐藏原生的控件并显示备用的控件 UI（`<select>`）来替代。

```js
// Obtain UI widgets
const nativePicker = document.querySelector(".nativeDateTimePicker");
const fallbackPicker = document.querySelector(".fallbackDateTimePicker");
const fallbackLabel = document.querySelector(".fallbackLabel");

const yearSelect = document.querySelector("#year");
const monthSelect = document.querySelector("#month");
const daySelect = document.querySelector("#day");
const hourSelect = document.querySelector("#hour");
const minuteSelect = document.querySelector("#minute");

// hide fallback initially
fallbackPicker.style.display = "none";
fallbackLabel.style.display = "none";

// test whether a new datetime-local input falls back to a text input or not
const test = document.createElement("input");

try {
  test.type = "datetime-local";
} catch (e) {
  console.log(e.description);
}

// if it does, run the code inside the if () {} block
if (test.type === "text") {
  // hide the native picker and show the fallback
  nativePicker.style.display = "none";
  fallbackPicker.style.display = "block";
  fallbackLabel.style.display = "block";

  // populate the days and years dynamically
  // (the months are always the same, therefore hardcoded)
  populateDays(monthSelect.value);
  populateYears();
  populateHours();
  populateMinutes();
}

function populateDays(month) {
  // delete the current set of <option> elements out of the
  // day <select>, ready for the next set to be injected
  while (daySelect.firstChild) {
    daySelect.removeChild(daySelect.firstChild);
  }

  // Create variable to hold new number of days to inject
  let dayNum;

  // 31 or 30 days?
  if (
    [
      "January",
      "March",
      "May",
      "July",
      "August",
      "October",
      "December",
    ].includes(month)
  ) {
    dayNum = 31;
  } else if (["April", "June", "September", "November"].includes(month)) {
    dayNum = 30;
  } else {
    // If month is February, calculate whether it is a leap year or not
    const year = yearSelect.value;
    const isLeap = new Date(year, 1, 29).getMonth() === 1;
    dayNum = isLeap ? 29 : 28;
  }

  // inject the right number of new <option> elements into the day <select>
  for (let i = 1; i <= dayNum; i++) {
    const option = document.createElement("option");
    option.textContent = i;
    daySelect.appendChild(option);
  }

  // if previous day has already been set, set daySelect's value
  // to that day, to avoid the day jumping back to 1 when you
  // change the year
  if (previousDay) {
    daySelect.value = previousDay;

    // If the previous day was set to a high number, say 31, and then
    // you chose a month with less total days in it (e.g. February),
    // this part of the code ensures that the highest day available
    // is selected, rather than showing a blank daySelect
    if (daySelect.value === "") {
      daySelect.value = previousDay - 1;
    }

    if (daySelect.value === "") {
      daySelect.value = previousDay - 2;
    }

    if (daySelect.value === "") {
      daySelect.value = previousDay - 3;
    }
  }
}

function populateYears() {
  // get this year as a number
  const date = new Date();
  const year = date.getFullYear();

  // Make this year, and the 100 years before it available in the year <select>
  for (let i = 0; i <= 100; i++) {
    const option = document.createElement("option");
    option.textContent = year - i;
    yearSelect.appendChild(option);
  }
}

function populateHours() {
  // populate the hours <select> with the 24 hours of the day
  for (let i = 0; i <= 23; i++) {
    const option = document.createElement("option");
    option.textContent = i < 10 ? `0${i}` : i;
    hourSelect.appendChild(option);
  }
}

function populateMinutes() {
  // populate the minutes <select> with the 60 hours of each minute
  for (let i = 0; i <= 59; i++) {
    const option = document.createElement("option");
    option.textContent = i < 10 ? `0${i}` : i;
    minuteSelect.appendChild(option);
  }
}

// when the month or year <select> values are changed, rerun populateDays()
// in case the change affected the number of available days
yearSelect.onchange = () => {
  populateDays(monthSelect.value);
};

monthSelect.onchange = () => {
  populateDays(monthSelect.value);
};

//preserve day selection
let previousDay;

// update what day has been set to previously
// see end of populateDays() for usage
daySelect.onchange = () => {
  previousDay = daySelect.value;
};
```

**备注：** 请记住某些年份有 53 个星期（见**每年的周数**）！当你在开发产品应用时应当考虑这个问题。

规范
--

| Specification |
| --- |
| HTML Standard # local-date-and-time-state-(type=datetime-local) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 通用 `<input>` 元素以及操作它的接口 `HTMLInputElement`
* `<input type="date">` 和 `<input type="time">`
* 日期和时间选择器教程 (en-US)


<input type="search"> - HTML（超文本标记语言）

<input type="search">
=====================

**`search`** 类型的 `<input>` 是专为用户输入查询文本而设计的字段。功能上与 `text` 输入相同，但是根据用户代理不同，可能会有不同的样式表现。

尝试一下
----

|  |  |
| --- | --- |
| **值** | 代表搜索字段中值的字符串。 |
| **事件** | `change` 和 `input` |
| **支持的通用属性** | `autocomplete`、`list`、`maxlength`、`minlength`、`pattern`、`placeholder`、`required`、`size`。 |
| **IDL 属性** | `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()`、`setRangeText()` (en-US)、`setSelectionRange()`。 |

值
-

`value` 属性包含一个代表搜索字段中含有值的字符串。你可以使用 JavaScript 的 `HTMLInputElement.value` 属性获取该值。

```js
searchTerms = mySearch.value;
```

如果没有针对该 input 的验证约束（请参见验证方式），该值可以是任何文本字符串或空字符串（`""`）。

其他属性
----

除了可在所有 `<input>` 上应用的属性（无论其类型）之外，搜索字段输入还支持以下属性。

### list

list 属性指定了一个 `<datalist>` 元素的 `id`，用来提供输入建议。`<datalist>` 提供了一个预定义的值列表，向用户建议这个输入。列表中任何与 `type` 不兼容的值都不包括在建议选项中。所提供的值是建议，不是要求：用户可以从这个预定义的列表中选择，或者提供不同的值。

### maxlength

用户可以在搜索字段中输入的最大字符数（UTF-16 代码单元）。必须为 0 或更高的整数。如果未指定 `maxlength` 或指定了无效值，则搜索字段没有最大长度。此值还必须大于或等于 `minlength` 的值。

如果输入到字段中的文本的长度大于 `maxlength` UTF-16 代码单元的长度，则输入无法通过约束验证。

### minlength

用户可以在搜索字段中输入的最小字符数（UTF-16 代码单元）。该值必须是小于或等于 `maxlength` 指定的值的非负整数值。如果未指定 `minlength` 或指定了无效值，则搜索输入没有最小长度。

如果在字段中输入的文本的长度小于 `minlength` UTF-16 代码单元的长度，则搜索字段将无法通过约束验证。

### pattern

如果指定了 `pattern` 属性，为了使 `value` 通过约束验证，必须满足该属性给定的正则表达式。它必须是 `RegExp` 类型的有效 JavaScript 正则表达式，并且已在我们的正则表达式指南中进行了说明；在编译正则表达式时指定了 `'u'` 标志，因此该模式被视为 Unicode 代码点的序列，而不是 ASCII。模式文本周围无需指定正斜杠。

如果模式未指定或无效，则不应用任何正则表达式，并且将完全忽略此属性。

**备注：** 使用 `title` 属性指定大多数浏览器将显示为文本的工具提示，以说明与模式匹配的要求。你还应该在附近添加其他说明性文字。

请参照指定模式更多内容和例子。

### placeholder

`placeholder` 属性是一个字符串，可向用户提供有关该字段中需要什么样的信息的简短提示。它应该是一个单词或短语来说明预期的数据类型，而不是说明性消息。文本中*不得*包含回车符或换行符。

如果控件的内容具有方向（LTR 或 RTL），但需要以相反的方向显示占位符，则可以使用 Unicode 双向算法来格式化字符，从而覆盖原有占位符的方向；请参见如何针对双向文本使用 Unicode 控制符获取更多信息。

**备注：** 尽可能避免使用 `placeholder` 属性。它在语义上没有其他解释表单的方式有用，并且可能导致内容出现意外的问题。请参见 `<input>` 标签以获取更多信息。

### readonly

一个布尔属性，如果存在，则表示该字段不能由用户编辑。但是，仍可以通过 JavaScript 代码直接设置 `HTMLInputElement` 的 `value` 属性来更改。

**备注：** 因为只读字段不能有值，所以 `required` 对指定了 `readonly` 属性的输入没有任何影响。

### size

`size` 属性是一个数字值，指示输入字段应有多少个字符宽。该值必须是一个大于零的数字，默认值是 20。由于字符宽度各不相同，这可能是也可能不是精确的，不应依赖于此；结果输入可能比指定的字符数更窄或更宽，这取决于字符和字体（正在使用的 `font` 设置）。

这并*不*限制用户可以在该字段中输入多少个字符，仅能指定一次可以看到多少个。要设置输入数据长度的上限，请使用 `maxlength` 属性。

### spellcheck

`spellcheck` 是一个全局属性，用于指示是否启用元素的拼写检查。它可以用于任何可编辑的内容，但是这里我们考虑在 `<input>` 元素上使用 `spellcheck` 的细节。 `spellcheck` 的允许值为：

`false`

禁用此元素的拼写检查。

`true`

对此元素启用拼写检查。

`""`（空字符串）或空值

遵循元素的默认行为进行拼写检查。这可能基于父元素 `spellcheck` 设置或其他因素。

如果输入字段没有设置 readonly 属性且未禁用，则可以启用拼写检查。

如果用户代理的首选项覆盖了设置，则通过读取 `spellcheck` 返回的值可能无法反映控件中拼写检查的实际状态。

非标准属性
-----

以下非标准属性在某些浏览器上对搜索输入字段也可用。一般来说，除非万不得已，否则你应该避免使用它们。

### autocorrect

Safari 扩展，`autocorrect` 属性是一个字符串，它指示在用户编辑此字段时是否激活自动更正。允许的值为：

`on`

启用拼写错误的自动更正，以及配置文本替换（如果已配置）的处理。

`off`

禁用自动更正和文本替换。

### incremental

布尔值属性 `incremental` 是 WebKit 和 Blink 的扩展（因此被 Safari、Opera、Chrome 等支持）。如果制定了它，它会告诉用户代理将输入作为实时搜索进行处理。当用户编辑字段的值时，用户代理将 `search` (en-US) 事件发送到代表搜索框的 `HTMLInputElement` 对象。这允许你的代码在用户编辑搜索时实时更新搜索结果。

如果没有指定 `incremental` ，则仅当用户显式启动搜索时（例如，在编辑字段时按 `Enter` 或 `Return` ）才发送 `search` (en-US) 事件。

`search` 事件受速率限制，因此发送事件的频率不会超过实现定义的间隔。

### mozactionhint

Mozilla 扩展，它提供了一个提示，提示用户在编辑字段时按 `Enter` 或 `Return` 键将采取何种操作。

此属性已经废弃：请使用全局属性 `enterkeyhint` 作为替代。

### results

`results` 属性是一个数字值（仅受 Safari 支持），可让你覆盖要在 `<input>` 元素原生提供的先前搜索查询的下拉菜单中所显示的最大条目数。

该值必须是非负十进制数字。如果未提供或给出了无效值，则使用浏览器的默认最大条目数。

使用搜索输入
------

`search` 类型的 `<input>` 元素与 `text` 类型的元素非常相似，不同之处在于它们专门用于处理搜索条目。它们的行为基本相同，但是用户代理可以选择与默认样式不同的样式（当然，站点可以使用样式表向其应用自定义样式）。

### 基本示例

```html
<form>
  <div>
    <input type="search" id="mySearch" name="q" />
    <button>搜索</button>
  </div>
</form>
```

如下：

`q` 是搜索输入中最常用的 `name` 值，尽管不是强制性的。提交后，发送到服务器的键值对数据将为 `q=searchterm`。

**备注：** 一定要记住为你的 input 设置 `name`，否则不会提交任何内容。

### 搜索类型和文本类型之间的差异

主要的基本区别在于浏览器处理它们的方式。首先要注意的是，某些浏览器显示一个十字图标，如果需要，可以单击该十字图标以立即删除搜索词。在 Chrome 中当按下 escape 键时也会触发这个动作。以下屏幕截图来自 Chrome：

![Focused search input, with focus ring, with the text 'cats'. There is an x icon in the input abutting the right side.](/zh-CN/docs/Web/HTML/Element/input/search/chrome-cross-icon.png)

此外，现代浏览器还倾向于自动存储先前在各个域中输入的搜索词，在该域的搜索输入中执行后续搜索时，这些搜索词会作为自动完成选项出现。这有助于随着时间的流逝倾向于在相同或相似搜索查询上进行搜索的用户。此屏幕截图来自 Firefox：

![An input in error state with a red focus ring. The user has entered the letter 'h'. A pop-up selection list is open directly under the input box with two options: hello and hermansje.](/zh-CN/docs/Web/HTML/Element/input/search/firefox-auto-complete.png)现在，让我们看看可以应用于搜索表单的一些有用的技巧。

### 设置占位符

可以在搜索输入中提供一个有用的占位符，使用 `placeholder` 属性来提示要做什么。看下面的示例：

```html
<form>
  <div>
    <input type="search" id="mySearch" name="q" placeholder="站内搜索..." />
    <button>搜索</button>
  </div>
</form>
```

可以在下面看到占位符的呈现方式：

### 搜索表单标签和无障碍

搜索表单的一个问题是它们的无障碍性。常见的设计惯例是不为搜索字段提供标签（尽管可能会有放大镜或类似图标），因为由于放置位置的原因，搜索表单的目的通常对于视力正常的用户而言相当明显（这个例子展示了一个典型的模式）。

但是，这可能会使屏幕阅读器用户感到困惑，因为它们不会对搜索输入内容有任何口头指示。解决此问题而不会影响你的视觉设计的一种方法是使用 WAI-ARIA 功能：

* `<form>` 元素上， `search` 值的 `role` 属性向屏幕阅读器用户声明该表单是搜索表单。
* 还可以在 `<input>` 本身使用 `aria-label` 属性。这应该是一个描述性的文本标签，屏幕阅读器会读出该标签；它用作 `<label>` 的非可视等效项。

让我们看一个例子：

```html
<form role="search">
  <div>
    <input
 type="search"
 id="mySearch"
 name="q"
 placeholder="站内搜索..."
 aria-label="在全站内容中搜索" />
    <button>搜索</button>
  </div>
</form>
```

你可以在下面看到它的呈现方式：

与上一个示例没有视觉上的区别，但是屏幕阅读器用户可以获得更多可用信息。

**备注：** 有关此类辅助功能的更多信息，请参见 Signposts/Landmarks 。

### 输入框元素物理大小

可以使用 `size` 属性来控制输入框的尺寸。使用它，可以指定输入框一次可以显示的字符数。例如，在此示例中，搜索框为 30 个字符宽：

```html
<form>
  <div>
    <input
 type="search"
 id="mySearch"
 name="q"
 placeholder="站内搜索..."
 size="30" />
    <button>搜索</button>
  </div>
</form>
```

结果是这个更宽的输入框：

验证方式
----

`<input>` 元素的 `search` 类型具有与常规文本 `text` 输入相同的验证功能。通常，不太可能希望对搜索框使用验证功能。在许多情况下，应该允许用户搜索任何内容，但是有几种情况需要考虑，例如搜索已知格式的数据。

**备注：** HTML 表单验证*不能*替代服务器脚本，以确保输入的数据格式正确。对于某人来说，对 HTML 进行调整以使其绕过验证或完全删除验证太容易了。有人也可以完全绕开你的 HTML 并将数据直接提交到你的服务器。如果服务器端代码无法验证接收到的数据，则当将格式不正确的数据（或太大，类型错误的数据等等）输入数据库时，灾难可能会发生。

### 样式注意事项

有一些有用的伪类可用于设置有效/无效表单元素的样式：`:valid` 和 `:invalid`。在本节中，我们将使用以下 CSS，它将在包含有效值的输入旁边放置一个复选标记（勾号），并在包含无效值的输入旁边放置一个叉号。

```css
input:invalid ~ span::after {
  content: "✖";
  padding-left: 5px;
  position: absolute;
}

input:valid ~ span::after {
  content: "✓";
  padding-left: 5px;
  position: absolute;
}
```

该技巧还需要将 `<span>` 元素放置在 form 元素之后，该 form 元素充当图标的持有者。这是必要的，因为某些浏览器上的某些输入类型不能很好地显示直接位于其后的图标。

### 让输入框必填

你可以使用 `required` 属性令输入一个值成为允许提交表单前的必要条件：

```html
<form>
  <div>
    <input
 type="search"
 id="mySearch"
 name="q"
 placeholder="站内搜索..."
 required />
    <button>搜索</button>
    <span class="validity"></span>
  </div>
</form>
```

```
input {
  margin-right: 10px;
}

input:invalid ~ span::after {
  content: "✖";
  padding-left: 5px;
  position: absolute;
}

input:valid ~ span::after {
  content: "✓";
  padding-left: 5px;
  position: absolute;
}
```

如下所示：

另外，如果尝试在未输入搜索词的情况下提交表单，浏览器将显示一条消息。以下示例来自 Firefox：

![form field with attached message that says Please fill out this field](/zh-CN/docs/Web/HTML/Element/input/search/firefox-required-message.png)

当尝试使用输入中包含的不同类型的无效数据提交表单时，将显示不同的消息；请参阅以下示例。

### 输入值长度

你可以使用 `minlength` 属性为输入的值指定最小长度（以字符为单位）；同样，使用 `maxlength` 设置输入值的最大长度。

下面的示例要求输入的值的长度为 4–8 个字符。

```html
<form>
  <div>
    <label for="mySearch">查找用户</label>
    <input
 type="search"
 id="mySearch"
 name="q"
 placeholder="用户 ID 的长度为 4-8 个字符"
 required
 size="30"
 minlength="4"
 maxlength="8" />
    <button>查找</button>
    <span class="validity"></span>
  </div>
</form>
```

```
input {
  margin-right: 10px;
}

input:invalid ~ span::after {
  content: "✖";
  padding-left: 5px;
  position: absolute;
}

input:valid ~ span::after {
  content: "✓";
  padding-left: 5px;
  position: absolute;
}
```

如下所示：

如果尝试提交少于 4 个字符的表单，则会收到相应的错误消息（不同的浏览器会有所不同）。如果尝试输入超过 8 个字符，浏览器将不允许你这样做。

### 指定模式

你可以使用 `pattern` 属性指定一个正则表达式，输入值必须遵循该正则表达式才能被视为有效（请参照使用正则表达式进行验证）。

让我们看一个例子。假设我们想提供一个产品 ID 搜索表格，这些 ID 都是由两个字母和四个数字组成的代码。以下示例对此进行了介绍：

```html
<form>
  <div>
    <label for="mySearch">根据 ID 查找产品：</label>
    <input
 type="search"
 id="mySearch"
 name="q"
 placeholder="两个字母接四位数字"
 required
 size="30"
 pattern="[A-z]{2}[0-9]{4}" />
    <button>查找</button>
    <span class="validity"></span>
  </div>
</form>
```

```
input {
  margin-right: 10px;
}

input:invalid ~ span::after {
  content: "✖";
  padding-left: 5px;
  position: absolute;
}

input:valid ~ span::after {
  content: "✓";
  padding-left: 5px;
  position: absolute;
}
```

如下所示：

例子
--

可以在我们的网站 website-aria-roles 示例中看到一个在上下文中使用搜索表单的一个好例子（试试在线运行它）。

规范
--

| Specification |
| --- |
| HTML Standard # text-(type=text)-state-and-search-state-(type=search) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* HTML 表单
* `<input>` 及其所基于的接口 `HTMLInputElement`
* `<input type="text">`
* CSS 属性的兼容性


<input type="button"> - HTML（超文本标记语言）

<input type="button">
=====================

**`button`** 类型的 `<input>` 元素被渲染为简单的按钮，可以根据需要对其进行编程，可以为其分配一个事件处理函数（通常为 `click` 事件），以控制网页上的任何地方的自定义功能。

尝试一下
----

**备注：** `button` 类型的 `<input>` 元素仍然是合法的 HTML 代码，但是新的 `<button>` 元素是创建按钮的更好的方式。鉴于 `<button>` 的标签文字可以插入至开闭标签之间，你可以在标签中包含 HTML 代码，甚至是图像。

值
-

### 含有值的按钮

`<input type="button">` 的 `value` 属性包含用作按钮标签的字符串。

```html
<input type="button" value="点我" />
```

### 不含有值的按钮

如果没有指定 `value`，会得到一个空的按钮：

```html
<input type="button" />
```

使用按钮
----

`<input type="button">` 元素没有默认行为（与之类似的 `<input type="submit">` 和 `<input type="reset">` 分别用于提交和重置表单）。要让按钮做任何事情，你必须编写 JavaScript 代码。

### 简单的按钮

我们从创建一个具有 `click` 事件处理器的按钮开始，它启动了我们的机器（同时，也切换了按钮的 `value` 和下列段落的文字）：

```html
<form>
  <input type="button" value="开动机器" />
</form>
<p>机器已经停下了。</p>
```

```js
const button = document.querySelector("input");
const paragraph = document.querySelector("p");

button.addEventListener("click", updateButton);

function updateButton() {
  if (button.value === "开动机器") {
    button.value = "停止机器";
    paragraph.textContent = "机器启动了！";
  } else {
    button.value = "开动机器";
    paragraph.textContent = "机器已经停下了。";
  }
}
```

脚本获得了对 DOM 中代表 `<input>` 的 `HTMLInputElement` 对象的引用，并将此引用保存在变量 `button` 中。然后，`addEventListener()` 被用来建立一个函数，当按钮上发生 `click` 事件时，该函数将被运行。

### 为按钮添加键盘快捷方式

键盘快捷键可以让用户使用键盘上的某个键或组合键来触发一个按钮。要为一个按钮添加键盘快捷键——就像对任何 `<input>` 都有意义的那样——你可以使用 `accesskey` 全局属性。

在这个例子中，`s` 被指定成为访问键，你需要按住浏览器或操作系统所指定的组合键加上 `s` 键来触发按钮，参见 accesskey 以获取一些有用的列表。

```html
<form>
  <input type="button" value="开动机器" accesskey="s" />
</form>
<p>机器已经停下了。</p>
```

```
const button = document.querySelector("input");
const paragraph = document.querySelector("p");

button.addEventListener("click", updateButton);

function updateButton() {
  if (button.value === "开动机器") {
    button.value = "停止机器";
    paragraph.textContent = "机器启动了！";
  } else {
    button.value = "开动机器";
    paragraph.textContent = "机器已经停下了。";
  }
}
```

**备注：** 当然，上述例子的问题是，用户将不知道访问键是什么！在一个真实的网站中，你必须以一种不影响网站设计的方式来提供这些信息（例如，提供一个容易访问的链接，指向关于网站访问键是什么的信息）。

### 禁用和启用按钮

要禁用按钮，在其上指定 `disabled` 全局属性，就像这样：

```html
<input type="button" value="禁用我" disabled />
```

#### 设置禁用属性

你可以在运行时通过设置 `disabled` 为 `true` 或 `false` 来启用和禁用按钮。在这个例子中，我们的按钮一开始是启用的，但如果你按下它，就会用 `button.disabled = true` 将其禁用。然后，一个 `setTimeout()` 函数被用来在两秒后将按钮重置为启用状态。

```html
<input type="button" value="已启用" />
```

```js
const button = document.querySelector("input");

button.addEventListener("click", disableButton);

function disableButton() {
  button.disabled = true;
  button.value = "已禁用";
  setTimeout(() => {
    button.disabled = false;
    button.value = "已启用";
  }, 2000);
}
```

#### 继承禁用状态

如果没有指定 `disabled` 属性，按钮将从其父元素继承其 `disabled` 状态。这使得一次启用和禁用一组元素成为可能，方法是将它们包围在一个容器中，如 `<fieldset>` 元素，然后在容器中设置 `disabled`。

下面的例子显示了这个动作。这与前面的例子非常相似，只是当第一个按钮被按下时，`disabled` 属性被设置在 `<fieldset>` 上——这导致所有三个按钮被禁用，直到两秒的超时时间过去。

```html
<fieldset>
  <legend>按钮组</legend>
  <input type="button" value="按钮 1" />
  <input type="button" value="按钮 2" />
  <input type="button" value="按钮 3" />
</fieldset>
```

```js
const button = document.querySelector("input");
const fieldset = document.querySelector("fieldset");

button.addEventListener("click", disableButton);

function disableButton() {
  fieldset.disabled = true;
  setTimeout(() => {
    fieldset.disabled = false;
  }, 2000);
}
```

**备注：** Firefox 不像其他浏览器那样，它会在不同页面之间保持 `<button>` 的动态禁用的状态。请使用 `autocomplete` 属性来控制这个特性。

验证
--

按钮不参与到约束验证中；它们没有用于约束的真值。

示例
--

下面的例子显示了一个非常简单的绘画应用，它是用 `<canvas>` 元素和一些简单的 CSS 和 JavaScript 创建的（为了简洁，我们将隐藏 CSS）。上面的两个控件允许你选择画笔的颜色和大小。按钮，当点击时，调用一个函数来清除画布。

```html
<div class="toolbar">
  <input type="color" aria-label="选择画笔颜色" />
  <input
 type="range"
 min="2"
 max="50"
 value="30"
 aria-label="选择画笔大小" /><span class="output">30</span>
  <input type="button" value="清除画布" />
</div>

<canvas class="myCanvas">
  <p>Add suitable fallback here.</p>
</canvas>
```

```
body {
  background: #ccc;
  margin: 0;
  overflow: hidden;
}

.toolbar {
  background: #ccc;
  width: 150px;
  height: 75px;
  padding: 5px;
}

input[type="color"],
input[type="button"] {
  width: 90%;
  margin: 0 auto;
  display: block;
}

input[type="range"] {
  width: 70%;
}

span {
  position: relative;
  bottom: 5px;
}
```

```js
const canvas = document.querySelector(".myCanvas");
const width = (canvas.width = window.innerWidth);
const height = (canvas.height = window.innerHeight - 85);
const ctx = canvas.getContext("2d");

ctx.fillStyle = "rgb(0,0,0)";
ctx.fillRect(0, 0, width, height);

const colorPicker = document.querySelector('input[type="color"]');
const sizePicker = document.querySelector('input[type="range"]');
const output = document.querySelector(".output");
const clearBtn = document.querySelector('input[type="button"]');

// covert degrees to radians
function degToRad(degrees) {
  return (degrees \* Math.PI) / 180;
}

// update sizepicker output value

sizePicker.oninput = () => {
  output.textContent = sizePicker.value;
};

// store mouse pointer coordinates, and whether the button is pressed
let curX;
let curY;
let pressed = false;

// update mouse pointer coordinates
document.onmousemove = (e) => {
  curX = e.pageX;
  curY = e.pageY;
};

canvas.onmousedown = () => {
  pressed = true;
};

canvas.onmouseup = () => {
  pressed = false;
};

clearBtn.onclick = () => {
  ctx.fillStyle = "rgb(0,0,0)";
  ctx.fillRect(0, 0, width, height);
};

function draw() {
  if (pressed) {
    ctx.fillStyle = colorPicker.value;
    ctx.beginPath();
    ctx.arc(
      curX,
      curY - 85,
      sizePicker.value,
      degToRad(0),
      degToRad(360),
      false,
    );
    ctx.fill();
  }

  requestAnimationFrame(draw);
}

draw();
```

技术总结
----

|  |  |
| --- | --- |
| **值** | 用作按钮标签的字符串 |
| **事件** | `click` |
| **支持的通用属性** | `type` 和
 `value` |
| **IDL 属性** | `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | 无 |

规范
--

| Specification |
| --- |
| HTML Standard # button-state-(type=button) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `<input>` 和实现它的 `HTMLInputElement` 接口。
* 更现代的 `<button>` 元素。
* 表单控件 CSS 兼容性表格


<input type="color"> - HTML（超文本标记语言）

<input type="color">
====================

**`color`** 类型的 `<input>` 元素为用户提供了指定颜色的用户界面，或使用可视化颜色选择器，或以 `#rrggbb` 十六进制格式输入颜色值。

虽然 CSS 颜色有很多格式（如颜色名称、功能表记和含有透明通道的十六进制），但是这里只支持简单颜色（无透明通道）。

此元素的外观会因浏览器不同而不同，它可能是一个简单的文本输入，自动验证以确保颜色信息以正确的格式输入，或一个平台标准的颜色选择器，或某种自定义的颜色选择器窗口。

尝试一下
----

|  |  |
| --- | --- |
| **值** | 长度为 7 的指定 `<color>` 值的小写十六进制字符串 |
| **事件** | `change` 和
 `input` |
| **支持的公共属性** | `autocomplete` 和
 `list` |
| **IDL 属性** | `list` 和 `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()` |

值
-

`color` 类型的 `<input>` 元素的 `value` 总是包含一个 7 个字符的字符串，它以 16 进制格式指定 RGB 颜色。虽然你可以用大写字母或小写字母输入颜色，但它将以小写字母形式存储。该值从不以任何其他形式出现，也从不为空。

**备注：** 将该值设置为任何不是有效的、完全不透明的、RGB 颜色的*十六进制表示*，都将导致该值被设置为 `#000000`。特别是，你不能使用 CSS 的标准化颜色名称或任何 CSS 函数语法来设置该值（记住，HTML 和 CSS 是独立的语言和规范）。此外，不支持带有透明通道的颜色；用 9 个字符的十六进制表示（例如 `#009900aa`）指定颜色，也会导致颜色被设置为 `#000000`。

使用 color 输入
-----------

由于有限的支持属性，`color` 类型的输入内容比较简单。

### 提供默认颜色

你可以更新上面的简单例子，设置一个默认值，这样颜色井就会预先填上默认的颜色，颜色选择器（如果有的话）也会默认为这个颜色。

```html
<input type="color" value="#ff0000" />
```

如果你没有手动指定的话，其默认值为 `#000000`，即黑色。输入必须为 7 个字符的十六进制表示，意味着需要以“#”符号开始，后跟代表红、绿、蓝的十六进制字符各 2 个（形如 `#rrggbb`）。如果你想输入的颜色是其他格式（比如 CSS 颜色名称或 CSS 颜色函数如 `rgb()` 或 `rgba()` 记法），在设定 `value` 值时必须将其转换为这种格式。

### 监听颜色变化

正如其他类型的 `<input>` 元素，有两个和值的改变相关的事件，`input` 和 `change`。每次颜色变更都会触发 `<input>` 元素上的 `input` 事件。用户关闭选色器之后会触发 `change` 事件。对于这两个事件，都可以通过 `value` 属性获取新值。

以下代码为监听颜色值变化的示例：

```js
colorPicker.addEventListener("input", updateFirst, false);
colorPicker.addEventListener("change", watchColorPicker, false);

function watchColorPicker(event) {
  document.querySelectorAll("p").forEach((p) => {
    p.style.color = event.target.value;
  });
}
```

### 选取值

当浏览器不支持颜色选择器接口时，它对颜色输入的实现将是一个自动验证内容以确保数值的格式正确的文本框。在这种情况下，你可以使用 `select()` 方法来选择当前编辑栏中的文本。

如果浏览器提供了选色器，`select()` 方法将会什么也不做。因此，需要留心这两种情况下方法行为的差异。

```js
colorWell.select();
```

验证
--

如果当前的用户代理下，用户输入无法转换为 7 个字符的十六进制 RGB 形式，会被判定为非法输入。在这种情况下，`:invalid` 伪类会作用于该元素上。

示例
--

让我们创建一个例子，通过跟踪 `change` 和 `input` 事件，对颜色输入做一些处理，将新颜色应用到文档中的每个 `<p>` 元素。

### HTML

这个 HTML 是相当简单的——有若干包含描述材料的段落和一个 ID 为 `colorWell` 的 `color` `<input>`，我们将用它来改变段落文本的颜色。

```html
<p>
  An example demonstrating the use of the
  <code><input type="color"></code> control.
</p>

<label for="colorWell">Color:</label>
<input type="color" value="#ff0000" id="colorWell" />

<p>
  Watch the paragraph colors change when you adjust the color picker. As you
  make changes in the color picker, the first paragraph's color changes, as a
  preview (this uses the <code>input</code> event). When you close the color
  picker, the <code>change</code> event fires, and we detect that to change
  every paragraph to the selected color.
</p>
```

### JavaScript

首先是一些设置，这里我们建立了一些变量，设置了一个包含我们在第一次加载时要设置的颜色井的变量，然后设置了 `load` 处理器，在页面完全加载后做主要的启动工作。

```js
let colorWell;
const defaultColor = "#0000ff";

window.addEventListener("load", startup, false);
```

#### 初始化

一旦页面完全加载，就会调用我们的 `load` 事件处理器 `startup()`：

```js
function startup() {
  colorWell = document.querySelector("#colorWell");
  colorWell.value = defaultColor;
  colorWell.addEventListener("input", updateFirst, false);
  colorWell.addEventListener("change", updateAll, false);
  colorWell.select();
}
```

在一个叫做 `colorWell` 的变量中获得对颜色 `<input>` 元素的引用，然后将颜色输入的值设置为 `defaultColor` 中的值。然后颜色输入的 `input` 事件被设置为调用我们的 `updateFirst()` 函数，而 `change` 事件被设置为调用 `updateAll()`。这些都在下面看到。

最后，如果控件被实现为文本字段，我们调用 `select()` 来选择颜色输入的文本内容（如果提供的是颜色选择器接口，这就没有效果）。

#### 对颜色变化作出反应

我们提供了两个处理颜色变化的函数。`updateFirst()` 函数是为了响应 `input` 事件而调用的。它改变文档中第一个段落元素的颜色，以匹配颜色输入的新值。由于每次对数值进行调整时都会触发 `input` 事件（例如，如果增加了颜色的亮度），在使用颜色选择器时，这些事件会重复发生。

```js
function updateFirst(event) {
  const p = document.querySelector("p");
  if (p) {
    p.style.color = event.target.value;
  }
}
```

当退出颜色选择器时，表明值不会再改变（除非用户重新打开颜色选择器），会向该元素发送 `change` 事件。我们使用 `updateAll()` 函数来处理该事件，使用 `Event.target.value` 来获得最终选择的颜色：

```js
function updateAll(event) {
  document.querySelectorAll("p").forEach((p) => {
    p.style.color = event.target.value;
  });
}
```

这将设置每个 `<p>` 区块的颜色，使其 `color` 属性与颜色输入的当前值相匹配，颜色输入是用 `event.target` 引用的。

### 结果

最终的运行结果如下所示：

规范
--

| Specification |
| --- |
| HTML Standard # color-state-(type=color) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* CSS 属性兼容性列表


<input type="text"> - HTML（超文本标记语言）

<input type="text">
===================

**`text`** 类型的 `<input>` 元素创建了基础的单行文本字段。

尝试一下
----

|  |  |
| --- | --- |
| **值** | 代表包含在文本字段中的文字 |
| **事件** | `change` 和 `input` |
| **支持的公共属性** | `autocomplete`、`list`、`maxlength`、`minlength`、`pattern`、`placeholder`、`readonly`、`required` 和 `size` |
| **IDL 属性** | `list`、`value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()`、`setRangeText()` (en-US) 和 `setSelectionRange()`。 |

值
-

`value` 属性是一个包含了文本域当前文字的字符串。你可以在 Javascript 中使用 `HTMLInputElement` 的 `value` 属性获取这些文字。

```js
let theText = myTextInput.value;
```

如果当前文本输入没有约束验证（查看验证小节获取更多详细信息），`value` 值可能是空字符串（`""`）。

其他属性
----

除了所有 `<input>` 元素上共有的可操作的属性外，文本输入框还支持以下属性：

### `list`

列表属性的值是位于同一文档中的 `<datalist>` 元素的 `id`。`<datalist>` 提供了一个预定义的值列表，向用户建议这个输入。列表中任何与 `type` 不兼容的值都不包括在建议选项中。所提供的值是建议，不是要求：用户可以从这个预定义的列表中选择，或者提供不同的值。

### `maxlength`

用户可以输入到 `text` 输入框中的最大字符数（以 UTF-16 码点为单位）。必须为大于等于 0 的整数。如果未指定 `maxlength` 或指定了无效的值，则 `text` 输入框将没有最大值。这个值也必须大于等于 `minlength` 的值。

如果文本框中的字符数大于 `maxlength` UTF-16 编码单元长度，则输入将无法通过约束验证。约束验证仅作用于用户修改输入值的时候。

### `minlength`

用户可以输入到 `text` 输入框中的最小字符数（以 UTF-16 码点为单位）。该值必须是小于等于 `maxlength` 指定的值的非负整数值。如果未指定 `minlength` 或指定了无效的值，则 `text` 输入将没有最小值。

如果输入到字段中的文本的长度小于 `minlength` UTF-16 代码单元的长度，则输入将无法通过约束验证。约束验证仅作用于用户修改输入值的时候。

### `pattern`

如果指定了 `pattern` 属性，为了使 `value` 通过约束验证，必须满足该属性给定的正则表达式。它必须是 `RegExp` 类型的有效 JavaScript 正则表达式，并且已在我们的正则表达式指南中进行了说明；在编译正则表达式时指定了 `'u'` 标志，因此该模式被视为 Unicode 代码点的序列，而不是 ASCII。模式文本周围无需指定正斜杠。

如果模式未指定或无效，则不应用任何正则表达式，并且将完全忽略此属性。

**备注：** 使用 `title` 属性指定大多数浏览器将显示为文本的工具提示，以说明与模式匹配的要求。你还应该在附近添加其他说明性文字。

请参照指定模式更多内容和例子。

### `placeholder`

`placeholder` 属性是一个字符串，可向用户提供有关该字段中需要什么样的信息的简短提示。它应该是一个单词或短语来说明预期的数据类型，而不是说明性消息。文本中*不得*包含回车符或换行符。

如果控件的内容具有方向（LTR 或 RTL），但需要以相反的方向显示占位符，则可以使用 Unicode 双向算法来格式化字符，从而覆盖原有占位符的方向；请参见如何针对双向文本使用 Unicode 控制符获取更多信息。

**备注：** 尽可能避免使用 `placeholder` 属性。它在语义上没有其他解释表单的方式有用，并且可能导致内容出现意外的问题。请参见 `<input>` 标签以获取更多信息。

### `readonly`

一个布尔属性，如果存在，则表示该字段不能由用户编辑。但是，仍可以通过 JavaScript 代码直接设置 `HTMLInputElement` 的 `value` 属性来更改。

**备注：** 因为只读字段不能有值，所以 `required` 对指定了 `readonly` 属性的输入没有任何影响。

### `size`

`size` 属性是一个数字值，指示输入字段应有多少个字符宽。该值必须是一个大于零的数字，默认值是 20。由于字符宽度各不相同，这可能是也可能不是精确的，不应依赖于此；结果输入可能比指定的字符数更窄或更宽，这取决于字符和字体（`font`使用中的设置）。

这并*不*限制用户可以在该字段中输入多少个字符，仅能指定一次可以看到多少个。要设置输入数据长度的上限，请使用 `maxlength` 属性。

### `spellcheck`

`spellcheck` 是一个全局属性，用于指示是否启用元素的拼写检查。它可以用于任何可编辑的内容，但是这里我们考虑在 `<input>` 元素上使用 `spellcheck` 的细节。 `spellcheck` 的允许值为：

`false`

禁用此元素的拼写检查。

`true`

对此元素启用拼写检查。

`""`（空字符串）或空值

遵循元素的默认行为进行拼写检查。这可能基于父元素 `spellcheck` 设置或其他因素。

如果输入字段没有设置 readonly 属性且未禁用，则可以启用拼写检查。

如果用户代理的首选项覆盖了设置，则通过读取 `spellcheck` 返回的值可能无法反映控件中拼写检查的实际状态。

非标准属性
-----

以下非标准属性在某些浏览器上也可用。一般来说，除非万不得已，否则你应该避免使用它们。

### `autocorrect`

Safari 扩展，`autocorrect` 属性是一个字符串，它指示在用户编辑此字段时是否激活自动更正。允许的值为：

`on`

启用拼写错误的自动更正，以及配置文本替换（如果已配置）的处理。

`off`

禁用自动更正和文本替换。

### `mozactionhint`

Mozilla 扩展，它提供了一个提示，提示用户在编辑字段时按 `Enter` 或 `Return` 键将采取何种操作。

此属性已经废弃：请使用全局属性 `enterkeyhint` 作为替代。

使用文本输入框
-------

`<input>` 元素的 `text` 类型创建基本的单行输入。你应该在希望用户输入单行值的任何地方使用它们，并且没有更具体的输入类型可用于收集该值（例如，如果是日期或时间、URL、电子邮件或查找词汇，你将拥有更好的选择）。

### 基础示例

```html
<form>
  <div>
    <label for="uname">输入一个用户名：</label>
    <input type="text" id="uname" name="name" />
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

如下所示：

提交后，发送到服务器的键/值对的数据将为 `name=Chris`（如果在提交之前输入了“Chris”作为输入值）。你必须记住在 `<input>` 元素上包含 `name` 属性，否则文本字段的值将不包含在提交的数据中。

### 设置占位符

你可以通过使用 `placeholder` 属性在文本输入中提供一个有用的占位符，提示用户该输入什么。看下面的例子：

```html
<form>
  <div>
    <label for="uname">输入一个用户名：</label>
    <input type="text" id="uname" name="name" placeholder="一个小写单词" />
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

你可以在下面看到占位符的呈现方式：

占位符通常以比元素的前景色更浅的颜色呈现，并且在用户开始向字段中输入文本时（或者每当字段通过编程方式设置其 `value` 属性时）就会自动消失。

### 输入框元素尺寸

可以使用 `size` 属性来控制输入框的尺寸。使用它，可以指定文本输入一次可以显示的字符数。这会影响元素的宽度，使你可以按字符而不是像素指定宽度。例如，在此示例中，输入为 30 个字符宽：

```html
<form>
  <div>
    <label for="uname">输入一个用户名：</label>
    <input
 type="text"
 id="uname"
 name="name"
 placeholder="一个小写单词"
 size="30" />
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

验证
--

`text` 类型的 `<input>` 元素默认没有应用自动验证（因为基本文本输入需要能够接受任意字符串），但是有一些客户端验证选项可用，我们将在下面讨论。

**备注：** HTML 表单验证*不能*替代服务器脚本，以确保输入的数据格式正确。对于某人来说，对 HTML 进行调整以使其绕过验证或完全删除验证太容易了。有人也可以完全绕开你的 HTML 并将数据直接提交到你的服务器。如果服务器端代码无法验证接收到的数据，则当将格式不正确的数据（或太大，类型错误的数据等等）输入数据库时，灾难可能会发生。

### 样式注意事项

有一些有用的伪类可用于设置表单元素的样式，以帮助用户查看其值是有效还是无效，它们是 `:valid` 和 `:invalid`。在本节中，我们将使用以下 CSS，它将在包含有效值的输入旁边放置一个复选标记（tick），并在包含无效值的输入旁边放置一个叉号（X）。

```css
div {
  margin-bottom: 10px;
  position: relative;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

该技术还需要将 `<span>` 元素放置在 `form` 元素之后，该 `form` 元素充当图标的持有者。这样做的原因是某些浏览器上的某些输入类型不能很好地显示直接位于其后的图标。

### 使输入框必填

你可以使用 `required` 属性简单地令该输入框在表单提交前必须填入值：

```html
<form>
  <div>
    <label for="uname">输入一个用户名：</label>
    <input type="text" id="uname" name="name" required />
    <span class="validity"></span>
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

```
div {
  margin-bottom: 10px;
  position: relative;
}
input + span {
  padding-right: 30px;
}
input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}
input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

该示例渲染如下所示：

如果尝试在未输入搜索词的情况下提交表单，浏览器将显示一条错误消息。

### 输入值长度

你可以使用 `minlength` 属性指定输入值的最小长度（以字符为单位）；同样，也可以使用 `maxlength` 设置输入值的最大长度（以字符为单位）。

下面的示例要求输入的值的长度为 4–8 个字符。

```html
<form>
  <div>
    <label for="uname">输入一个用户名：</label>
    <input
 type="text"
 id="uname"
 name="name"
 required
 size="10"
 placeholder="用户名"
 minlength="4"
 maxlength="8" />
    <span class="validity"></span>
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

```
div {
  margin-bottom: 10px;
  position: relative;
}
input + span {
  padding-right: 30px;
}
input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}
input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

如下所示：

如果尝试提交少于 4 个字符的表单，则会收到一条相应的错误消息（不同的浏览器会有所不同）。如果尝试输入 8 个以上的字符，浏览器将不允许输入。

**备注：** 如果你指定了 `minlength` 但未指定 `required`，则输入被视为有效，因为不需要用户指定值。

### 指定模式

可以使用 `pattern` 属性指定输入值必须匹配才能被认为是有效的正则表达式（请参照以正则表达式验证 (en-US)）。

下面的示例将值限制为 4-8 个字符，并要求该值仅包含小写字母。

```html
<form>
  <div>
    <label for="uname">输入一个用户名：</label>
    <input
 type="text"
 id="uname"
 name="name"
 required
 size="45"
 pattern="[a-z]{4,8}" />
    <span class="validity"></span>
    <p>用户名必须为 4-8 位长，且仅包含小写字母。</p>
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

```
div {
  margin-bottom: 10px;
  position: relative;
}

p {
  font-size: 80%;
  color: #999;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
}
```

如下所示：

示例
--

可以在你的第一个 HTML 表单和如何结构化 HTML 表单文章中看到一些好的示例。

规范
--

| Specification |
| --- |
| HTML Standard # text-(type=text)-state-and-search-state-(type=search) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参阅
--

* HTML 表单
* `<input>` 元素和其基于的接口 `HTMLInputElement`
* `<input type="search">`
* `<textarea>`：多行文本输入元素
* CSS 属性兼容性表格


<input type="email"> - HTML（超文本标记语言）

<input type="email">
====================

**`"email"`** 类型的 `<input>` 元素能够让用户输入或编辑一个电子邮箱地址，如果指定了 `multiple` (en-US) 属性，则可以输入多个电子邮箱地址。

尝试一下
----

在表单提交前，输入框会自动验证输入值是否是一个或多个合法的电子邮箱地址（非空值且符合电子邮箱地址格式）。CSS 伪标签 `:valid` 和 `:invalid` 能够在校验后自动应用，代表被校验的邮箱地址是否合法。

值
-

`<input>` 元素的 `value` 属性包含会自动验证是否为正确邮件地址形式的字符串。具体来说，此处有三种格式可以通过验证：

1. 一个空字符串（“”），表示用户未输入值或该值已被删除。
2. 单个符合格式的电子邮件地址。并不代表该邮件地址存在，而是说它至少在格式上是正确的，简单地讲就是 `username@domain` 或者 `username@domain.tld`，当然并不局限于此，关于匹配电子邮件地址验证算法的正则表达式，参见验证一节。
3. 当且仅当指定了 `multiple` 属性时，值可以是一个列表，该列表包含一串符合格式的电子邮件地址，且每个地址之间用逗号分隔。列表中，位于每个地址之前和之后的任何空白字符都会被移除。

关于如何验证电子邮件地址以保证其格式正确的细节，参见验证一节。

额外属性
----

除了所有 `<input>` 元素支持的属性以外，`email` 输入还支持以下属性：

### list

list 属性指定了一个 `<datalist>` 元素的 `id`，用来提供输入建议。`<datalist>` 提供了一个预定义的值列表，向用户建议这个输入。列表中任何与 `type` 不兼容的值都不包括在建议选项中。所提供的值是建议，不是要求：用户可以从这个预定义的列表中选择，或者提供不同的值。

### maxlength

用户可以输入到 `email` 输入框中的最大字符数（以 UTF-16 代码单元为单位）。必须为大于等于 0 的整数。如果未指定 `maxlength` 或指定了无效的值，则 `email` 输入框将没有最大长度。这个值也必须大于等于 `minlength` 的值。

如果文本框中的字符数大于 `maxlength` UTF-16 编码单元长度，则输入将无法通过约束验证。约束验证仅作用于用户修改输入值的时候。

### minlength

用户可以输入到 `email` 输入框中的最小字符数（以 UTF-16 代码单元为单位）。该值必须是小于等于 `maxlength` 指定的值的非负整数值。如果未指定 `minlength` 或指定了无效的值，则 `email` 输入将没有最小长度。

如果输入到字段中的文本的长度小于 `minlength` UTF-16 代码单元的长度，则输入将无法通过约束验证。约束验证仅作用于用户修改输入值的时候。

### multiple

一个布尔属性，如果存在，代表用户可以输入多个由逗号和可选空白字符分开的电子邮件地址。参见示例允许多个邮件地址，或 HTML 属性：multiple (en-US) 一文以获取更多信息。

**备注：** 一般地，如果你指定了 `required` 属性，那么用户将必须输入一个合法的邮件地址。然而，如果你添加了 `multiple` 属性，一系列零地址（一个空字符串，或完全为空白字符的字符串）也是合法的。也就是说，当指定了 `multiple` 时，用户甚至不需要输入一个邮件地址，无论是否指定了 `required`。

### pattern

如果指定了 `pattern` 属性，为了使 `value` 通过约束验证，必须满足该属性给定的正则表达式。它必须是 `RegExp` 类型的有效 JavaScript 正则表达式，并且已在我们的正则表达式指南中进行了说明；在编译正则表达式时指定了 `'u'` 标志，因此该模式被视为 Unicode 代码点的序列，而不是 ASCII。模式文本周围无需指定正斜杠。

如果没有指定模式，或指定了无效的模式，则不会应用任何正则表达式，且该属性将被完全忽略。

**备注：** 使用 `title` 属性来指定大多数浏览器将作为工具提示的文本，以解释匹配该模式的要求是什么。还应该在附近包括其他解释性的文本。

参阅模式验证一节以获取详细说明和示例。

### placeholder

`placeholder` 属性是一个字符串，可向用户提供有关该字段中需要什么样的信息的简短提示。它应该是一个单词或短语来说明预期的数据类型，而不是说明性消息。文本中*不得*包含回车符或换行符。

如果控件的内容具有方向（LTR 或 RTL），但需要以相反的方向显示占位符，则可以使用 Unicode 双向算法来格式化字符，从而覆盖原有占位符的方向；请参见如何针对双向文本使用 Unicode 控制符获取更多信息。

**备注：** 尽可能避免使用 `placeholder` 属性。它在语义上没有其他解释表单的方式有用，并且可能导致内容出现意外的问题。请参见 `<input>` 标签以获取更多信息。

### readonly

一个布尔属性，如果存在，则表示该字段不能由用户编辑。但是，仍可以通过 JavaScript 代码直接设置 `HTMLInputElement` 的 `value` 属性来更改。

**备注：** 因为只读字段不能有值，所以 `required` 对指定了 `readonly` 属性的输入没有任何影响。

### size

`size` 属性是一个数字值，指示输入字段应有多少个字符宽。该值必须是一个大于零的数字，默认值是 20。由于字符宽度各不相同，这可能是也可能不是精确的，不应依赖于此；结果输入可能比指定的字符数更窄或更宽，这取决于字符和字体（`font` 使用中的设置）。

这并*不*限制用户可以在该字段中输入多少个字符，仅能指定一次可以看到多少个。要设置输入数据长度的上限，请使用 `maxlength` 属性。

使用 email 输入
-----------

电子邮件地址是网络上最经常输入的文本数据形式之一；它们被用于登录网站、请求信息、允许订单确认、网络邮件等等。因此，`email` 输入类型可以使你作为一个网络开发者的工作变得更加容易，因为它可以帮助你在建立用户界面和电子邮件地址的逻辑时简化工作。当你用适当的 `type` 值创建一个电子邮件输入时，你会得到自动验证，即输入的文本至少是正确的形式，可能是一个合法的电子邮件地址。这可以帮助避免用户错误输入他们的地址，或提供一个无效的地址。

然而，重要的是要注意，这不足以确保指定的文本是实际存在的电子邮件地址，对应于站点的用户，或者以任何其他方式可接受。它只是确保将字段的值正确格式化为电子邮件地址。

**备注：** 记住用户可以在幕后修改 HTML 也很重要，因此你的站点*不得*出于任何安全目的使用此验证。在任何事务中，如果所提供的文本可能有任何形式的安全影响，你必须在服务器端验证该电子邮件地址。

### 一个简单的 email 输入

目前，所有实现此元素的浏览器都将其实现为具有基本验证功能的标准文本输入字段。但是，该规范允许浏览器有一定的自由度。例如，该元素可以与用户设备的内置地址簿集成，以允许从该列表中挑选电子邮件地址。在最基本的形式中，电子邮件输入可以像这样实现：

```html
<input id="emailAddress" type="email" />
```

请注意，在空的时候和输入一个有效格式的电子邮件地址的时候，它被认为是有效的，但在其他情况下，则不被认为是有效的。通过添加 `required` 属性，只允许输入有效格式的电子邮件地址；当输入为空时不再被视为有效。

### 允许多个邮件地址

通过添加 `multiple` 布尔属性，输入框可以接受多个邮件地址。

```html
<input id="emailAddress" type="email" multiple />
```

现在，当输入一个电子邮件地址时，或当任何数量的电子邮件地址由逗号分隔，并可选地含有空白字符时，输入被认为是有效的。

**备注：** 当使用了 `multiple` 属性时，值*允许*为空。

当指定了 `multiple` 属性时，一些有效字符串示例如下：

* `""`
* `"me@example"`
* `"me@example.org"`
* `"me@example.org,you@example.org"`
* `"me@example.org, you@example.org"`
* `"me@example.org,you@example.org, us@example.org"`

一些无效字符串示例如下：

* `","`
* `"me"`
* `"me@example.org you@example.org"`
### 占位符

有时，提供一个上下文提示，说明输入数据应该采取什么形式，是很有帮助的。如果页面设计没有为每个 `<input>` 提供描述性的标签，这一点就特别重要。这就是**占位符**的作用。占位符是一个值，它通过展示一个有效值的例子来证明 `value` 应该采取的形式，当元素的 `value` 为 "" 时，它将显示在编辑框内。一旦数据被输入框中，占位符就会消失；如果框被清空，占位符会重新出现。

这里，我们有一个含有占位符 `sophie@example.com` 的 `email` 输入框。请注意在改变编辑框的内容时占位符如何消失和重新出现。

```html
<input type="email" placeholder="sophie@example.com" />
```

### 控制输入框大小

不仅可以控制输入框的物理长度，还可以控制输入文本本身允许的最小和最大长度。

#### 输入框物理大小

输入框的物理尺寸可以用 `size` 属性来控制。通过它，你可以指定输入框一次可以显示的字符数。在这个例子中，`email` 编辑框有 15 个字符宽：

```html
<input type="email" size="15" />
```

#### 元素值的长度

`size` 与输入的电子邮件地址本身的长度限制是分开的，所以你可以让字段在一个小空间里适应，同时仍然允许输入更长的电子邮件地址字符串。你可以使用 `minlength` 属性为输入的电子邮件地址指定一个最小长度，以字符为单位；同样，使用 `maxlength` 来设置输入电子邮件地址的最大长度。

下面的例子创建了一个 32 个字符宽的电子邮件地址输入框，要求内容不能短于 3 个字符，不能长于 64 个字符。

```html
<input type="email" size="32" minlength="3" maxlength="64" />
```

### 提供默认选项

#### 使用 value 属性提供单个默认值

像往常一样，你可以通过设置 `value` 属性，为 `email` 输入框提供一个默认值：

```html
<input type="email" value="default@example.com" />
```

#### 提供推荐值列表

再进一步，你可以提供一个默认选项的列表，用户可以通过指定 `list` 属性从中选择。这并不限制用户使用这些选项，但可以让他们更快地选择常用的电子邮件地址。这也为 `autocomplete` 提供提示。`list` 属性指定了 `<datalist>` 的 ID，它又包含了每个建议值的一个 `<option>` 元素；每个 `option` 的 `value` 是电子邮件输入框的对应建议值。

```html
<input type="email" size="40" list="defaultEmails" />

<datalist id="defaultEmails">
  <option value="jbond007@mi6.defence.gov.uk"></option>
  <option value="jbourne@unknown.net"></option>
  <option value="nfury@shield.org"></option>
  <option value="tony@starkindustries.com"></option>
  <option value="hulk@grrrrrrrr.arg"></option>
</datalist>
```

有了 `<datalist>` 元素及其 `<option>`，浏览器将提供指定的值作为电子邮件地址的潜在值；这通常以弹出式或下拉式菜单的形式呈现，其中包含建议。虽然具体的用户体验可能因浏览器而异，但通常情况下，点击编辑框就会出现建议的电子邮件地址的下拉菜单。然后，当用户输入时，该列表被过滤，只显示匹配的值。每个键入的字符都会缩小列表的范围，直到用户做出选择或键入一个自定义值。

验证
--

`email` 输入有两个级别的内容验证。首先，所有 `<input>` 都有标准的验证级别，它自动确保内容符合有效电子邮件地址的要求。但也可以选择添加额外的过滤功能，以确保满足你自己的特殊需求。

**警告：** HTML 表单验证*不能*替代确保输入的数据格式正确的脚本。对于某些人来说，调整 HTML 非常容易，因为它允许他们绕过验证，或者完全删除它。某人也可以完全绕过 HTML 并将数据直接提交给你的服务器。如果服务器端代码无法验证它收到的数据，则当数据格式不正确（或数据太大，类型错误等等）输入数据库时，灾难可能会发生。

### 基本验证

浏览器自动提供验证，以确保只有符合互联网电子邮件地址标准格式的文本被输入到输入框。浏览器使用一种相当于以下正则表达式的算法：

```js
/^[a-zA-Z0-9.!#$%&'\*+/=?^\_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)\*$/;
```

要了解更多关于表单验证的工作原理，以及如何利用 `:valid` 和 `:invalid` 这两个 CSS 属性，根据当前值是否有效来设计输入的样式，请参阅表单数据验证 (en-US)一文。

**备注：** 有一些已知的规范问题与国际域名和 HTML 中电子邮件地址的验证有关。参阅 W3C bug 15489 以了解详细内容。

### 模式验证

如果你需要进一步限制输入的邮件地址，不仅仅需要“任何看起来像邮件地址的字符串”，你可以使用 `pattern` 属性来指定一个正则表达式，该值必须与之匹配才有效。如果指定了 `multiple` 属性，每个由逗号分开的值必须满足该正则表达式。

例如，假设你正在为 Best Startup Ever, Inc. 公司的员工建立一个支持页面，如果他们的某个页面出现问题，他们可以联系 IT 部门寻求帮助。在我们的简化表单中，用户需要输入出现他们的邮箱地址，以及描述遇到的问题。为了安全起见，我们希望用户不仅提供了有效的邮箱地址，而且还是一个内部邮件地址。

由于 `email` 类型的输入会对标准邮箱地址*和*自定义 `pattern` 同时进行校验，你可以很方便地实现这些。我们来看看如何这样做：

```html
<form>
  <div class="emailBox">
    <label for="emailAddress">你的邮箱地址</label><br />
    <input
 id="emailAddress"
 type="email"
 size="64"
 maxlength="64"
 required
 placeholder="username@beststartupever.com"
 pattern=".+@beststartupever\.com"
 title="请仅提供 Best Startup Ever 公司邮件地址" />
  </div>

  <div class="messageBox">
    <label for="message">请求</label><br />
    <textarea
 id="message"
 cols="80"
 rows="8"
 required
 placeholder="我的鞋子太紧了，而且我忘记如何跳舞了。"></textarea>
  </div>
  <input type="submit" value="发送请求" />
</form>
```

我们的 `<form>` 表单包含一个 `email` 类型的 `<input>`，用于用户电子邮件地址，一个 `<textarea>`，用来输入他们的 IT 信息，以及一个 `<input>` 类型为 `"submit"` 的按钮，用来创建一个提交表单。每个文本输入框都有一个 `<label>` 与之相关，让用户知道对他们的期望。

让我们仔细看看电子邮件地址输入框。它的 `size` 和 `maxlength` 属性都被设置为 64，以便为 64 个字符的电子邮件地址提供空间，并将实际输入的字符数限制在最大 64 个。这里还指定了 `required` 属性，使得用户必须提供一个有效的电子邮件地址。

表单中提供了一个适当的 `placeholder`——`username@beststartupever.com`，以证明什么是有效的条目。这个字符串表明，应该输入一个电子邮件地址，并建议它应该是一个企业的 beststartupever.com 账户。此外，使用 `email` 类型将验证文本以确保它的格式像一个电子邮件地址。如果输入框中的文本不是电子邮件地址，你会得到一个错误信息，看起来像这样：

![Invalid email address in error state with a popout from the input reading 'please enter an email address'.](/zh-CN/docs/Web/HTML/Element/input/email/enter-valid-email-address.png)

如果我们让事情停留在这个阶段，我们至少会在合法的电子邮件地址上进行验证。但我们想走得更远：我们想确保电子邮件地址实际上是“\_username\_@beststartupever.com”的形式。这就是我们要使用 `pattern` 的地方。我们将 `pattern` 设置为 `.+@beststartupever.com`。这个简单的正则表达式要求一个至少由一个任何类型的字符组成的字符串，然后是“@”，后面是域名“beststartupever.com”。

请注意，这根本不是一个有效的电子邮件地址过滤器；它允许诸如“ @beststartupever.com”（注意前面的空格）或“@@beststartupever.com”这样的内容，它们都是无效的。然而，浏览器对指定的文本同时运行标准的电子邮件地址过滤器*和*我们的自定义模式。结果，我们的验证结果是：“确保这类似于一个有效的电子邮件地址，如果是的话，确保它也是一个 beststartupever.com 的地址。”

建议在使用 `pattern` 属性的同时使用 `title`。如果你这样做，`title` *必须*描述该模式。也就是说，它应该解释数据应该采取什么格式，而不是任何其他信息。这是因为 `title` 可以作为验证错误信息的一部分被显示或说出。例如，浏览器可能会显示“输入的文本不符合要求的模式。”，随后是你指定的 `title`。如果你的 `title` 是类似于“Email address”的字符串，结果将是“输入的文本不符合要求的模式。Email address”，这不太通顺。

这就是为什么我们指定字符串“请只提供 Best Startup Ever 公司的电子邮件地址”。通过这样做，所产生的完整错误信息可能是这样的：“输入的文本不符合要求的模式。请只提供 Best Startup Ever 公司的电子邮件地址”。

![A valid email address, but the input is in error state with a popout from the input reading 'The entered text doesn't match the required pattern. Please provide only a Best Startup Ever corporate email address.'](/zh-CN/docs/Web/HTML/Element/input/email/email-pattern-match-bad.png)

**备注：** 如果你在编写验证正则表达式时遇到麻烦，它们不能正常工作，请检查你的浏览器控制台；那里可能有有用的错误信息来帮助你解决问题。

示例
--

这里我们有一个 ID 为 `emailAddress` 的电子邮件输入框，它最多可以有 256 个字符长。输入框本身的宽度为 64 个字符，并在字段为空时显示文本 `user@example.gov` 作为占位符。此外，通过使用`multiple` (en-US)属性，该框被配置为允许用户输入零个或多个电子邮件地址，用逗号分隔，如允许多个电子邮件地址中所述。最后，`list` 属性包含一个 `<datalist>` 的 ID，其 `<option>` 指定一组建议值，供用户选择。

作为补充，`<label>` 元素被用来为电子邮件输入框建立一个标签，其 `for` 属性引用了 `<input>` 元素的 `emailAddress` ID。通过这种方式将这两个元素联系起来，点击标签将聚焦输入元素。

```html
<label for="emailAddress">电子邮件</label><br />
<input
 id="emailAddress"
 type="email"
 placeholder="user@example.gov"
 list="defaultEmails"
 size="64"
 maxlength="256"
 multiple />

<datalist id="defaultEmails">
  <option value="jbond007@mi6.defence.gov.uk"></option>
  <option value="jbourne@unknown.net"></option>
  <option value="nfury@shield.org"></option>
  <option value="tony@starkindustries.com"></option>
  <option value="hulk@grrrrrrrr.arg"></option>
</datalist>
```

技术总结
----

|  |  |
| --- | --- |
| **值** | 代表电子邮件地址的字符串，或为空 |
| **事件** | `change` 和
 `input` |
| **支持的通用属性** | `autocomplete`、`list`、`maxlength`、`minlength`、`multiple`、`name`、`pattern`、`placeholder`、`readonly`、`required`、`size` 和 `type` |
| **IDL 属性** | `list` 和 `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()` |

规范
--

| Specification |
| --- |
| HTML Standard # email-state-(type=email) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* HTML 表单指南
* `<input>`
* `<input type="tel">`
* `<input type="url">`
* 属性：
    + `list`
    + `minlength` (en-US)
    + `maxlength` (en-US)
    + `multiple` (en-US)
    + `pattern`
    + `placeholder` (en-US)
    + `readonly`
    + `size` (en-US)
* CSS 属性兼容性列表


<input type="checkbox"> - HTML（超文本标记语言）

<input type="checkbox">
=======================

**`checkbox`** 类型的 `<input>` 元素在默认情况下被呈现为激活时被选中（打勾）的方框，就像你在官方的政府文件表格中看到的那样。具体外观取决于浏览器运行的操作系统配置。一般来说，这是一个正方形，但它可能有圆角。复选框允许你在表格中选择单一的数值进行提交（或不提交）。

尝试一下
----

**备注：** 单选按钮与复选框类似，但有一个重要的区别——单选按钮被分组为一个集合，一次只能选择一个单选按钮；而复选框允许你选中/取消选中单个值。如果存在多个控件，单选按钮允许从它们中选择一个，而复选框则允许选择多个值。

|  |  |
| --- | --- |
| **值** | 一个代表该复选框值的字符串。 |
| **事件** | `change` 和 `input` |
| **支持的常用属性** | `checked` |
| **IDL 属性** | `checked`、`indeterminate` 和
 `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()` |

值
-

一个字符串，代表复选框的值。在客户端不显示，但在服务器上对应了给予该复选框的 `name` 的 `value` 值。以下面的例子为例：

```html
<form>
  <div>
    <input
 type="checkbox"
 id="subscribeNews"
 name="subscribe"
 value="newsletter" />
    <label for="subscribeNews">要订阅报纸吗？</label>
  </div>
  <div>
    <button type="submit">订阅</button>
  </div>
</form>
```

在这个例子中，我们的 `subscribe` 下具有的值为 `newsletter`。当表单被提交时，数据的键值对将是 `subscribe=newsletter`。

如果复选框的 `value` 属性被省略了，则它默认具有值 `on`，在这种情况下提交的数据将是 `subscribe=on`。

**备注：** 如果一个复选框在其表单被提交时没有被选中，就不会有任何代表其未被选中的状态（例如 `value=unchecked`）的值被提交给服务器——该值根本就没有被提交给服务器！如果你想在复选框未被选中时提交一个默认值，你可以在表单中加入一个具有相同的 `name` 和 `value` 的 <input type="hidden"> 字段，它可以由 JavaScript 生成。

其他属性
----

除了 `<input>` 元素共有的属性外，`checkbox` 还支持以下属性：

`checked`

一个布尔属性，表示该复选框是否被默认选中（当页面加载时）。它不表示这个复选框当前是否被选中：如果复选框的状态被改变，这个内容属性不反映这个变化。此时，只有 `HTMLInputElement` 的 IDL 属性 `checked` 会更新。

**备注：** 与其他输入控件不同，复选框的值只有在复选框当前状态为 `checked` 时才会被包含在提交的数据中。如果它被选中，那么复选框的 `value` 属性的值就会被报告为输入的值。不像其他浏览器那样，Firefox 默认情况下在不同页面之间会保持 `<input>` 动态选中的状态。请使用 `autocomplete` 属性来控制这个特性。

`value`

所有的 `<input>` 元素都有 `value` 属性；但是，它对 `checkbox` 类型的输入有特殊作用：当表单被提交时，只有当前被选中的复选框会被提交给服务器，报告的值就是 `value` 属性的值。如果没有指定 `value`，默认为字符串 `on`。这在上面的值部分有阐述。

使用复选框输入
-------

我们已经介绍了复选框的最基本用途。现在让我们看看需要掌握的其他与复选框有关的常见功能和技术。

### 处理多个复选框

我们在上面看到的例子只包含一个复选框；在现实世界中，你可能会遇到多个复选框。如果它们完全不相关，那么你可以如上所示，分别处理它们。但是，如果它们都是相关的，事情就没那么容易了。

例如，在下面的演示中，我们包括多个复选框，让用户选择他们的兴趣（见示例部分的完整版本）。

```html
<fieldset>
  <legend>选择你的兴趣</legend>
  <div>
    <input type="checkbox" id="coding" name="interest" value="coding" />
    <label for="coding">编码</label>
  </div>
  <div>
    <input type="checkbox" id="music" name="interest" value="music" />
    <label for="music">音乐</label>
  </div>
</fieldset>
```

在这个例子中，你会看到我们给每个复选框赋予了相同的 `name`。如果两个复选框都被选中，然后提交表单，你会得到这样一串键/值对：`interest=coding&interest=music`。当这个字符串到达服务器时，你需要把它解析成一个关联数组以外的东西，`interest` 的所有值都需要被捕获。有关 Python 使用的一种技术，参见用一个服务器端变量处理多个复选框。

### 默认选中复选框

为了让复选框默认为选中状态，需要给它赋予 `checked` 属性。见如下例子：

```html
<fieldset>
  <legend>选择你的兴趣</legend>
  <div>
    <input type="checkbox" id="coding" name="interest" value="coding" checked />
    <label for="coding">编码</label>
  </div>
  <div>
    <input type="checkbox" id="music" name="interest" value="music" />
    <label for="music">音乐</label>
  </div>
</fieldset>
```

### 为复选框提供稍大的点击区域

在上面的例子中，你可能已经注意到，你可以通过点击复选框相关的 `<label>` 元素以及复选框本身来切换复选框的状态。这是 HTML 表单标签的一个非常有用的功能，使你更容易点击你想要的选项，特别是在智能手机等小屏幕设备上。

除了无障碍之外，这也是在表单上正确设置 `<label>` 元素的另外一个理由。

### 中间状态复选框

除了选中和未选中的状态外，复选框还有第三种状态：**不确定**。这是一种无法说清该选项是被打开还是关闭的状态。这是通过 JavaScript 设置的 `HTMLInputElement` 对象的 `indeterminate` 属性（它不能用 HTML 属性设置）。

```js
inputInstance.indeterminate = true;
```

在大多数浏览器中，处于不确定状态的复选框在框中有一条横线（看起来有点像连字符或减号），而不是一个对勾。

这个属性的使用情况不多。最常见的是当一个复选框“拥有”一些子选项（也是复选框）的时候。如果所有的子选项都被选中，拥有的复选框也被选中，如果它们都没有被选中，拥有的复选框就没有被选中。如果任何一个或多个子选项的状态与其他选项不同，拥有的复选框就处于不确定的状态。

这可以在下面的例子中看到（感谢 CSS Tricks 提供的灵感）。在这个例子中，我们记录了为一个配方收集的原料。当你勾选或不勾选一个原料的复选框时，一个 JavaScript 函数会检查勾选的原料总数：

* 如果没有一项被选中，配方名称的复选框是未选中状态。
* 如果选中了一项或两项，配方名称的复选框是 `indeterminate`（中间）状态。
* 如果选中了全部三项，配方名称的复选框是 `checked`（已选中）状态。

在这种情况下，`indeterminate` 状态用来说明已经开始收集原料，但配方还没有完成。

```js
const overall = document.querySelector("#enchantment");
const ingredients = document.querySelectorAll("ul input");

overall.addEventListener("click", (e) => {
  e.preventDefault();
});

for (const ingredient of ingredients) {
  ingredient.addEventListener("click", updateDisplay);
}

function updateDisplay() {
  let checkedCount = 0;
  for (const ingredient of ingredients) {
    if (ingredient.checked) {
      checkedCount++;
    }
  }

  if (checkedCount === 0) {
    overall.checked = false;
    overall.indeterminate = false;
  } else if (checkedCount === ingredients.length) {
    overall.checked = true;
    overall.indeterminate = false;
  } else {
    overall.checked = false;
    overall.indeterminate = true;
  }
}
```

**备注：** 如果你提交一个带有不确定复选框的表单，发生的情况与复选框不被选中的情况相同——没有代表复选框的数据提交给服务器。

验证方式
----

复选框支持提供给所有 `<input>` 元素的验证功能。然而，大部分的 `ValidityState` 值将永远为 `false`。如果复选框具有 `required` 属性，但没有被选中，那么 `ValidityState.valueMissing` (en-US) 将为 `true`。

示例
--

下面的例子是我们在上面看到的“多个复选框”例子的扩展版本——它有更多的标准选项，还有一个“其他”复选框，当被选中时，会出现一个文本字段来输入“其他”选项的值。这是用一些简单的 JavaScript 代码实现的。这个例子还包括一些 CSS 来改善样式。

### HTML

```html
<form>
  <fieldset>
    <legend>选择你的兴趣</legend>
    <div>
      <input type="checkbox" id="coding" name="interest" value="coding" />
      <label for="coding">编码</label>
    </div>
    <div>
      <input type="checkbox" id="music" name="interest" value="music" />
      <label for="music">音乐</label>
    </div>
    <div>
      <input type="checkbox" id="art" name="interest" value="art" />
      <label for="art">艺术</label>
    </div>
    <div>
      <input type="checkbox" id="sports" name="interest" value="sports" />
      <label for="sports">体育</label>
    </div>
    <div>
      <input type="checkbox" id="cooking" name="interest" value="cooking" />
      <label for="cooking">烹饪</label>
    </div>
    <div>
      <input type="checkbox" id="other" name="interest" value="other" />
      <label for="other">其他</label>
      <input type="text" id="otherValue" name="other" />
    </div>
    <div>
      <button type="submit">提交表单</button>
    </div>
  </fieldset>
</form>
```

### CSS

```css
html {
  font-family: sans-serif;
}

form {
  width: 600px;
  margin: 0 auto;
}

div {
  margin-bottom: 10px;
}

fieldset {
  background: cyan;
  border: 5px solid blue;
}

legend {
  padding: 10px;
  background: blue;
  color: cyan;
}
```

### JavaScript

```js
const otherCheckbox = document.querySelector("#other");
const otherText = document.querySelector("#otherValue");
otherText.style.visibility = "hidden";

otherCheckbox.addEventListener("change", () => {
  if (otherCheckbox.checked) {
    otherText.style.visibility = "visible";
    otherText.value = "";
  } else {
    otherText.style.visibility = "hidden";
  }
});
```

规范
--

| Specification |
| --- |
| HTML Standard # checkbox-state-(type=checkbox) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 通用 `<input>` 元素和用于操作该元素的接口 `HTMLInputElement`
* 基于当前状态的 `:checked` 和 `:indeterminate` CSS 选择器，可供赋予样式
* 表单控件 CSS 兼容性列表


<input type="file"> - HTML（超文本标记语言）

<input type="file">
===================

带有 **`type="file"`** 的 `<input>` 元素允许用户可以从他们的设备中选择一个或多个文件。选择后，这些文件可以使用提交表单的方式上传到服务器上，或者通过 Javascript 代码和文件 API 对文件进行操作。

尝试一下
----

|  |  |
| --- | --- |
| **值** | 表示已选择文件的路径字符串 |
| **事件** | `change` 和 `input` |
| **支持的公共属性** | `required` |
| **附加属性** | `accept`、`capture` 和 `multiple` |
| **IDL 属性** | `files` 和 `value` |
| **DOM 接口** | `HTMLInputElement` |
| **方法** | `select()` |

值
-

文件 input 的 `value` 属性包含了一个字符串，表示已选择文件的路径。如果用户没有选择任何文件，则该值为空字符串（`""`）。如果用户选择了多个文件，则 `value` 表示他们选择的文件列表中的第一个文件。可以使用 input 的 `HTMLInputElement.files` 属性标识其他文件。

**备注：** 为了阻止恶意软件猜测文件路径，该值的字符串表示总是以 `C:\fakepath\` 为前缀的文件名，而并不是文件的真实路径。

附加属性
----

除了被所有 `<input>` 元素共享的公共属性，`file` 类型的 input 还支持下列属性：

### accept

`accept` (en-US) 属性是一个字符串，它定义了文件 input 应该接受的文件类型。这个字符串是一个以逗号为分隔的**唯一文件类型说明符**列表。由于给定的文件类型可以用多种方式指定，因此当你需要给定格式的文件时，提供一组完整的类型指定符是非常有用的。

例如，可以通过多种方式识别 Microsoft Word 文件，因此接受 Word 文件的网站可能使用像这样的 `<input>`：

```html
<input
 type="file"
 id="docpicker"
 accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
```

### capture

`capture` (en-US) 属性是一个字符串，如果 `accept` (en-US) 属性指出了 input 是图片或者视频类型，则它指定了使用哪个摄像头去获取这些数据。值 `user` 表示应该使用前置摄像头和（或）麦克风。值 `environment` 表示应该使用后置摄像头和（或）麦克风。如果缺少此属性，则用户代理可以自由决定做什么。如果请求的前置模式不可用，则用户代理可能退回到其首选的默认模式。

**备注：** `capture` 以前是一个布尔类型的属性，如果存在，则请求使用设备的媒体捕获设备（如：摄像机），而不是请求一个文件输入。

### multiple

当指定布尔类型属性 `multiple` (en-US) 时，文件 input 允许用户选择多个文件。

非标准属性
-----

除了上面列出来的属性，下面的非标准属性在某些浏览器中可用。应该尽量避免使用它们，因为这样做将限制代码在没有实现它们的浏览器中的运行能力。

### `webkitdirectory`

如果出现布尔属性 `webkitdirectory`，表示在文件选择器界面中用户只能选择目录。更多细节和示例见 `HTMLInputElement.webkitdirectory`。

尽管 `webkitdirectory` 最初仅为基于 Webkit 的浏览器实现，它还在 Microsoft Edge 和 Firefox 50 及其后版本中可用。然而，尽管它有相对广泛的支持，它仍然是非标准的。除非别无选择，否则不要使用它。

唯一文件类型说明符
---------

**唯一文件类型说明符**是一个字符串，表示在 `file` 类型的 `<input>` 元素中用户可以选择的文件类型。每个唯一文件类型说明符可以采用下列形式之一：

* 一个以英文句号（“.”）开头的合法的不区分大小写的文件名扩展名。例如：`.jpg`、`.pdf` 或 `.doc`。
* 一个不带扩展名的 MIME 类型字符串。
* 字符串 `audio/*`，表示“任何音频文件”。
* 字符串 `video/*`，表示“任何视频文件”。
* 字符串 `image/*`，表示“任何图片文件”。

`accept` 属性的值是包含一个或多个（用逗号分隔）唯一文件类型说明符的字符串。例如，一个文件选择器需要能被表示成一张图片的内容，包括标准的图片格式和 PDF 文件，大概是这样的：

```html
<input type="file" accept="image/\*,.pdf" />
```

使用文件输入
------

### 基本示例

```html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="file">选择要上传的文件</label>
    <input type="file" id="file" name="file" multiple />
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

```
div {
  margin-bottom: 10px;
}
```

产生如下结果：

**备注：** 你也可以在 GitHub 中找到这个示例——详见源代码和在线运行实例。

无论用户的设备或操作系统是什么，文件输入都提供一个按钮，打开一个允许用户选择文件的文件选择对话框。

通过包含上述的 `multiple` 属性，可以指定一次选择多个文件。用户可以用他们选择的平台允许的任何方式从文件选择器中选择多个文件（如按住 `Shift` 或 `Control`，然后单击）。如果只想让用户为每个 `<input>` 选择一个文件，那么省略 `multiple` 属性。

### 获取已选择文件的信息

被选择的文件以 `HTMLInputElement.files` 属性返回，它是包含一系列 `File` 对象的 `FileList` 对象。`FileList` 的行为像一个数组，可以通过检查 `length` 属性来获得已选择文件的数量。

每个 `File` 包含下列信息：

`name`

文件名。

`lastModified`

一个数字，指定文件最后一次修改的日期和时间，以 UNIX 新纪元（1970 年 1 月 1 日午夜）以来的毫秒数表示。

`lastModifiedDate`
已弃用

一个 `Date` 对象，表示文件最后一次修改的日期和时间。*这被弃用，并且不应使用。使用 `lastModified` 作为替代。*

`size`

以字节数为单位的文件大小。

`type`

文件的 MIME 类型。

`webkitRelativePath`
非标准

一个字符串，指定了相对于在目录选择器中选择的基本目录的文件路径（即，一个设置了 `webkitdirectory` 属性的 `file` 选择器）。*这是非标准的，应该谨慎使用。*

**备注：** 你可以在所有现代浏览器中读写 `HTMLInputElement.files` 的值；该特性已经添加到了 Firefox 57 中（见 Firefox bug 1384030）。

### 限制可接受的文件类型

通常，你不希望用户能够选择任意类型的文件；相反，你通常希望它们选择特定类型的文件。例如，如果你的文件输入让用户上传个人资料图片，你可能希望他们选择 Web 兼容的图像格式，如 JPEG 或 PNG。

可以用 `accept` 属性指定可接受的文件类型，它是一个以逗号间隔的文件扩展名和 MIME 类型列表。一些例子如下所示：

* `accept="image/png"` 或 `accept=".png"`——接受 PNG 文件。
* `accept="image/png, image/jpeg"` 或 `accept=".png, .jpg, .jpeg"`——接受 PNG 或 JPEG 文件。
* `accept="image/*"`——接受任何带有 `image/*` MIME 类型的文件。（许多移动设备也允许用户在使用它时用摄像头拍照。）
* `accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"`——接受类似于 MS Word 文档的任何文件。

让我们来看一个更完整的例子：

```html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="profile\_pic">选择要上传的文件</label>
    <input
 type="file"
 id="profile\_pic"
 name="profile\_pic"
 accept=".jpg, .jpeg, .png" />
  </div>
  <div>
    <button>提交</button>
  </div>
</form>
```

```
div {
  margin-bottom: 10px;
}
```

上述代码产生和之前示例相似的结果：

**备注：** 你也可以在 GitHub 中找到这个示例——详见源代码和在线运行实例。

这可能看起来很相似，但是如果你尝试用该输入选择一个文件，你将看到文件选择器只允许你选择 `accept` 值指定的文件类型（实际接口会按不同的浏览器和操作系统有所不同）。

`accept` 属性不验证所选文件的类型；它只是为浏览器提供提示来引导用户选择正确的文件类型。用户仍然可以（在大多数情况下）在文件选择器中切换一个选项，使其能够覆盖此选项并选择他们希望的任何文件，然后选择不正确的文件类型。

因此，应该确保 `accept` 属性得到适当的服务器端验证的支持。

### 注意事项

1. 不能从脚本中设置文件选取器的值——做下面这样的事情是没有效果的：

```js
const input = document.querySelector("input[type=file]");
input.value = "foo";
```

2. 当使用 `<input type="file">` 选择文件时，出于明显的安全原因，源文件的实际路径没有显示在 input 的 `value` 属性中。实际上显示了文件名，并用 `C:\fakepath\` 附加在路径的开头。这种怪癖有一些历史原因，但它在所有现代浏览器中都受到支持，而且实际上在规范中也有定义。
示例
--

在本例中，我们将展示一个稍微高级一点的文件选择器，它利用了在 `HTMLInputElement.files` 属性中可用的文件信息，并且展示了一些聪明的技巧。

**备注：** 你可以在 GitHub 中查看本示例的完整源代码——file-example.html（参见在线的运行实例）。我们不会解释 CSS；JavaScript 是主要的关注点。

首先，让我们看看 HTML：

```html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="image\_uploads">Choose images to upload (PNG, JPG)</label>
    <input
 type="file"
 id="image\_uploads"
 name="image\_uploads"
 accept=".jpg, .jpeg, .png"
 multiple />
  </div>
  <div class="preview">
    <p>No files currently selected for upload</p>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
```

```
html {
  font-family: sans-serif;
}

form {
  width: 580px;
  background: #ccc;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid black;
}

form ol {
  padding-left: 0;
}

form li,
div > p {
  background: #eee;
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
  list-style-type: none;
  border: 1px solid black;
}

form img {
  height: 64px;
  order: 1;
}

form p {
  line-height: 32px;
  padding-left: 10px;
}

form label,
form button {
  background-color: #7f9ccb;
  padding: 5px 10px;
  border-radius: 5px;
  border: 1px ridge black;
  font-size: 0.8rem;
  height: auto;
}

form label:hover,
form button:hover {
  background-color: #2d5ba3;
  color: white;
}

form label:active,
form button:active {
  background-color: #0d3f8f;
  color: white;
}
```

这和我们之前看到的类似，没有什么要说明的。

接下来，让我们看一下 JavaScript。

在脚本的第一行，我们获得了对表单 input 本身和拥有 `.preview` 类的 `<div>` 元素的引用。然后，我们隐藏了 `<input>` 元素，这样做是因为文件输入往往很难看，难于设计样式，而且在跨浏览器中对它们的设计不一致。你可以通过单击 `<label>` 部分来激活 `input` 元素，因此，最好在视觉上隐藏 `input` 并将 label 设计成按钮的样式，这样用户如果想上传文件就会知道如何与之交互。

```js
const input = document.querySelector("input");
const preview = document.querySelector(".preview");

input.style.opacity = 0;
```

**备注：** 使用 `opacity` 来隐藏文件输入，而不是使用 `visibility: hidden` 或者 `display: none`，因为辅助技术将后两种样式解释为文件 input 是不可交互的。

接下来，我们将事件监听器添加到 input 中，以监听选择的值的更改（在本例中，当选择文件时）。事件监听器调用我们定制的 `updateImageDisplay()` 函数。

```js
input.addEventListener("change", updateImageDisplay);
```

每当 `updateImageDisplay()` 函数被调用时，我们：

* 使用一个 `while` 循环来清空预览区 `<div>` 留下的内容。
* 获取包含所有已选择文件信息的 `FileList` 对象，并将其用一个变量 `curFiles` 保存。
* 通过检查 `curFiles.length` 是否等于 0 来检查是否没有文件被选择。如果是，则向预览区 `<div>` 输出一条消息，表示没有选择文件。
* 如果*选择*了文件，我们将循环遍历每个文件，并将关于它的信息输出到预览区 `<div>`。注意事项：
* 我们使用定制的 `validFileType()` 函数来检查文件的类型是否正确（例如，用 `accept` 属性指定的图片类型）。
* 如果是，我们：
    + 将其名称和文件大小输出到预览区 `<div>` 的一个列表项中（从 `file.name` 和 `file.size` 获取这些信息）。定制的 `returnFileSize()` 函数返回一个用 bytes/KB/MB 表示的可读性良好的文件大小（默认情况下，浏览器以绝对字节数报告大小）。
    + 通过调用 `URL.createObjectURL(curFiles[i])` 来生成图片的一张缩略预览图。然后，通过创建一个新的 `<img>` 来将这张图片也插入到列表项，并且将它的 `src` 设置为缩略图。
* 如果文件类型无效，则在列表项中显示一条消息，告诉用户需要选择一个其他的文件类型。

```js
function updateImageDisplay() {
  while (preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  const curFiles = input.files;
  if (curFiles.length === 0) {
    const para = document.createElement("p");
    para.textContent = "No files currently selected for upload";
    preview.appendChild(para);
  } else {
    const list = document.createElement("ol");
    preview.appendChild(list);

    for (const file of curFiles) {
      const listItem = document.createElement("li");
      const para = document.createElement("p");
      if (validFileType(file)) {
        para.textContent = `File name ${file.name}, file size ${returnFileSize(
 file.size,
 )}.`;
        const image = document.createElement("img");
        image.src = URL.createObjectURL(file);

        listItem.appendChild(image);
        listItem.appendChild(para);
      } else {
        para.textContent = `File name ${file.name}: Not a valid file type. Update your selection.`;
        listItem.appendChild(para);
      }

      list.appendChild(listItem);
    }
  }
}
```

定制的 `validFileType()` 函数接受一个 `File` 对象作为参数，然后使用 `Array.prototype.includes()` 检查 `fileTypes` 中是否有值和文件的 `type` 属性匹配。如果找到匹配项，函数返回 `true`。如果没找到，返回 `false`。

```js
// https://developer.mozilla.org/zh-CN/docs/Web/Media/Formats/Image\_types
const fileTypes = [
  "image/apng",
  "image/bmp",
  "image/gif",
  "image/jpeg",
  "image/pjpeg",
  "image/png",
  "image/svg+xml",
  "image/tiff",
  "image/webp",
  "image/x-icon",
];

function validFileType(file) {
  return fileTypes.includes(file.type);
}
```

`returnFileSize()` 函数接受一个数字（字节数，取自当前文件的 `size` 属性）作为参数，并且将其转化为用 bytes/KB/MB 表示的可读性良好的文件大小。

```js
function returnFileSize(number) {
  if (number < 1024) {
    return `${number} bytes`;
  } else if (number >= 1024 && number < 1048576) {
    return `${(number / 1024).toFixed(1)} KB`;
  } else if (number >= 1048576) {
    return `${(number / 1048576).toFixed(1)} MB`;
  }
}
```

这个例子是这样的；演示一下：

规范
--

| Specification |
| --- |
| HTML Standard # file-upload-state-(type=file) |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 在 web 应用中使用文件——包含许多其他关于 `<input type="file">` 和 File API 的有用示例。
* CSS 属性兼容性