<input type="file">

<input> 元素和 type="file" 允许用户从其设备存储中选择一个或多个文件。选择后,可以使用 表单提交 将文件上传到服务器,或使用 JavaScript 代码和 文件 API 进行操作。

¥<input> elements with type="file" let the user choose one or more files from their device storage. Once chosen, the files can be uploaded to a server using form submission, or manipulated using JavaScript code and the File API.

Try it

¥Value

文件输入的 value 属性包含一个表示所选文件路径的字符串。如果尚未选择文件,则该值为空字符串 ("")。当用户选择多个文件时,value 代表他们选择的文件列表中的第一个文件。其他文件可以使用 输入的 HTMLInputElement.files 属性

¥A file input's value attribute contains a string that represents the path to the selected file(s). If no file is selected yet, the value is an empty string (""). When the user selected multiple files, the value represents the first file in the list of files they selected. The other files can be identified using the input's HTMLInputElement.files property.

注意:该值为 文件名始终以 C:\fakepath\ 为前缀,不是文件的真实路径。这是为了防止恶意软件猜测用户的文件结构。

¥Note: The value is always the file's name prefixed with C:\fakepath\, which isn't the real path of the file. This is to prevent malicious software from guessing the user's file structure.

附加属性

¥Additional attributes

除了所有 <input> 元素共享的公共属性外,类型 file 的输入还支持以下属性。

¥In addition to the common attributes shared by all <input> elements, inputs of type file also support the following attributes.

accept

accept 属性值是一个字符串,定义文件输入应接受的文件类型。该字符串是 唯一的文件类型说明符 的逗号分隔列表。由于给定的文件类型可能以多种方式标识,因此当你需要给定格式的文件时,提供一组完整的类型说明符很有用。

¥The accept attribute value is a string that defines the file types the file input should accept. This string is a comma-separated list of unique file type specifiers. Because a given file type may be identified in more than one manner, it's useful to provide a thorough set of type specifiers when you need files of a given format.

例如,可以通过多种方式识别 Microsoft Word 文件,因此接受 Word 文件的站点可能会使用如下所示的 <input>

¥For instance, there are a number of ways Microsoft Word files can be identified, so a site that accepts Word files might use an <input> like this:

html
<input
  type="file"
  id="docpicker"
  accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />

capture

capture 属性值是一个字符串,如果 accept 属性指示输入应属于这些类型之一,则指定使用哪个相机来捕获图片或视频数据。值 user 表示应使用面向用户的摄像头和/或麦克风。值 environment 指定应使用朝外的摄像头和/或麦克风。如果缺少此属性,user agent 可以自由决定自己要做什么。如果所请求的面向模式不可用,则用户代理可能会回退到其首选的默认模式。

¥The capture attribute value is a string that specifies which camera to use for capture of image or video data, if the accept attribute indicates that the input should be of one of those types. A value of user indicates that the user-facing camera and/or microphone should be used. A value of environment specifies that the outward-facing camera and/or microphone should be used. If this attribute is missing, the user agent is free to decide on its own what to do. If the requested facing mode isn't available, the user agent may fall back to its preferred default mode.

注意:capture 以前是一个布尔属性,如果存在,则请求使用设备的媒体捕获设备(例如相机或麦克风),而不是请求文件输入。

¥Note: capture was previously a Boolean attribute which, if present, requested that the device's media capture device(s) such as camera or microphone be used instead of requesting a file input.

multiple

当指定 multiple 布尔属性时,文件输入允许用户选择多个文件。

¥When the multiple Boolean attribute is specified, the file input allows the user to select more than one file.

非标准属性

¥Non-standard attributes

除了上面列出的属性之外,某些浏览器还提供以下非标准属性。你应该尽可能避免使用它们,因为这样做会限制代码在未实现它们的浏览器中运行的能力。

¥In addition to the attributes listed above, the following non-standard attributes are available on some browsers. You should try to avoid using them when possible, since doing so will limit the ability of your code to function in browsers that don't implement them.

webkitdirectory

布尔值 webkitdirectory 属性(如果存在)指示用户在文件选择器界面中只能选择目录。有关更多详细信息和示例,请参阅 HTMLInputElement.webkitdirectory

¥The Boolean webkitdirectory attribute, if present, indicates that only directories should be available to be selected by the user in the file picker interface. See HTMLInputElement.webkitdirectory for additional details and examples.

尽管最初仅针对基于 WebKit 的浏览器实现,但 webkitdirectory 也可在 Microsoft Edge 以及 Firefox 50 及更高版本中使用。然而,尽管它有相对广泛的支持,但它仍然不是标准,除非你别无选择,否则不应使用。

¥Though originally implemented only for WebKit-based browsers, webkitdirectory is also usable in Microsoft Edge as well as Firefox 50 and later. However, even though it has relatively broad support, it is still not standard and should not be used unless you have no alternative.

独特的文件类型说明符

¥Unique file type specifiers

唯一文件类型说明符是描述用户可以在类型 file<input> 元素中选择的文件类型的字符串。每个唯一的文件类型说明符可以采用以下形式之一:

¥A unique file type specifier is a string that describes a type of file that may be selected by the user in an <input> element of type file. Each unique file type specifier may take one of the following forms:

  • 有效的不区分大小写的文件扩展名,以句点 (".") 字符开头。例如:.jpg.pdf.doc
  • 有效的 MIME 类型字符串,不带扩展名。
  • 字符串 audio/* 表示 "任何音频文件"。
  • 字符串 video/* 表示 "任何视频文件"。
  • 字符串 image/* 表示 "任何图片文件"。

accept 属性采用包含一个或多个唯一文件类型说明符的字符串作为其值,并以逗号分隔。例如,需要可以以图片形式呈现的内容(包括标准图片格式和 PDF 文件)的文件选择器可能如下所示:

¥The accept attribute takes a string containing one or more of these unique file type specifiers as its value, separated by commas. For example, a file picker that needs content that can be presented as an image, including both standard image formats and PDF files, might look like this:

html
<input type="file" accept="image/*,.pdf" />

使用文件输入

¥Using file inputs

一个基本的例子

¥A basic example

html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="file">Choose file to upload</label>
    <input type="file" id="file" name="file" multiple />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
css
div {
  margin-bottom: 10px;
}

这会产生以下输出:

¥This produces the following output:

注意:你也可以在 GitHub 上找到此示例 - 请参阅 源代码看到它实时运行

¥Note: You can find this example on GitHub too — see the source code, and also see it running live.

无论用户的设备或操作系统如何,文件输入都会提供一个按钮,用于打开文件选择器对话框,允许用户选择文件。

¥Regardless of the user's device or operating system, the file input provides a button that opens up a file picker dialog that allows the user to choose a file.

包括 multiple 属性,如上所示,指定可以一次选择多个文件。用户可以按照其所选平台允许的任何方式从文件选择器中选择多个文件(例如,按住 ShiftControl 然后单击)。如果你只想让用户为每个 <input> 选择一个文件,请省略 multiple 属性。

¥Including the multiple attribute, as shown above, specifies that multiple files can be chosen at once. The user can choose multiple files from the file picker in any way that their chosen platform allows (e.g. by holding down Shift or Control and then clicking). If you only want the user to choose a single file per <input>, omit the multiple attribute.

获取有关选定文件的信息

¥Getting information on selected files

所选文件由元素的 HTMLInputElement.files 属性返回,该属性是包含 File 对象列表的 FileList 对象。FileList 的行为类似于数组,因此你可以检查其 length 属性来获取所选文件的数量。

¥The selected files' are returned by the element's HTMLInputElement.files property, which is a FileList object containing a list of File objects. The FileList behaves like an array, so you can check its length property to get the number of selected files.

每个 File 对象包含以下信息:

¥Each File object contains the following information:

name

文件的名称。

lastModified

一个数字,指定上次修改文件的日期和时间,以 UNIX 纪元(1970 年 1 月 1 日午夜)以来的毫秒为单位。

lastModifiedDate Deprecated

一个 Date 对象,表示文件上次修改的日期和时间。这已被弃用,不应使用。请改用 lastModified

size

文件的大小(以字节为单位)。

type

该文件是 MIME 类型

webkitRelativePath Non-standard

一个字符串,指定文件相对于目录选择器(即设置了 webkitdirectory 属性的 file 选择器)中选择的基目录的路径。这是非标准的,应谨慎使用。

注意:你可以在所有现代浏览器中设置和获取 HTMLInputElement.files 的值;这是最近添加到 Firefox 版本 57 中的(参见 火狐浏览器错误 1384030)。

¥Note: You can set as well as get the value of HTMLInputElement.files in all modern browsers; this was most recently added to Firefox, in version 57 (see Firefox bug 1384030).

限制接受的文件类型

¥Limiting accepted file types

通常,你不希望用户能够选择任何任意类型的文件;相反,你通常希望他们选择特定类型的文件。例如,如果你的文件输入允许用户上传个人资料图片,你可能希望他们选择 Web 兼容的图片格式,例如 JPEGPNG

¥Often you won't want the user to be able to pick any arbitrary type of file; instead, you often want them to select files of a specific type or types. For example, if your file input lets users upload a profile picture, you probably want them to select web-compatible image formats, such as JPEG or PNG.

可以使用 accept 属性指定可接受的文件类型,该属性采用逗号分隔的允许文件扩展名或 MIME 类型列表。一些例子:

¥Acceptable file types can be specified with the accept attribute, which takes a comma-separated list of allowed file extensions or MIME types. Some examples:

  • 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 文档的内容。

让我们看一个更完整的例子:

¥Let's look at a more complete example:

html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="profile_pic">Choose file to upload</label>
    <input
      type="file"
      id="profile_pic"
      name="profile_pic"
      accept=".jpg, .jpeg, .png" />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
css
div {
  margin-bottom: 10px;
}

这会产生与前面的示例类似的输出:

¥This produces a similar-looking output to the previous example:

注意:你也可以在 GitHub 上找到此示例 - 请参阅 源代码看到它实时运行

¥Note: You can find this example on GitHub too — see the source code, and also see it running live.

它可能看起来很相似,但如果你尝试使用此输入选择文件,你将看到文件选择器仅允许你选择 accept 值中指定的文件类型(确切的界面因浏览器和操作系统而异)。

¥It may look similar, but if you try selecting a file with this input, you'll see that the file picker only lets you select the file types specified in the accept value (the exact interface differs across browsers and operating systems).

accept 属性不验证所选文件的类型;它为浏览器提供提示,引导用户选择正确的文件类型。用户仍然可以(在大多数情况下)在文件选择器中切换一个选项,从而可以覆盖此选项并选择他们想要的任何文件,然后选择不正确的文件类型。

¥The accept attribute doesn't validate the types of the selected files; it provides hints for browsers to guide users towards selecting the correct file types. It is still possible (in most cases) for users to toggle an option in the file chooser that makes it possible to override this and select any file they wish, and then choose incorrect file types.

因此,你应该确保 accept 属性得到适当的服务器端验证的支持。

¥Because of this, you should make sure that the accept attribute is backed up by appropriate server-side validation.

检测取消

¥Detecting cancellations

当用户不更改其选择并重新选择先前选择的文件时,会触发 cancel 事件。当文件选择器对话框通过 "cancel" 按钮或 escape 键关闭或取消时,也会触发 cancel 事件。

¥The cancel event is fired when the user does not change their selection, reselecting the previously selected files. The cancel event is also fired when the file picker dialog gets closed, or canceled, via the "cancel" button or the escape key.

例如,如果用户关闭弹出窗口而不选择文件,以下代码将记录到控制台:

¥For example, the following code will log to the console if the user closes the popup without selecting a file:

js
const elem = document.createElement("input");
elem.type = "file";
elem.addEventListener("cancel", () => {
  console.log("Cancelled.");
});
elem.addEventListener("change", () => {
  if (elem.files.length == 1) {
    console.log("File selected: ", elem.files[0]);
  }
});
elem.click();

注意

¥Notes

  1. 你无法从脚本设置文件选择器的值 - 执行如下操作不会产生任何效果:
    js
    const input = document.querySelector("input[type=file]");
    input.value = "foo";
    
  2. 当使用 <input type="file"> 选择文件时,出于明显的安全原因,源文件的真实路径不会显示在输入的 value 属性中。相反,会显示文件名,并在其前面添加 C:\fakepath\。这种怪癖有一些历史原因,但所有现代浏览器都支持它,事实上是 规范中定义

示例

¥Examples

在此示例中,我们将展示一个稍微更高级的文件选择器,它利用 HTMLInputElement.files 属性中可用的文件信息,并展示一些巧妙的技巧。

¥In this example, we'll present a slightly more advanced file chooser that takes advantage of the file information available in the HTMLInputElement.files property, as well as showing off a few clever tricks.

注意:你可以在 GitHub — file-example.html (也看到它直播) 上查看此示例的完整源代码。我们不会解释 CSS;JavaScript 是主要焦点。

¥Note: You can see the complete source code for this example on GitHub — file-example.html (see it live also). We won't explain the CSS; the JavaScript is the main focus.

首先,让我们看一下 HTML:

¥First of all, let's look at the 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>
css
html {
  font-family: sans-serif;
}

form {
  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;
}

这与我们之前看到的类似 - 没有什么特别值得评论的。

¥This is similar to what we've seen before — nothing special to comment on.

接下来,让我们浏览一下 JavaScript。

¥Next, let's walk through the JavaScript.

在脚本的第一行中,我们获取对表单输入本身以及具有 .preview 类的 <div> 元素的引用。接下来,我们隐藏 <input> 元素 - 我们这样做是因为文件输入往往很丑陋,难以设计样式,并且在不同浏览器中的设计不一致。你可以通过单击 <label> 来激活 input 元素,因此最好在视觉上隐藏 input 并将标签样式设置为按钮,以便用户在想要上传文件时知道与其进行交互。

¥In the first lines of script, we get references to the form input itself, and the <div> element with the class of .preview. Next, we hide the <input> element — we do this because file inputs tend to be ugly, difficult to style, and inconsistent in their design across browsers. You can activate the input element by clicking its <label>, so it is better to visually hide the input and style the label like a button, so the user will know to interact with it if they want to upload files.

js
const input = document.querySelector("input");
const preview = document.querySelector(".preview");

input.style.opacity = 0;

注意:opacity 用于隐藏文件输入,而不是 visibility: hiddendisplay: none,因为辅助技术将后两种样式解释为意味着文件输入不是交互式的。

¥Note: opacity is used to hide the file input instead of visibility: hidden or display: none, because assistive technology interprets the latter two styles to mean the file input isn't interactive.

接下来,我们将 事件监听器 添加到输入以监听其所选值的更改(在本例中,当选择文件时)。事件监听器调用我们的自定义 updateImageDisplay() 函数。

¥Next, we add an event listener to the input to listen for changes to its selected value (in this case, when files are selected). The event listener invokes our custom updateImageDisplay() function.

js
input.addEventListener("change", updateImageDisplay);

每当调用 updateImageDisplay() 函数时,我们:

¥Whenever the updateImageDisplay() function is invoked, we:

  • 使用 while 循环清空预览 <div> 之前的内容。
  • 获取包含所有选定文件信息的 FileList 对象,并将其存储在名为 curFiles 的变量中。
  • 通过检查 curFiles.length 是否等于 0 来检查是否未选择任何文件。如果是这样,请在预览 <div> 中打印一条消息,说明尚未选择任何文件。
  • 如果已选择文件,我们将循环遍历每个文件,并将有关它的信息打印到预览 <div> 中。这里需要注意的事项:
  • 我们使用自定义 validFileType() 函数来检查文件类型是否正确(例如 accept 属性中指定的图片类型)。
  • 如果是的话,我们:
    • 将其名称和文件大小打印到前面的 <div>(从 file.namefile.size 获得)内的列表项中。自定义 returnFileSize() 函数返回格式良好的大小版本(以字节/KB/MB 为单位)(默认情况下,浏览器以绝对字节为单位报告大小)。
    • 通过调用 URL.createObjectURL(file) 生成图片的缩略图预览。然后,通过创建新的 <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);
        image.alt = image.title = file.name;

        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

¥The custom validFileType() function takes a File object as a parameter, then uses Array.prototype.includes() to check if any value in the fileTypes matches the file's type property. If a match is found, the function returns true. If no match is found, it returns false.

js
// https://web.nodejs.cn/en-US/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 属性),并将其转换为格式良好的大小(以字节/KB/MB 为单位)。

¥The returnFileSize() function takes a number (of bytes, taken from the current file's size property), and turns it into a nicely formatted size in 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`;
  }
}
js
const button = document.querySelector("form button");
button.addEventListener("click", (e) => {
  e.preventDefault();
  const para = document.createElement("p");
  para.append("Image uploaded!");
  preview.replaceChildren(para);
});

该示例如下所示;玩一玩:

¥The example looks like this; have a play:

技术总结

¥Technical summary

表示所选文件路径的字符串。
活动 changeinputcancel
支持的通用属性 required
附加属性 accept, capture, multiple
IDL 属性 filesvalue
DOM 接口

HTMLInputElement

方法 select()
隐式 ARIA 角色 no corresponding role

规范

Specification
HTML Standard
# file-upload-state-(type=file)

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看

¥See also