Задача
У нас есть файлы на компьютере (или ноутбуке). Мы хотим при помощи браузера получить список имён выбранных файлов из какой-нибудь директории на нашем компьютере (то есть на клиентской стороне, а не на серверной). Мы как бы хотим провзаимодействовать с этими файлами в будущем.
Как это сделать и с чего начать?
Шаг первый - Стандарт HTML и элемент input
На вкладках браузера мы всегда имеем дело с языком разметки HTML. У HTML есть много элементов, но нас будет интересовать всего один - это элемент ввода input.
Он может владеть всеми глобальными атрибутами языка HTML, а также имеет 32 своих собственных атрибутов.


В нашей задаче нас будет интересовать type с состоянием File Upload - состояние Загрузки Файла.
Давайте создадим такой элемент:
<input type="file"></input>
Мы положили этот input внутрь элемента body в простом документе с HTML-разметкой.

Теперь на странице документа есть кликабельная кнопка, которая вызовет окно обозревателя (проводника) для выбора директории и файла на ПК.

В стандартном поведении выбора файла есть один минус. По умолчанию он позволяет выбирать только один файл из директории. Но нам нужно иметь возможность выбирать несколько разных файлов из директории. Как это исправить?
За "мультифайловость" отвечает атрибут multiple, который может быть установлен у элемента input. Давайте его добавим.
<input type="file" multiple></input>

Теперь можем открыть эти 2 файла.

Как мы видим, надпись "Файл не выбран" сменилась на "Число файлов: 2". И на этом всё. Больше никаких визуальных изменений не произошло.
Шаг второй - JavaScript объект элемента input и его свойство files
Теперь мы можем взаимодействовать с элементом input при помощи языка JavaScript и объектной модели документа - DOM.
Из объекта документа (document) мы можем получить объект нашего элемента input.
document.querySelector("body > input[type=file]") или document.getElementsByTagName('input')[0]
На странице он у нас всего один, поэтому мы его легко можем обнаружить.

Объект элемента input обладает очень большим количеством свойств. Я насчитал 253 свойства в 2021 году. Но нас интересует только одно свойство, которое называется files.

Свойство files хранит в себе объект, прототипом которого является класс FileList
По сути это массив, который состоит из объектов File, где свойствами перечислены основные значения любого файла:
- lastModified
- lastModifiedDate
- name
- size
- type
- webkitRelativePath
Из всех этих вложенных свойств нас будет интересовать только свойство с ключом name. Именно в значении хранится нужное нам имя файла.

Для получения FIleList
document.querySelector("body > input[type=file]").files
Шаг третий - Вывод имён на текущую страницу в элемент body
Теперь можно вывести нужные нам имена файлов прямо под элементом input. Для этого конвертируем объект FIleList в массив.
[...document.querySelector("body > input[type=file]").files]
и проходим по каждому файлу. Методом map() возвращаем только значения свойств name
[...document.querySelector("body > input[type=file]").files].map(i=>i.name)

Теперь мы можем пройти по каждому имени из массива и превратить их в абзацы.
[...document.querySelector("body > input[type=file]").files].map(i=>i.name) .map(x=>{ let newp = document.createElement('p'); newp.innerText = x; document.body.append(newp) })
И после этого мы получаем

Шаг четвёртый - Автоматизация вывода имён файлов при загрузке новых файлов
Все предыдущие манипуляции мы делали вручную пошагово, когда состояние объекта input менялось от пустого (безфайлового) до полного (с какими-то загруженными файлами из папки). То есть мы сами точно знали, что состояние изменилось и только тогда выводили имена. Как это автоматизировать?
Для этого нам понадобится слушатель события. Этот слушатель мы повесим на элемент input и когда его состояние будет меняться, мы будем выводить имена файлов на страницу. Как это сделать?
На этот раз нам нужно добавить в наш файл элемент скрипта. Внутри мы будем расписывать логику обработки желаемого поведения.
Для начала в переменной inputfiles мы будем хранить наш элемент ввода - input.
let inputfiles = document.querySelector("body > input[type=file]")
Теперь повесим на него слушатель событий методом addEventListener(type, callback, options)
inputfiles.addEventListener('change', event => {})
В качестве события мы будем использовать событие изменения элемента - 'change'. Когда мы будем выбирать файлы на ПК, тогда состояние нашего элемента ввода будет меняться. Мы будем перехватывать это изменение и выполнять нужные нам действия.
Полная версия документа:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="file" multiple></input> <script> let inputfiles = document.querySelector("body > input[type=file]") inputfiles.addEventListener('change', event => { // Очищаем body от возможных старых имён файлов [...document.body.children].slice(1).map(i=>i.remove()); // Добавляем новые имена файлов [...event.target.files].map(i=>{ let newp = document.createElement('p'); newp.innerText = i.name; document.body.append(newp); }) }) </script> </body> </html>
Выражение event.target будет возвращать нам элемент input, тот единственный, состояние которого может меняться.
Информационные ссылки
Стандарт HTML - Элемент input - https://html.spec.whatwg.org/multipage/input.html#the-input-element
Стандарт HTML - Элемент input - https://html.spec.whatwg.org/multipage/input.html#common-input-element-apis
Стандарт HTML - События элемента input - https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
Стандарт DOM - Добавление слушателя события - Метод addEventListener(type, callback, options) - https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener