Mithril.js — минималистичный JavaScript-фреймворк для создания SPA, который обеспечивает высокую производительность и простую работу с виртуальным DOM. Управление пользовательским вводом и формами в Mithril реализуется через связывание состояния компонентов с элементами формы, обработку событий и управление реактивностью.
В Mithril состояние компонента чаще всего хранится в простых JavaScript-объектах или свойствах функции-компонента. Для работы с формами создается объект, который хранит значения полей:
let formData = {
username: "",
email: "",
password: ""
};
Эти данные затем привязываются к атрибутам элементов формы через
свойство value и обработчики oninput или
onchange.
m("input[type=text]", {
value: formData.username,
oninput: (e) => formData.username = e.target.value
})
Ключевой момент: в отличие от некоторых других
фреймворков, Mithril не требует специального состояния для перерисовки
компонентов — обновление виртуального DOM происходит автоматически при
изменении данных через m.redraw() (вызывается автоматически
при событиях UI, таких как onclick,
oninput).
Mithril позволяет использовать стандартные события DOM, такие как
onsubmit, oninput, onclick. Для
формы обработка отправки реализуется следующим образом:
m("form", {
onsubmit: (e) => {
e.preventDefault();
console.log("Данные формы:", formData);
// Здесь может быть вызов API
}
}, [
m("input[type=text][placeholder=Username]", {
value: formData.username,
oninput: (e) => formData.username = e.target.value
}),
m("input[type=email][placeholder=Email]", {
value: formData.email,
oninput: (e) => formData.email = e.target.value
}),
m("button[type=submit]", "Отправить")
])
Особенность: предотвращение стандартного поведения
формы (e.preventDefault()) обязательно, чтобы SPA
оставалась на одной странице и не происходила перезагрузка.
Mithril не предоставляет встроенного двухстороннего связывания, как
Angular, но его можно реализовать через сочетание value и
oninput. Это обеспечивает синхронизацию состояния формы с
объектом данных:
function bindField(field) {
return {
value: formData[field],
oninput: (e) => formData[field] = e.target.value
};
}
m("input[type=text]", bindField("username"));
m("input[type=password]", bindField("password"));
Такой подход уменьшает дублирование кода и упрощает поддержку форм с большим числом полей.
Валидация в Mithril может выполняться прямо в обработчиках событий
или перед отправкой формы. Результаты валидации можно хранить в
отдельном объекте errors:
let errors = {};
function validate() {
errors = {};
if (!formData.username) errors.username = "Имя пользователя обязательно";
if (!formData.email.includes("@")) errors.email = "Некорректный email";
return Object.keys(errors).length === 0;
}
m("form", {
onsubmit: (e) => {
e.preventDefault();
if (validate()) {
console.log("Форма валидна:", formData);
}
}
}, [
m("input[type=text]", bindField("username")),
errors.username && m("div.error", errors.username),
m("input[type=email]", bindField("email")),
errors.email && m("div.error", errors.email),
m("button[type=submit]", "Отправить")
])
Рекомендация: ошибки лучше выводить рядом с полем ввода, чтобы пользователю было проще корректировать данные.
Для элементов типа checkbox и radio
используется свойство checked вместо
value:
let options = {
subscribe: false,
gender: "male"
};
m("input[type=checkbox]", {
checked: options.subscribe,
onclick: (e) => options.subscribe = e.target.checked
});
m("input[type=radio][value=male]", {
checked: options.gender === "male",
onclick: (e) => options.gender = e.target.value
});
m("input[type=radio][value=female]", {
checked: options.gender === "female",
onclick: (e) => options.gender = e.target.value
});
Важный момент: для радио-кнопок нужно вручную
проверять соответствие значения и состояния checked.
<select> и множественным выборомДля <select> и множественного выбора применяется
value и onchange:
let selectedOption = "option1";
m("select", {
value: selectedOption,
onchange: (e) => selectedOption = e.target.value
}, [
m("option[value=option1]", "Опция 1"),
m("option[value=option2]", "Опция 2")
]);
Для множественного выбора массив значений обновляется через перебор
выбранных элементов e.target.selectedOptions.
Mithril имеет встроенный m.request для работы с API, что
удобно для отправки форм без перезагрузки страницы:
m("form", {
onsubmit: (e) => {
e.preventDefault();
if (validate()) {
m.request({
method: "POST",
url: "/api/register",
body: formData
}).then(response => {
console.log("Ответ сервера:", response);
}).catch(err => console.error(err));
}
}
}, [
m("input[type=text]", bindField("username")),
m("input[type=email]", bindField("email")),
m("button[type=submit]", "Отправить")
])
Использование m.request интегрируется с реактивностью
компонентов и автоматически вызывает перерисовку при изменении
данных.
Для больших форм удобно разделять поля на подкомпоненты. Каждый
компонент получает объект данных через свойства (attrs) и
управляет своим набором полей. Это повышает читаемость и
поддерживаемость кода:
function UserInfoForm({ data }) {
return m("div", [
m("input[type=text]", {
value: data.username,
oninput: (e) => data.username = e.target.value
}),
m("input[type=email]", {
value: data.email,
oninput: (e) => data.email = e.target.value
})
]);
}
m(UserInfoForm, { data: formData });
Такой подход позволяет легко масштабировать формы и повторно использовать компоненты в разных частях приложения.
Mithril предоставляет простые и гибкие механизмы для работы с пользовательским вводом, позволяя реализовать любые формы — от простых до сложных, с валидацией и асинхронной обработкой, при этом оставаясь максимально производительным и минималистичным.