Пользовательский ввод и формы

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 предоставляет простые и гибкие механизмы для работы с пользовательским вводом, позволяя реализовать любые формы — от простых до сложных, с валидацией и асинхронной обработкой, при этом оставаясь максимально производительным и минималистичным.