Hyperapp — это минималистичный JavaScript-фреймворк для построения реактивных пользовательских интерфейсов. Его ядро сосредоточено на управлении состоянием и виртуальном DOM, что делает работу с файлами и медиа-контентом особенной задачей, требующей интеграции стандартных веб-API с архитектурой Hyperapp.
Файлы, загружаемые пользователем через
<input type="file">, необходимо хранить в состоянии
приложения. Hyperapp использует объект состояния (state)
для реактивного обновления интерфейса:
import { h, app } from "https://unpkg.com/hyperapp?module";
const state = {
files: []
};
const actions = {
setFiles: files => state => ({ files }),
};
const view = (state, actions) =>
h("div", {}, [
h("input", {
type: "file",
multiple: true,
onchange: e => actions.setFiles(Array.from(e.target.files))
}),
h("ul", {}, state.files.map(file => h("li", {}, file.name)))
]);
app({ init: state, view, actions });
Ключевые моменты:
File.onchange события <input>
обрабатывает файлы и обновляет состояние через action.FileList в массив через
Array.from позволяет удобно использовать
.map.Для работы с текстовыми или бинарными данными используется
FileReader:
const actions = {
readFile: file => state => {
const reader = new FileReader();
reader.onl oad = () => {
state.filesContent = [...(state.filesContent || []), reader.result];
};
reader.readAsText(file);
return state;
}
};
Особенности:
reader.onload асинхронно получает содержимое
файла.readAsArrayBuffer
или readAsDataURL.Hyperapp не имеет встроенной поддержки загрузки медиа, но можно использовать реактивное состояние для отображения выбранных файлов:
const actions = {
previewImage: file => state => {
const reader = new FileReader();
reader.onl oad = () => {
state.preview = reader.result;
};
reader.readAsDataURL(file);
return state;
}
};
const view = (state, actions) =>
h("div", {}, [
h("input", {
type: "file",
accept: "image/*",
onchange: e => actions.previewImage(e.target.files[0])
}),
state.preview && h("img", { src: state.preview, width: 200 })
]);
Выделенные аспекты:
readAsDataURL преобразует файл в строку base64, удобную
для <img> или <video>.preview автоматически обновляет интерфейс при
загрузке.Для отправки файлов на сервер используется FormData и
стандартный fetch:
const actions = {
uploadFile: file => async state => {
const formData = new FormData();
formData.append("file", file);
const response = await fetch("/upload", {
method: "POST",
body: formData
});
if (response.ok) {
state.uploadStatus = "Файл загружен";
} else {
state.uploadStatus = "Ошибка загрузки";
}
return state;
}
};
Особенности интеграции:
async) возвращают обновлённое
состояние.state для отображения
прогресса.XMLHttpRequest и onprogress.Для больших видео или аудио-файлов важно не загружать весь контент в
память. Использование URL.createObjectURL позволяет
создавать временные ссылки:
const actions = {
createPreviewURL: file => state => {
state.mediaURL = URL.createObjectURL(file);
return state;
}
};
const view = (state, actions) =>
h("div", {}, [
h("input", { type: "file", accept: "video/*", onchange: e => actions.createPreviewURL(e.target.files[0]) }),
state.mediaURL && h("video", { src: state.mediaURL, controls: true, width: 400 })
]);
Преимущества:
URL.revokeObjectURL,
когда он больше не нужен.Hyperapp легко комбинивается с событиями dragover и
drop для загрузки файлов перетаскиванием:
const actions = {
dropFiles: files => state => ({ files })
};
const view = (state, actions) =>
h("div", {
ondragover: e => e.preventDefault(),
ondrop: e => {
e.preventDefault();
actions.dropFiles(Array.from(e.dataTransfer.files));
},
style: { border: "2px dashed #ccc", padding: "20px", width: "300px" }
}, "Перетащите файлы сюда");
Особенности:
e.preventDefault() обязателен для корректного приема
событий drop.createObjectURL.Работа с файлами и медиа-контентом в Hyperapp строится на сочетании
реактивного состояния и стандартных веб-API (FileReader,
FormData, URL.createObjectURL).
Минималистичная архитектура Hyperapp позволяет интегрировать эти
возможности без сложных обёрток, сохраняя скорость и предсказуемость
приложения.