Mithril — это легковесный JavaScript-фреймворк для создания одностраничных приложений (SPA), отличающийся высокой производительностью и минимальным размером. Его архитектура позволяет гибко использовать популярные паттерны проектирования, такие как MVC (Model-View-Controller) и MVP (Model-View-Presenter).
Модель отвечает за управление состоянием приложения и работу с данными. В Mithril модели часто представляют собой простые объекты с методами для изменения состояния и выполнения асинхронных запросов.
Пример модели:
const TodoModel = {
list: [],
load() {
return m.request({
method: "GET",
url: "/api/todos",
})
.then(result => {
TodoModel.list = result;
});
},
add(todo) {
TodoModel.list.push(todo);
},
remove(id) {
TodoModel.list = TodoModel.list.filter(t => t.id !== id);
}
};
Ключевое в моделях Mithril — это реактивность через обновление
состояния и последующий вызов m.redraw() или использование
встроенной автоматической перерисовки после промисов
m.request.
Представление в Mithril реализуется через функции, возвращающие виртуальный DOM (vDOM). Эти функции полностью декларативны и описывают, как должны отображаться данные.
Пример простого представления:
const TodoView = {
view(vnode) {
return m("ul",
vnode.attrs.todos.map(todo =>
m("li", todo.text)
)
);
}
};
Особенность Mithril — возможность передачи данных через
attrs и использование их внутри vDOM-функций. Это делает
представления чистыми и независимыми от бизнес-логики.
В паттерне MVC контроллер управляет взаимодействием между моделью и представлением. В Mithril классический контроллер можно реализовать через объект или функцию, которая управляет состоянием и обработкой событий.
Пример контроллера для списка задач:
const TodoController = {
init() {
TodoModel.load();
},
addTodo(text) {
TodoModel.add({ id: Date.now(), text });
},
removeTodo(id) {
TodoModel.remove(id);
}
};
Контроллеры в Mithril могут вызывать m.redraw() для
обновления представления после изменения модели, но чаще используется
автоматическая перерисовка после промисов или событий.
MVP отделяет представление от логики, предоставляя Presenter как посредника между View и Model. Presenter управляет состоянием, обрабатывает пользовательские действия и изменяет модель, не заставляя View содержать бизнес-логику.
Пример Presenter:
const TodoPresenter = () => {
const addTodo = (text) => {
TodoModel.add({ id: Date.now(), text });
};
const removeTodo = (id) => {
TodoModel.remove(id);
};
return { addTodo, removeTodo, todos: TodoModel.list };
};
View в MVP становится максимально «тупым», отображая данные и вызывая методы Presenter по событиям.
Пример View с Presenter:
const TodoViewMVP = {
view(vnode) {
const { todos, addTodo, removeTodo } = vnode.attrs.presenter;
return m("div", [
m("input[type=text][placeholder=New task]", { oninput: e => vnode.state.newTodo = e.target.value }),
m("button", { onclick: () => { addTodo(vnode.state.newTodo); vnode.state.newTodo = ""; } }, "Add"),
m("ul", todos.map(todo =>
m("li", [
todo.text,
m("button", { onclick: () => removeTodo(todo.id) }, "Remove")
])
))
]);
}
};
MVC
MVP
m.redraw() или промисы m.request, чтобы
интерфейс оставался синхронизированным с состоянием.Использование Mithril совместно с паттернами MVC и MVP позволяет строить приложения, где бизнес-логика четко отделена от отображения, а компоненты остаются компактными и легко тестируемыми.