Краткий обзор простого фреймворка для создания одностраничных приложений Matreshka.js. В посте используется ECMAScript 2017, который можно переписать на ECMAScript 5.
Основные функции
Функция bindNode
связывает свойство и элемент.
const object = { name: 'Brendan' };
const node = document.querySelector('.name');
Matreshka.bindNode(object, 'name', node);
object.name = 'Doug';
Если свойство меняется, меняется и элемент, если элемент меняется (например, пользователь вводит текст), меняется и свойство. Из коробки Matreshka.js умеет обрабатывать любые элементы форм. Можно объявить байндинг для произвольных элементов см. документацию.
Функция calc
связывает одно свойство с другими.
Matreshka.calc(object, 'fullName', ['firstName', 'lastName'], (firstName, lastName) => {
return `${firstName} ${lastName}`
});
object.firstName = 'Brendan';
object.lastName = 'Eich';
// ...
console.log(object.fullName); // "Brendan Eich"
Когда меняется свойство-источник (firstName
или lastName
), меняется и свойство-цель (fullName
).
Вместе с функцией bindNode
можно объявлять длинные цепочки зависимостей: свойство a
зависит от состояния элемента e1
, свойство b
зависит от свойства a
, свойство c
зависит от элементов e2
и e3
и от свойства b
, изменение которого, как следствие, меняет e1
, e2
и e3
...
Такие зависимости можно представить как таблицу в табличном процессоре (например, Excel): в каждый момент времени вы думаете об одной формуле, а не о многочисленных связях все ячеек. Как следствие, получаете меньше багов, так как нужно думать об атомарных сущностях, а не обо всей "таблице" (приложении). Больше информации в документации.
Функция on
ловит, а trigger
генерирует события.
Matreshka.on(object, 'something', () => alert('something is happened'));
Matreshka.trigger(object, 'something');
Можно слушать изменения свойств, чтоб вызвать кастомный код. Таким образом в цепочку зависимостей можно добавить, скажем, fetch запрос.
Matreshka.on(object, 'change:fullName', async () => {
await fetch('/api/name', { method: 'post', body: this.fullName });
// ...
})
События в Matreshka.js — это отдельная тема. Можно объявлять делегированные события объекта (слушать изменения в глубине дерева объектов), DOM события, делегированные DOM события и пр. Читайте подробную статью на эту тему.
Функция mediate
добавляет рантайм валидацию и конвертацию значений свойств. Например, можно объявить свойство определенного типа, можно ограничить свойство указанным диапазоном, можно генерировать исключение, если необходимо.
Matreshka.mediate(object, 'x', x => String(x));
object.x = 42;
console.log(object.x, typeof object.x); // "42", "string"
Классы
Экземпляры класса Matreshka
содержат те же методы, работающие с объектом, с тем отличием, что не нужно передавать объект первым аргументом: им становится this
.
class User extends Matreshka {
constructor() {
super();
this.bindNode('fullName', '.full-name');
this.calc('fullName', ['firstName', 'lastName'], (firstName, lastName) => {
return `${firstName} ${lastName}`
});
// chained call can be used there: super().bindNode(...).calc(...);
}
}
Этот класс объединяет описанные ниже классы Matreshka.Array
и Matreshka.Object
, объявляя общие для всех классов методы.
Класс Matreshka.Object
отвечает за данные, типа "ключ-значение". Это данные, которые разработчик желает отделить от всех остальных свойств и, скажем, отправить на сервер или сохранить в локальном хранилище. Для этого фреймворку нужно указать на то, какие свойства отвечают за бизнес логику (например, имя пользователя), какие за временное состояние приложения (например, виден ли DOM элемент). За это отвечает метод addDataKeys
.
class User extends Matreshka.Object {
constructor() {
super();
this.firstName = 'Brendan';
this.lastName = 'Eich';
this.language = 'JavaScript';
this.addDataKeys(['firstName', 'lastName']);
console.log(JSON.stringify(this)); // '{"firstName": "Brendan", "lastName": "Eich"}'
}
}
Matreshka.Array
— отвечает за массивоподобные коллекции во фреймворке. Экземпляры, помимо методов унаследованных у Matreshka
, содержит методы из нативного Array
(push
, splice
, map
, reduce
...).
Для коллекций, подобно Backbone.Collection, можно указать "модель" (свойство Model
) с тем отличием, что ею может высупать любой класс.
class Users extends Matreshka.Array {
get Model() { return User; }
constructor() {
super();
this.push({ firstName: 'Brendan', lastName: 'Eich' });
console.log(this[0] instanceof User); // true
}
}
Коллекция может автоматически рендериться при изменени содержимого. Для этого нужно указать куда вставлять новосозданные DOM элементы и как их рендерить. Для указания места рендеринга, нужно привязать свойству sandbox
, либо свойству container
(разницу см. в документации) DOM узел. Для указания того, как рендерить элемент, нужно восмользоваться виртуальным методом itemRenderer
(либо определить renderer
для модели).
class Foo extends Matreshka.Array {
itemRenderer() {
return '<div>Hello, world!</div>';
}
constructor() {
super();
this.bindNode('sandbox', '.sandbox-node');
this.push({}); // inserts <div>Hello, world!</div> to .sandbox-node
}
}
Подробнее о классах в посте "От простого к простому".
Всё указанное выше можно импортировать в качестве CJS/ES2015 модуля:
import calc from 'matreshka/calc';
import MatreshkaArray from 'matreshka/array';
Роутинг
За роутинг отвечает отдельная библиотека matreshka-router. Она связвает части адреса со свойствами:
Matreshka.initRouter(object, '/a/b/c/');
object.a = 'foo';
object.b = 'bar';
object.c = 'baz';
// makes location.hash to be #!/foo/bar/baz/
Подробно описано в статье.
Вместо вывода
Matreshka.js заполняет пропасть между джуном и сеньором, позволяя на раннем этапе писать модульные и расширяемые приложения. Всё, что требуется — это знание языка и основных понятий.
Всем спасибо.
Комментарии (21)
shimanskybiz
04.04.2017 00:06Мое мнение:
1) Невнятное описание либы (на гитхабе и на .io), если это для SPA, так и напишите, посмотрите, как кричат реакт (will efficiently update and render just the right components when your data changes) и вю (тоже невнятно, но глаз цепляется за Virtual DOM, и уже знаешь зачем).
2) В последнее время, нетолько усталость от JS, но и от фреймворков. Мне устраивает microjs подход — копилка микролибов, выполняющих одну задачу, и жонглируешь ими в зависимости от задач.
3) Согласен, что в последнее время оверинджениринг в вебразработке доставляет.Finom
04.04.2017 00:06Обновил описание в репозитории, спасибо.
vlasenkofedor
06.04.2017 11:52+2Спасибо за новый реализ.
В свободное время стараюсь глянуть на реализацию (исходный код)
Мне устраивает microjs подход — копилка микролибов, выполняющих одну задачу
У Finom там-же лежит микролиба Balalaika, реализация которой достойна для ознакомления Js программистов
neoxack
Так и не понял для чего конкретно нужна эта библиотека. На сайте и в многочисленных статьях на хабре не описано это. Были подозрения, что для веб разработки, но теперь возникли сомнения.
Finom
Цитирую с сайта:
Для кого этот фреймворк?
justboris
Позволю себе не согласиться с вашим позиционированием:
Новички скорее всего будут смотреть на React, обучающих видео и статей по нему немало
Бекендщики с большей вероятностью посмотрят на Angular2, потому что там есть DI, MVC и типизация
Ну а эта категория людей обычно пишет что-то свое в любом случае.
Finom
Есть такое понятие, как JavaScript усталость. Слишком много всего нужно знать помимо, собственно Реакта: сборка, стор, оптимизация рендеринга (чем, к сожалению, часто пренебрегают).
Смотря кто. По моему опыту общения с разработчиками, бек-ендщики (например, PHP-шники), как правило, не уделяют много внимания фронт-енду и обходятся неструктурированным кодом на jQuery. React/Angular/Vue — это то, что их не интересует (это не касается людей, пишуих под NodeJS).
Razaz
Как бэкенд разработчик, который интересуется React/Angular/Vue, не соглашусь :) Тут проблема не в разработчиках, а в требованиях. Я на своих проектах достаточно трепетно отношусь к выбору запчастей к frontend и сейчас потихоньку переезжаем на React с первого Angular. Еще и codestyle стараемся поддерживать. То, что front не основной приоритет, не означает, что там можно болт забивать.
Finom
В общем, всё вышесказанное, можно свести к "Я умею что-то на jQuery, но хочу делать лучше" и таких разработчиков немало. Причем, остальное (сборка, пакеты, ECMAScript Stage X) можно учить постепенно, по-прежнему используя Matreshka.js.
Razaz
Ну мы как-то осилили и сборку, и тестирование. Вынесли фронт в отдельный репо, собираем на TFS и закидываем в локальный NPM. На том же Egghead столько материала по теме, что грех не разобраться. Думаю основной фактор это лень и фу фу фу относительно JS ?\_(?)_/?
Тот же React + TSX вот отлично зашел ;)
Finom
Ну такое. Не только выучить, но и заюзать это всё не так просто. У многих возникает шок от того, что веб разработчик, оказывается. должен знать NodeJS, даже если пишет только под фронт. Это я не говорю об остальном инструментарии. Если вы осилили (изучили и смогли использовать) все необходимые технологии за пару месяцев, примите моё уважение.
Razaz
Ну ноду вообще полезно знать и юзать. Вот пример: утилита на .Net ставится через npm и позволяет генерить клиетов к OpenApi(мы через gulp делаем). ИМХО если можешь в инженера, то пофиг на чем. Общее чувство прекрасного не даст делать каку ни в фронте ни в бэке :D
justboris
И чем же ваша библиотека здесь больше подходит? Лучше оптимизирует рендеринг?
А про усталость и сложные инструменты уже давно неправда и не надо поддерживать этот миф. Вот, например, недавний пост о там как быстро начать разрабатывать на React
Finom
Если вы хорошо разбираетесь в React можем подискутировать (так как я и сам в нем неплохо разбираюсь). Если нет, я бы не хотел в этом посте описывать принципы рендеринга в Реакте, есть масса статей на эту тему.
Поговорите с любым начинающим разработчиком, для начала. Немало людей забивают на веб разработку, узнав о том, сколько вего им нужно знать, чтоб написать грамотный Hello World, используя один из мейнстримных фреймворком.
justboris
Открываем документацию React, ищем раздел "Installation", читаем
То есть берем React с CDN, подключаем на страницу и начинаем писать.
Для более сложных вариантов есть CLI, о котором там тоже рассказывается.
Что из этого кажется сложным и отпугивает людей?
Finom
Вы на полном серьезе вырываете из контектста раздела "Trying Out React" эту фразу?
justboris
Не вырываю из контекста, а выборочно цитирую. Не превращать же этот тред в копипасту документации React.
Вы пишете
Я привожу пример минимального Hello World из документации. Что здесь не так?
Finom
Это не просто Hello World, это — quick and dirty Hello World. Такой код никогда не должен попасть в продакшн, уж лучше на jQuery намакаронить.
Я так понимаю, у вас достаточно мало знаний относительно React. Тогда, давайте прекратим эту беседу.
Singaporian
Спросили «для ЧЕГО», а не «для КОГО».
Это многое меняет. Вопрос для кого не отвечает, что с ней надо делать.