2
Простой фреймворк для создания одностраничных веб-приложений
<output class="out"></output>
<input class="in" type="text">

<script src="matreshka.min.js"></script>
<script>
const app = new Matreshka();
app.bindNode('x', '.in, .out');
app.x = 'Простой фреймворк для создания одностраничных веб-приложений';
</script>

Скачать Github

Немного логотипов

Введение

Фичи

  • Реактивный API, позволяющий эффективно решать сложные и запутанные задачи
  • Меньше ошибок в коде
  • Возможность рефакторинга легаси приложений, без переписывания с нуля
  • Освоить фреймворк можно за пару часов благодаря отсутствию сложных концепций
  • Одна из самых удобных документаций среди JavaScript библиотек

Для кого этот фреймворк?

Matreshka.js заполняет пропасть между джуном и сеньором

  • Для новичков в веб программировании, желающих освоить разработку одностраничных приложений
  • Для full-stack разработчиков, для которых front-end разработка стоит на втором месте после back-end
  • Для всех тех, кого не устраивает текущий порядок вещей во Вселенной веб разработки

Какую бизнес задачу решает фреймворк?

Не секрет, что порог вхождения в веб разработку становится всё выше, требований к современному разработчику всё больше, количество зависимостей в проектах может доходить до нескольких сотен. Несмотря на то, что изучать JavaScript стало модным, спрос на разработчиков, которые могут выполнить поставленную задачу всё сильнее превышает предложение.

Благодаря крайней простоте фреймворка, даже начинающие веб разработчики могут быстро начать делать сначала небольшие, потом средние, а затем и крупные веб приложения. Это значит, что веб студии получают возможность экономить деньги, нанимая младших специалистов, которые, в свою очередь, не могли найти работу раньше.

Только лишь для новичков?

Две вещи, которые выдают Matreshka.js, как простой фреймворк - это прямое обращение к DOM при объявлении двустороннего связывания данных и отсутствие каких-либо ограничений по требованиям к архитектуре и шаблонам проектирования. В остальном Matreshka.js - современный фреймворк общего назначения для неограниченных в размере одностраничных веб приложений, разработанный с использованием технологий сегодняшнего дня. А тот факт, что фреймворк использует, возможно, весь потенциал акцессоров в JavaScript, как минимум, может вызвать неподдельный интерес.

Как использовать документацию

Уровни важности

Документация разбита на три уровня "продвинутости".

Первый уровень - самое важное

Изучив самые важные свойства и методы, вы можете смело приступать к работе. С классами, методами и свойствами, помеченными значком необходимо разобраться в первую очередь.

Второй уровень - рекомендуется изучить

После того, как вы освоили необходимые для быстрого старта возможности, можете ознакомиться с другими, менее важными (но всё еще важными) свойствами и методами Matreshka.js.

Третий уровень - остальные методы и свойства

Для того, чтоб не пугать новичков вещами, которые используются относительно редко, все неважные методы и свойства по умолчанию скрыты. Если вы хотите знать о фреймворке всё, без исключения, кликните на "Продвинутый режим" слева, в меню.

Внимание, если вы перейдете по ссылке к методу или свойству третьего уровня важности, то режим документации автоматически переключится в "продвинутый режим".

Опечатки и ошибки в документации

В конце каждой статьи документации есть ссылка на исходник статьи. Исправить опечатку или ошибку можно прямо в редакторе на Github. Если по каким-либо причинам не можете отправить исправление, выберите текст с ошибкой и нажмите CTRL + Enter. Появится окно, позволяющее отправить сообщение разработчику.

Документация разработана с использованием JSDoc3 и GitHub Flavored Markdown.

Язык

В примерах на этой странице используется синтаксис, соответствующий спецификации ECMAScript 2015 (в частности, классы, стрелочные функции, циклы for..of, let/const). Те, кто не использует транспайлеры (инструменты, которые конвертируют новый JavaScript в старый) и, в то же время, вынуждены поддерживать устаревающие браузеры, могут заменить const и let на var, arrow function на function expression, а классы, на вызов функции Matreshka.Class. При этом, конечно, нужно понимать разницу между старым синтаксисом и новым.

const foo = 1;
let bar = 2;
// ->
var foo = 1;
var bar = 2;
this.on('foo', evt => {
    doSomething();
});
// ->
this.on('foo', function(evt) {
    doSomething();
});
class Foo extends Bar {
    method() {
        // ...
    }
}
// ->
var Foo = Class({
    'extends': Bar,
    method: function() {
        // ...
    }
});

Модули

Если вы используете CommonJS, адреса отдельных модулей указаны в каждой статье этой документации. Размер результирующего JavaScript файла можно сократить за счет импорта только необходимых частей фреймворка.

// каждое статичное свойство какого-либо объекта
// или функции можно импортировать в виде модуля
const MatreshkaArray = require('matreshka/array');
const propBinder = require('matreshka/binders/prop');
const bindNode = require('matreshka/bindNode');

Импорт главного модуля подтянет весь фреймворк. Как правило, это не требуется.

const Matreshka = require('matreshka');

Модуль класса Matreshka, без binders, Array и Object находится по адресу 'matreshka/matreshka'

Примеры

Hello World

Написать первое приложение с помощью фреймворка Matreshka.js очень просто.

1. Создайте HTML файл со следующим содержимым

<!DOCTYPE html>
<html>
    <head>
        <title>Моё первое приложение на базе Matreshka.js</title>
    </head>
    <body>
        <input type="text" class="my-input">
        <div class="my-output"></div>

        <script
          src="https://matreshkajs.github.io/matreshka/matreshka.min.js">
        </script>

        <script src="js/app.js"></script>
    </body>
</html>

2. Создайте класс в файле js/app.js

// сохраняем html байндер в переменную с коротким именем
const htmlBinder = Matreshka.binders.html;

// создаём класс, который наследуется от Matreshka
class Application extends Matreshka {
    constructor() {
        super();

        // связываем свойство x и текстовое поле
        this.bindNode('x', '.my-input');

        // связываем свойство x и блок с классом my-output
        this.bindNode('x', '.my-output', htmlBinder());

        // слушаем изменения свойства x
        this.on('change:x', () =>
            console.log(`x изменен на "${this.x}"`));
    }
}

const app = new Application();

3. Это всё!

Теперь можете открыть консоль разработчика (клавиша F12) и написать:

app.x = 'Hello World!';

Ссылки

Другие примеры

1. TodoMVC - список дел. (Исходный код с аннотациями)

2. TreeView - древовидный список неограниченной вложенности.

3. Markdown editor - простейший редактор Markdown.

4. Simple SoundCloud player - поиск музыки, использующий SoundCloud API.

5. Contact List - позволяет добавлять, удалять, сортировать, менять и искать контакты.

Donate

Разработка и поддержка такого крупного проекта, а так же содержание трехъязычной документации в актуальном состоянии - это тяжелый труд, требующий сотен часов работы. При этом, проект всегда будет совершенно бесплатным для использования в любых, в том числе, коммерческих проектах.

Если ваша компания использует Matreshka.js, финансовая поддержка проекта будет являться гарантией того, что проект будет активно развиваться. Если вы индивидуальный разработчик, даже небольшая помощь позитивно влияет на развитие фреймворка.

Patreon (постоянная поддержка)

LiqPay (единовременная помощь)

Bitcoin (единовременная помощь)

178QKqoyk1yXi9SoyFCv66cW3P7YmiCxAd

Другие способы спонсирования

Если ни один из способов, предложенных выше, не подходит, пишите автору фреймворка на andrey@gubanov.eu.

Класс Matreshka

Путь к модулю CommonJS: 'matreshka/matreshka'

Класс Matreshka - ядро фреймворка Matreshka.js, от которого наследуются Matreshka.Array, Matreshka.Object и каждый класс создаваемого приложения. Он содержит основной функционал фреймворка: медиаторы, зависимости, привязки к DOM, движок событий и пр.

Как правило, этот класс, (как и Matreshka.Array и Matreshka.Object), не используются напрямую. Вместо этого, от него наследуются классы, создаваемые разработчиком.

Ссылки

Примеры

Создание экземпляра

const mk = new Matreshka();

Краткая запись: MK вместо Matreshka (для немодульного окружения)

const mk = new MK();

Наследование

class MyClass extends Matreshka {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Наследование при помощи функции Matreshka.Class

const MyClass = Matreshka.Class({
	'extends': Matreshka,
	constructor() {
		this.sayHello();
	},
	sayHello() {
		alert("Hello World!");
	}
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#bindNode(key, node, binder, eventOptions) object

Связывает свойство объекта с HTML элементом

Matreshka#bindNode - это единственный метод класса Matreshka, отвечающий за изменения DOM. Он создаёт мост между значением свойства и состоянием HTML элемента на странице: от простого инпута до сложного виджета (сложность элементов не ограничена). После связывания свойства экземпляра и HTML элемента не нужно больше следить за синхронизацией данных и представления.

Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой целевой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.

const bindNode = require('matreshka/bindnode');
const object = {};
bindNode(object, key, node, binder, eventOptions);
// вместо this.bindNode(key, node, binder, eventOptions);

Для двустороннего связывания элемента и значения свойства, в метод передаются три аргумента: имя свойства, HTML элемент и правило привязки (байндер, биндер, binder, привязчик). Байндер, в свою очередь, является обычным объектом и может иметь следующие свойства: on, getValue, setValue, initialize, destroy (подробнее см. binder). Все пять свойств опциональны. Это позволяет также объявлять и односторонние привязки.

Метод bindNode поддерживает привязки "многие ко многим". С одним свойством можно связать несколько элементов, а с одним элементом можно связать несколько свойств, в том числе и от разных экземпляров разных классов.

this.bindNode('myKey', '.my-element', {
    on: 'click',
    getValue() { ... },
    setValue() { ... }
});

Например, вы хотите связать свойство объекта с элементом input[type="checkbox"]:

this.bindNode('myKey', '.my-checkbox', {
    // когда менятся состояние элемента?
    // - по событию 'click'
    on: 'click',
    // как извлечь состояние элемента?
    // - вернуть значение 'checked'
    getValue() {
        return this.checked;
    },
    // как установить состояние элемента?
    // - установить значение 'checked'
    setValue(v) {
        this.checked = !!v;
    }
});

После объявления привязки можно устанавливать значение свойства объекта самым привычным способом, а элемент изменит своё состояние автоматически. При клике на чекбокс, значение свойства тоже изменится на соответствующее.

// устанавливает checked = true
this.myKey = true;

Более сложный пример: связывание свойства объекта с виджетом jQuery UI

<div class="my-slider"></div>
this.bindNode('myKey', '.my-slider', {
    // когда менятся состояние элемента?
    // - по событию 'slide'
    on: 'slide',
    // как извлечь состояние элемента?
    // - вернуть значение виджета 'value'
    getValue() {
        return $(this).slider('option', 'value');
    },
    // как установить состояние элемента?
    // - установить значение 'value'
    setValue(v) {
        $(this).slider('option', 'value', v);
    },
    // как инициализировать виджет?
    // инициализировать слайдер можно любым способом,
    // но initialize предоставляет немного синтаксического сахара
    initialize() {
        $(this).slider({ min: 0, max: 100 });
    }
});
// установит знaчeние слайдера 42
this.myKey = 42;

Выглядит просто, но вы, скорее всего, задаётесь вопросом: "Как сделать так, чтоб мне не пришлось каждый раз прописывать эти правила?". Действительно, на странице может быть очень много однотипных элементов: текстовых полей, выпадающих меню, новых полей из спецификации HTML5, могут быть и сторонние виджеты (о чем говорит пример выше).

Как видно из документации к аргументам метода bindNode, третий аргумент не обязателен. Этот вопрос решает массив Matreshka.defaultBinders, который содержит функции, проверяющие HTML элемент на соответствие заданным правилам и возвращающие соответствующий байндер или undefined. Появляется возможность многократно сократить код, вынося правила привязки в отдельную часть вашего кода, а для привязки использовать синтаксис без третьего аргумента:

this.bindNode('myKey', '.my-element');

Как это сделать? Нужно добавить функцию, проверяющую ваш элемент на соответствие некоторым правилам в начало массива Matreshka.defaultBinders.

const checkboxBinder = () => {
    return {
        on: 'click',
        getValue() {
            return this.checked;
        },
        setValue(v) {
            this.checked = !!v;
        }
    }
};

// метод unshift добавляет функцию
// в начало массива Matreshka.defaultBinders
Matreshka.defaultBinders.unshift(node => {
    // проверяем, является ли элемент чекбоксом
    if(node.tagName === 'INPUT' && node.type === 'checkbox') {
        // если проверка пройдена, возвращаем новый байндер
        return checkboxBinder();
    }
});
this.bindNode('myKey', '.my-checkbox');
this.myKey = true;

Что делать, если вам нужно передать аргументы для инициализации какого-нибудь плагина или виджета? Можно вручную вызывать функцию, возвращающую байндер.

const uiSlider = (min, max) => {
    return {
        on: 'slide',
        getValue() {
            return $(this).slider('option', 'value');
        },
        setValue(v) {
            $(this).slider('option', 'value', v);
        },
        initialize() {
            $(this).slider({ min: min, max: max });
        }
    }
};

this.bindNode('myKey1', '.my-slider1', uiSlider(0, 100));
this.bindNode('myKey2', '.my-slider2', uiSlider(1, 1000));
this.myKey1 = 42;
this.myKey2 = 999;

Для глобального доступа к байндеру, можно расширить Matreshka.binders.

Matreshka.binders.uiSlider = uiSlider;
// ...
this.bindNode('myKey1', '.my-slider1', Matreshka.binders.uiSlider(0, 100));
this.bindNode('myKey2', '.my-slider2', Matreshka.binders.uiSlider(1, 1000));

Matreshka.defaultBinders из коробки содержит поддержку всех без исключения HTML элементов форм: select (включая multiple), textarea, output, input (в том числе и все типы из спецификации HTML5: text, checkbox, radio, range, number, date, search, time, datetime, datetime-local, color и остальных). Это значит, что для стандартных элементов указывать байндер не обязательно.

<input type="color" class="my-color-input">
this.bindNode('myColor', '.my-color-input');
this.myColor = '#66bb6a';

После привязки, вам доступен новый нестандартный CSS селектор :bound(KEY).

this.bindNode('myKey', '.my-element');

// найдет элемент '.my-inner-element' внутри '.my-element'
this.bindNode('myAnotherKey', ':bound(myKey) .my-inner-element');

И расширяется синтаксис возможных имен событий:

this.bindNode('myKey', '.my-element');

// отловит клик на элементе .my-element
this.on('click::myKey', () => { ... });

// отловит клик на элементе .my-element .my-inner-element
this.on('click::myKey(.my-inner-element)', () => { ... });

Если элемент не найден, бросается исключение "Bound element is missing". Для того, чтоб избежать ошибки используйте метод Matreshka#bindOptionalNode

Создание песочницы

Matreshka#bindNode умеет ассоциировать экземпляр класса с "главным" HTML элементом, создавая так называемую песочницу. Это нужно для того, чтоб ограничить влияние объекта одним HTML элементом. Для привязки песочницы используется специальное свойство sandbox.

<div class="my-sandbox">
    <!-- your HTML code -->
</div>
this.bindNode('sandbox', '.my-sandbox');

Определение песочницы добавляет множество удобств программисту. Например:

Следует иметь в виду, что только один HTML элемент может быть связан со свойством sandbox, иначе бросается ошибка. Для объявления песочницы можно воспользоваться методом Matreshka#bindSandbox. Перед тем, как объявить байндинг, метод отвязывает предыдущую песочницу.

// объявляем песочницу
this.bindNode('sandbox', '.my-sandbox');

// .my-element ищется в песочнице
this.bindNode('myKey', ':sandbox .my-element');

// для делегированных событий внутри песочницы не требуется указывать ключ
this.on('click::(.my-button)', () => { ... });

// выведет в консоль элемент .inner-node,
// который находится внутри песочницы
console.log(this.$('.inner-node'));

Важные особенности работы метода и специальные флаги

Четвертым аргументом eventOptions в метод bindNode можно передать объект, состоящий из флагов, описанных ниже, глобальных флагов (например, silent), или кастомных данных, которые попадут в обработчики событий bind и bind:KEY.

this.on('bind:x', evt => {
    console.log(evt.foo); // bar
});
this.bindNode('x', node, binder, { foo: 'bar' });

Для ознакомления с важными тонкостями работы bindNode информация ниже обязательна к ознакомлению. При этом, имена флагов запоминать не обязательно.

Флаг exactKey=false

Если в качестве key передать строку, содержащую точку, то такая строка будет интерпритирована как путь к свойству во вложенном объекте. фреймворк будет слушать изменения во всём дереве, разрывая связь для старых ветвей, и создавая её для новых.

this.a = { b: { c: 'foo' } };
this.bindNode('a.b.c', node);

this.a.b.c = 'bar'; // обновит элемент значением bar

const oldB = this.a.b;

this.a.b = { c: 'baz' }; // обновит элемент значением baz

 // элемент не обновится, так как связь с этой ветвью разорвана
oldB.c = 'fuu';

В случае, если имя свойства должно быть использовано как есть, воспользуйтесь флагом exactKey со значением true.

this['a.b.c'] = 'foo';
this.bindNode('a.b.c', node, binder, {
    exactKey: true
});
this['a.b.c'] = 'bar';

Флаг getValueOnBind

При наличии у байндера getValue, состояние элемента будет извлечено и присвоено свойству сразу после вызова bindNode при условии, если привязываемое свойство имеет значение undefined. Для того, чтоб форсировать это поведение даже если свойство - не undefined используйте флаг getValueOnBind со значением true. Для отмены этого поведения, используйте тот же флаг со значением false.

Флаг setValueOnBind

При наличии у байндера setValue, значение свойства будет установлено в качестве состояния элемента сразу после вызова bindNode при условии, если привязываемое свойство имеет значение отличное от undefined. Для того, чтоб форсировать это поведение даже если свойство - undefined используйте флаг setValueOnBind со значением true. Для отмены этого поведения, используйте тот же флаг со значением false.

Флаги debounceGetValue=true и debounceSetValue=true

Важной особенностью метода bindNode является то, что к изменению свойств и изменению состояния элемента применяется микропаттерн debounce. Это значит, что если привязанное свойство будет изменено многократно за короткий промежуток времени (например, в цикле), состояние элемента будет обновлено лишь один раз после задержки в несколько миллисекунд (благодаря debounceSetValue=true). И наоборот: если состояние элемента меняется многократно за короткий промежуток времени (т. е. вызывается соответствующее DOM событие), свойство получит новое значение только один раз после короткой зарержки (благодаря debounceGetValue=true).

const input = document.querySelector('.my-input');
this.bindNode('x', input);
this.x = 'foo';
console.log(input.value === 'foo'); // false
setTimeout(() => {
    console.log(input.value === 'foo'); // true
});

Для отмены этого поведения, т. е. для отмены асинхронности действий, используйте флаги debounceSetValue и/или debounceGetValue со значением false.

Флаги debounceSetValueOnBind=false и debounceGetValueOnBind=false

Как говорилось выше, к изменению свойств и изменению состояния элемента применяется микропаттерн debounce. Это не касается самого момента связывания. При вызове bindNode установка состояния элемента или его извлечение с изменением свойства происходит синхронно. debounceSetValueOnBind и debounceGetValueOnBind установленные как true включают debounce и для этих процессов.

Флаги debounceSetValueDelay=0 и debounceGetValueDelay=0

Эти флаги позволяют указать задержку debounce. debounceSetValueDelay задаётся при использовании debounceSetValue и debounceSetValueOnBind, debounceGetValueDelay при использовании debounceGetValue и debounceGetValueOnBind.

Флаг useExactBinder=false

Даже если в метод bindNode передать конкретный байндер, фреймворк попытается отыскать байндер из Matreshka.defaultBinder и расширить его свойствами переданного объекта. Такая возможность позволяет использовать дефолтный байндер, который частично переопределен.

Например, мы хотим связать input[type="text"] со свойством. По умолчанию, стандартный байндер для этого элемента содержит свойство "on" со значением "input". Это значит, что значение свойства экземпляра и состояние элемента будут синхронизированы сразу после ввода или удаления символа пользователем. В случае, если вы хотите, чтоб синхронизация происходила по DOM событию "blur", вам потребуется передать третьим аргументом объект, содержащий единственное свойство "on". Этот объект объединится со стандартным байндером, сохранив при этом значения getValue и setValue.

this.bindNode('x', '.my-input', { on: "blur" });

Для отмены этого поведения и использования байндера как он есть, в объект события можно передать флаг useExactBinder со значением true.

this.bindNode('x', node, binder, {
    useExactBinder: true
})

Возвращает object - self

Генерирует события bind bind:KEY

Аргументы

Имя Тип Описание
key string

Имя свойства

node string node $nodes

HTML элемент, который должен быть связан со свойством объекта

binder optional binder

Байндер, содержащий свойства on, getValue, setValue, initialize, destroy, см. binder.

eventOptions optional eventOptions

Объект события, в который можно передать ключ "silent" (чтоб не генерировать события "bind" и "bind:KEY"), флаги, описанные выше или кастомные данные

Ссылки

Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#bindNode(bindings, binder, eventOptions) object

Альтернативный синтаксис Matreshka#bindNode: возможность передать объект с байндингами

В метод Matreshka#bindNode можно передать объект чтобы избежать многократного вызова метода и сократить код. Ключи объекта - это имена привязываемых свойств, а значения могут быть следующими:

  • HTML элемент
  • Объект со свойствами node (HTML элемент) и binder
  • Массив объектов со свойствами node (HTML элемент) и binder

Если binder передан вторым аргументом, то он служит байндером для тех элементов, для которых байднер не указан явно.

Возвращает object - self

Аргументы

Имя Тип Описание
bindings object

(см. пример)

binder optional binder

(см. выше)

eventOptions optional eventOptions

(см. выше)

Примеры

this.bindNode({
	foo: '.custom-checkbox',
	'bar.length': 'textarea'
});
this.bindNode({
	foo: {
		node: ':sandbox .aaa',
		binder: Matreshka.binders.html()
	},
	bar: '.bbb',
	baz: [{
		node: '.ccc'
	}, {
		node: document.querySelector('.ddd'),
		binder: Matreshka.binders.prop('baz')
	}]
}, {
	// will be used as a binder for .bbb and .ccc
	setValue(value) {
		foo(value);
	}
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#bindNode(batch, commonEventOptions) object

Альтернативный синтаксис, позволяющий объявить неограниченное количество байндингов одним вызовом метода.

Вариация метода позволяет передать массив объектов, содержащих информацию об одном байндинге каждый. Элемент массива должен содержать следующие свойства:

  • key - имя свойства
  • node - элемент, для которого объявляем связывание с key
  • binder - байндер (не обязательно)
  • event - объект события (не обязательно)

Второй аргумент - общий объект события, расширяющий event для каждого байндинга (свойства из event приоритетнее).

Возвращает object - self

Аргументы

Имя Тип Описание
batch array

Массив байндингов

commonEventOptions optional eventOptions

Общие для всех объектов события свойств

Примеры

this.bindNode([{
	key: 'a',
	node: '.my-node',
	binder: {
		setValue(v) {
			doSomething(v);
		}
	}
}, {
	key: 'b',
	node: document.querySelectorAll('.bar')
	event: {
		foo: 'bar'
	}
}, {
	key: 'c.d.e',
	node: jQuery('.baz'),
	binder: Matreshka.binders.html(),
	event: {
		silent: true,
		exactKey: true
	}
}], {
	getValueOnBind: false
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#bindOptionalNode()

Работает в точности так же, как и Matreshka#bindNode но не бросает исключение, если аргумент node - пустой массив, undefined или не существует

У метода есть статичный аналог.

Ссылки

Примеры

this.bindOptionalNode('myKey', '.my-element');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#bindSandbox(node, eventOptions)

Привязывает песочницу

При этом, "отвязывает" предыдущую, если таковая существует.

У метода есть статичный аналог.

Генерирует события bind bind:sandbox

Аргументы

Имя Тип Описание
node string node $nodes

Элемент, который должен стать песочницей

eventOptions optional eventOptions

Объект события

Ссылки

Примеры

this.bindSandbox('.my-element');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#calc(target, source, handler=(v)=>v, eventOptions)

Создает зависимость значения одного свойства от значений других

Метод calc создает зависимость значения свойства (аргумент target) от значений других свойств (аргумент source). При изменении source, target вычисляется автоматически.

Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.

const calc = require('matreshka/calc');
const object = {};
calc(object, target, source, handler, eventOptions);
// вместо this.calc(target, source, handler, eventOptions);

Аргумент source имеет несколько вариаций.

Строка

Свойство target будет зависеть от свойства source.

this.b = 1;
this.calc('a', 'b', b => b * 2);
console.log(this.a); // 2

Массив строк

Свойство target будет зависеть от свойств, перечисленных в source.

this.b = 1;
this.c = 2;
this.d = 3;
this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d);
console.log(this.a); // 6

Объект со свойствами object и key

В этом случае можно объявить зависимость свойства target от другого объекта.

const someObject = { b: 1 };
this.calc('a', {
    object: someObject,
    key: 'b'
}, b => b * 2);

console.log(this.a); // 2

В качестве свойства key в объект можно передать массив ключей.

const someObject = {
    b: 1,
    c: 2,
    d: 3
};
this.calc('a', {
    object: someObject,
    key: ['b', 'c', 'd']
}, (b, c, d) => b + c + d);

console.log(this.a); // 6

Массив объектов со свойствами object и key

Так можно объявить зависимость свойства от свойств разных объектов.

const someObjectX = {
    b: 1,
    c: 2
};
const someObjectY = {
    d: 3
};
this.calc('a', [{
    object: someObjectX,
    key: ['b', 'c']
}, {
    object: someObjectY,
    key: 'd'
}], (b, c, d) => b + c + d);

console.log(this.a); // 6

Массив, комбинирующий строки (собственные свойства) и объекты

this.b = 1;
this.c = 2;

const someObject = {
    d: 3,
    e: 4
};

this.calc('a', ['b', 'c', {
    object: someObjectX,
    key: ['d', 'e']
}], (b, c, d, e) => b + c + d + e);

console.log(this.a); // 10

Из соображений чистоты кода, комбинировать строки и объекты в массиве source не рекомендуется. Вместо строк лучше передать объект, у которого свойство object равно целевому объекту. Пример ниже делает то же самое, что и предыдущий.

this.b = 1;
this.c = 2;

const someObject = {
    d: 3,
    e: 4
};

this.calc('a', [{
    object: this, // целевой объект - это this
    keys: ['b', 'c']
}, {
    object: someObjectX,
    key: ['d', 'e']
}], (b, c, d, e) => b + c + d + e);

console.log(this.a); // 10

Точка в имени свойства-источника

Если имя ключа содержит точку, метод инициирует зависимость от свойства во вложенном объекте.

this.b = { c: { d: 1 } };
this.e = { f: { g: 2 } };

this.calc('a', ['b.c.d', 'e.f.g'], (d, g) => d + g);

console.log(this.a); // 3

То же самое касается и внешних объектов

this.b = { c: { d: 1 } };
const someObject = { e: { f: { g: 2 } } };

this.calc('a', [{
    object: this
    key: 'b.c.d'
}, {
    object: someObject
    key; 'e.f.g'
}], (d, g) => d + g);

console.log(this.a); // 3

Метод защищен от цикличных зависимостей (например a зависит от b, b зависит от c, а c зависит от a) и при ошибке вычислений не блокирует страницу и не бросает исключение о переполнении стека.

Как вы могли заметить, аргументы функции handler всегда расположены в том же порядке, что и свойства из source.

В случае, если нужно изменить значение свойства-источника и сделать это так, чтоб целевое свойство не было вычислено заново, используйте метод Matreshka#set с флагом skipCalc равным true.

this.calc('a', 'b', handler);
this.set('b', newValue, {
    skipCalc: true
});

Важные особенности работы метода и специальные флаги

Четвертым аргументом в метод calc можно передать объект события eventOptions, содержащий специальные флаги, которые описаны ниже, флаги для метода set (например, silent), либо кастомные данные, которые передаются в обработчик события change:KEY.

this.on('change:a', evt => {
    console.log(evt.foo); // 'bar'
});

this.calc('a', source, handler, { foo: 'bar' });

Флаг debounceCalc=true

При вызове метода calc целевое свойство вычисляется без задержек, но при изменении свойства-источника применяется паттерн debounce. Это значит, что целевое свойство изменится через несколько миллисекунд и только один раз, даже если свойства-источники изменились многократно за короткий промежуток времени.

this.b = 1;
this.c = 2;
this.d = 3;

this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d);

this.on('change:a', () => {
    // обработчик будет вызван один раз несмотря на то,
    // что свойства-источники изменились трижды
    console.log(`a is changed to ${this.a}`); // a is changed to 60
});

this.b = 10;
this.c = 20;
this.d = 30;
console.log(this.a); // 6 вместо 60

Для отмены debounce при изменении свойств, т. е. для включения моментального обновления целевого свойства (как было в предыдущих версиях метода), четвертым аргументом метода calc можно передать флаг debounceCalc равный false.

this.b = 1;
this.c = 2;
this.d = 3;

this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d, {
    debounceCalc: false
});

this.on('change:a', () => {
    // обработчик будет вызван трижды,
    // каждый раз когда свойства b, c или d меняются

    // a is changed to... 15, 33, 60
    console.log(`a is changed to ${this.a}`);
});

this.b = 10;
this.c = 20;
this.d = 30;
console.log(this.a); // 60

Флаг debounceCalcOnInit=false

Как говорилось выше, при вызове метода calc целевое свойство вычисляется сразу, а при изменении свойств-источников - нет. Включить debounce и при первом вычислении свойства можно передав в качестве свойства объекта события флаг debounceCalcOnInit=true.

this.on('change:a', () => {
    // обработчик будет вызван один раз через небольшой промежуток времени
    console.log(`a is changed to ${this.a}`); // a is changed to 6
});

this.b = 1;
this.c = 2;
this.d = 3;

this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d, {
    debounceCalcOnInit: true
});

console.log(this.a); // undefined

На практике debounceCalcOnInit вряд ли пригодится. Нужно лишь помнить, что есть флаг включающий "полный debounce".

Флаг debounceCalcDelay=0

Флаг позволяет указать задержку debounce при использовании debounceCalc и debounceCalcOnInit.

Флаг setOnInit=true

Известно, что при вызове метода calc свойство сразу получает новое значение. Для того, чтоб отменить это поведение и вычислить свойство target только тогда, когда свойство-источник впервые изменено, используйте флаг setOnInit равный false.

this.calc('a', 'b', b => b * 2, {
    setOnInit: false
});

console.log(this.a); // undefined

// но если обновить this.b, для свойства a будет вычислено новое значение
this.b = 1;

Флаг exactKey=false

Как говорилось выше, в качестве имени свойства-источника можно передать строку, содержащую точки. Такое имя будет истолковано как путь к свойству во вложенном объекте. В случае, если имя должно быть использовано как есть, воспользуйтесь флагом exactKey со значением true.

this['foo.bar.baz'] = 1;
this.calc('a', 'foo.bar.baz', fooBarBaz => fooBarBaz * 2, {
    exactKey: true
});
console.log(this.a); // 2

Флаг promiseCalc=false

Этот флаг позволяет использовать экземпляры Promise внутри функции, вычисляющей значение. Значением искомого свойства становится результат успешного выполнения промиса.

Внимание! Promise невозможно отменить. Используйте возможность promiseCalc аккуратно и не допускайте многократного вызова тяжелых функций.

this.calc('a', ['b', 'c'], (b, c) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(a + b)
        }, 1000);
    });
}, {
    promiseCalc: true
});

this.b = 1;
this.c = 2;

// "a" изменится через секунду
this.calc('response', 'data', async (data) => {
    const resp = await fetch(url, {
        method: 'post',
        body: data
    });

    return resp.json();
}, {
    promiseCalc: true
});

Аргументы

Имя По умолчанию Тип Описание
target string

Имя свойства которое зависит от других свойств

source string array

От каких свойств зависит искомое свойство (см. описание выше)

handler optional (v)=>v function

Функция, возвращающая новое значение

eventOptions optional eventOptions

Объект, в который можно передать какие-нибудь данные для обработчика события, слушающего изменения target или специальные флаги (см. описание метода)

Примеры

this.calc('greeting', 'name', name => `Hello, ${name}!`);

this.name = 'World';

// ... in a moment
alert(this.greeting); // 'Hello, World!'

Вычисление периметра прямоугольника по двум сторонам (и сторон по периметру)

this.a = 3;
this.b = 4;

this
    .calc('p', ['a', 'b'], (a, b) => (a + b) * 2)
    .calc('a', ['p', 'b'], (p, b) => p/2 - b)
    .calc('b', ['p', 'a'], (p, a) => p/2 - a);

alert(this.p); // 14

this.on('change:p', () => {
    // "периметр изменен и равен 18"
    console.log(`периметр изменен и равен ${this.p}`);
});

this.a = 5;
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#calc(batch, commonEventOptions)

Дополнительная возможность метода Matreshka#calc, позволяющая объявить несколько вычислимых свойств одним вызовом

Первый аргумент - объект, ключи которого - имена свойств, которые нужно вычислять, а значения - объекты, содержащие:

  • source - свойства, от которых зависит целевое свойство;
  • handler - как именно будет вычислено свойство (по умолчанию равен (value) => value);
  • event - объект события (не обязательно).

Второй аргумент - общий объект события, расширяющий event для каждого искомого свойства (свойства из event приоритетнее).

source может принимать любой вид описаный выше (строка, массив строк, объект со свойствами key и object, массив объектов).

Аргументы

Имя Тип Описание
batch array

Объект содержащий информацию о вычислимых свойствах

commonEventOptions optional eventOptions

Общие свойства для объектов события

Примеры

this.calc({
	x: {
    	source: ['a', 'b'],
    	handler: (a, b) => a + b
	},
	y: {
	    source: {
	        object: someObject,
	        key: 'c'
	    },
	    event: {
	        setOnInit: false
	    }
	},
	z: {
	    source: [{
	        object: this,
	        key: 'x'
	    }, {
	        object: someObject,
	        key: 'd'
	    }],
	    handler: (x, d) => x + d
	}
}, {
    debounceCalc: false
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#instantiate(key, class, updateCallback) object

Создаёт фиксированный экземпляр класса

Обратите внимание, что у метода есть статичный аналог.

Метод создаёт и фиксирует экземпляр класса в качестве значения заданного свойства. При попытке переопределить свойство, вместо самого переопределения, экземпляр обновляется. Таким образом достигается целостность приложения, сделанном на базе Matreshka.

Метод является надстройкой над Matreshka#mediate и переопределяет медиатор.

Экземпляр класса создается во время запуска метода instantiate. Первым аргументом конструктора класса становится текущее значение свойства. В конструкторе класса необходимо предусмотреть то, что в него попадет либо undefined (если свойство не содержало до этого никаких данных), либо объект, с которым нужно что-то сделать (например, расширить экземпляр класса свойствами объекта).

На деле это выглядит просто: вы создаете обычный класс, который почти всегда принимает какие-нибудь данные, которые нужно обработать (например, использовать их в методе Matreshka.Object#setData).

При попытке присвоить свойству другое значение, внутренний механизм метода instantiate, вместо присваивания, делает следующее:

  • Если указана функция updateCallback, метод запускает его с двумя аргументами: текущим значением свойства и данными, которые код пытается присвоить.
  • Если заданный класс унаследован от Matreshka.Object, экземпляр обновляется новыми данными, используя метод Matreshka.Object#setData с флагом replaceData=true.
  • Если заданный класс унаследован от Matreshka.Array, экземпляр обновляется новыми данными, используя метод Matreshka.Array#recreate.
  • Если не указана функция updateCallback и если класс не унаследован от Matreshka.Object или Matreshka.Array, экземпляр расширяется свойствами объекта, который код пытается присвоить.

Особенностью метода является отсутствие ограничений на источник класса. В качестве класса может выступать любая функция-конструктор. которая инициализируется с помощью оператора new, а не только наследники Matreshka.

Возвращает object - self

Аргументы

Имя Тип Описание
key string array

Имя свойства или массив имен свойств

class function

Класс, чей экземпляр становится значением свойства

updateCallback optional function

Функция, вызывающаяся при каждой попытке присвоить новые данные свойству, позволяющая кастомизировать логику обновления экземпляра класса новыми данными. Функция принимает два аргумента: текущее значение свойства (экземпляр класса) и данные, которые пытаются присвоить.

Примеры

class MyClass {
    // ...
}

// ...

this.instantiate('x', MyClass);

// пытаемся присвоить свойству другое значение
this.x = { a: 42 };

// this.x по-прежнему экземпляр класса MyClass
alert(this.x instanceof MyClass); // true
alert(this.x.a); // 42

Использование updateCallback.

this.instantiate('x', MyClass, (instance, data) => {
	updateSomeHow(instance, data);
});

Получение родителя и имени свойства. Кроме данных (первый аргумент), в конструктор создаваемого класса, передается ссылка на объект, вызвавший instantiate и имя созданного свойства

class MyClass extends Matreshka {
	constructor(data, parent, key) {
		// parent - это экземпляр MyParentClass,
        // который создал свойство
		// key - имя свойства ("х")
	}
}

const MyParentClass extends Matreshka {
    constructor() {
        this.instantiate('x', MyClass);
    }
}

Нестандартный способ использования updateCallback для игнорирования любых изменений свойства.

this.instantiate('x', SubClass, () => {});

В случае, если ваш класс не подерживает использование оператора new, вместо instantiate воспользуйтесь методом Matreshka#mediate.

this.mediate('x', (data, currentValue) => {
	return currentValue instanceof SomeClass
		? Object.assign(currentValue, data)
		: SomeLib.initInstance(SomeClass, data);
});

Абстрактный пример с данными большой вложенности (для краткости используется синтаксис class instance fields)

// app.js
class App extends Matreshka {
	constructor(appData) {
		this.appData = appData;
		this.instantiate('appData', AppData);
	}
}

// app-data.js
class AppData extends Matreshka.Object {
	constructor(data) {
		super(data)
			.instantiate({
				friends: Friends,
				settings: Settings
			});
	}
}

// friend.js
class Friend extends Matreshka.Object {
	constructor(data) {
		super(data);
	}
}

// friends.js
class Friends extends Matreshka.Array {
	Model = Friend;
	trackBy = 'id';
	constructor(data) {
		super(...data);
	}
}

// settings.js
class Settings extends Matreshka.Object {
	constructor(data) {
		super(data)
			.instantiate('credentials', Credentials);
	}
}

// credentials.js
class Credentials extends Matreshka.Object {
	constructor(data) {
		super(data);
	}
}

// app-init.js
var app = new App({
	settings: {
		name: 'Vasiliy Vasiliev',
		credentials: {
			email: 'vasia.vasia@gmail.com'
		}
	},
	friends: [{
		name: 'Yulia Zuyeva',
		id: 1
	}, {
		name: 'Konstantin Konstantinopolsky',
		id: 2
	}, {
		name: 'nagibator3000',
		id: 3
	}]
});

// данные можно сериализовать и передать на сервер
JSON.stringify(app.appData);

// потом просто присвоить новые данные свойству appData
// при этом, структура классов не изменится
app.appData = {
	settings: {
		name: 'Petr Petrov',
		credentials: {
			email: 'petr.petrov@gmail.com'
		}
	},
	friends: [{
		name: 'Yulechka Zuyeva',
		id: 1
	}, {
		name: 'Konstantin Konstantinopolsky',
		id: 2
	}]
};
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#instantiate(keyClassPairs, updateCallback) object

Альтернативный синтаксис метода Matreshka#instantiate, принимающий в качестве аргумента объект "ключ-класс"

Возвращает object - self

Аргументы

Имя Тип Описание
keyClassPairs object

Объект со свойствами ключ-класс

updateCallback optional function

Функция, вызывающаяся при каждой попытке присвоить новые данные свойству.

Примеры

this.instantiate({
	x: Class1,
	y: Class2,
	z: Class3
}, (instance, data) => {
	instance.doSomethingWith(data);
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#mediate(key, mediator)

Трансформирует значение свойства при его изменении

Этот метод используется для преобразования значения свойства при его изменении. Например, вам нужно, чтоб значение свойства всегда было либо определенного типа, либо целым числом, либо быть не менее нуля и не более ста и т. д.

Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.

const mediate = require('matreshka/mediate');
const object = {};
mediate(object, key, mediator);
// вместо this.mediate(key, mediator);

Аргументы

Имя Тип Описание
key string array

Имя свойства или массив имен

mediator function

Функция-посредник (медиатор, mediator), возвращающая новое значение. В неё передаются следующие аргументы: новое значение, предыдущее значение, имя свойства, сам объект

Примеры

this.mediate('x', value => String(value));
this.x = 1;
alert(typeof this.x); // "string"

Массив ключей

this.mediate(['x', 'y'], value => String(value));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#mediate(keyMediatorPairs)

Альтернативный синтаксис метода Matreshka#mediate, принимающий в качестве аргумента объект "ключ-медиатор"

Аргументы

Имя Тип Описание
keyMediatorPairs object

Объект со свойствами ключ-медиатор

Примеры

this.mediate({
	x: String,
	y: Number,
	z: Boolean
});
this.x = 1;
this.y = 2;
this.z = 3;
alert(typeof this.x); // "string"
alert(typeof this.y); // "number"
alert(typeof this.z); // "boolean"
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#off(names, callback, context) matreshka

Удаляет обработчик события

Удаляет созданный ранее обработчик. Все три аргумента опциональны. Вы можете удалить как все события (не передавая ни одного аргумента), так и отдельные (передав только имя события, передав имя события и обработчик, передав и имя события, и обработчик, и контекст)

Возвращает matreshka - self

Генерирует события removeevent removeevent:NAME

Аргументы

Имя Тип Описание
names optional eventNames

Разделенный пробелами список имен событий (например, "change:x ajaxcomplete change:y")

callback optional eventHandler

Функция-обработчик

context optional object

Контекст

Ссылки

Примеры

this.off('change:x bind');

Удаление всех событий

this.off();

Удаление события с определенным обработчиком

const handler = function() {
	//...
}
this.on('change:x', handler);
this.off('change:x', handler);

Удаление события с определенным контекстом

const object = {};
this.on('change:x', handler, object);
this.off('change:x', handler, object);
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#on(names, callback, triggerOnInit, context) object

Добавляет обработчик события

Метод Matreshka#on добавляет обработчик события для экземпляра класса Matreshka. Полный список возможных событий с описанием см. здесь: eventNames.

Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.

const on = require('matreshka/on');
const object = {};
on(object, names, callback, triggerOnInit, context);
// вместо this.on(names, callback, triggerOnInit, context);

Возвращает object - self

Генерирует события addevent addevent:NAME

Аргументы

Имя Тип Описание
names eventNames

Имя события или несколько имен, разделенных пробелом (например, "change:x ajaxcomplete change:y")

callback eventHandler

Функция, которая вызывается по событию

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчик будет вызван немедленно после инициализации.

context optional object

Контекст обработчика. Другими словами, this при вызове callback

Ссылки

Примеры

this.on('foo', () => {
	alert('Custom Event is fired');
});

this.trigger('foo');

Передача контекста

this.on('foo', function() {
	alert(this.a); // 5
}, { a: 5 });

this.trigger('foo', 'Hello world');

Вызов обработчика сразу после инициализации

//Выводит на экран "bar" сиюсекундно и ждет события "foo"
this.on('foo', () => {
	alert('bar');
}, true);
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#on(evtnameHandlerObject, triggerOnInit, context) object

Альтернативный синтаксис: пары "событие-обработчик"

В метод Matreshka#on можно передать объект с парами событие-обработчик, чтобы избежать многократного вызова метода и сократить код.

Возвращает object - self

Аргументы

Имя Тип Описание
evtnameHandlerObject object

Объект с событиями

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчики будут вызван немедленно после инициализации

context optional object

Контекст обработчика

Примеры

this.on({
	'custom': evt => ...,
	'click::x': evt => ...,
	'change:y': evt => ...,
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#onDebounce(names, callback, debounceDelay, triggerOnInit, context) object

Добавляет обработчик события, вызываемый лишь однажды за определенный промежуток времени

Метод позволяет добавить обработчик события на экземпляр класса Matreshka, устраняя "дребезжание" обработчика. Функция может быть вызвана лишь один раз за определенный промежуток времени. В остальном, метод работает так же, как и Matreshka#on.

У метода есть статичный аналог.

Возвращает object - self

Генерирует события addevent addevent:NAME

Аргументы

Имя Тип Описание
names eventNames

Имя события или несколько имен, разделенных пробелом (например, "change:x ajaxcomplete change:y").

callback eventHandler

Функция, которая вызывается по событию

debounceDelay optional number

Задержка

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчик будет вызван немедленно после инициализации

context optional object

Контекст обработчика. Другими словами, this при вызове callback

Ссылки

Примеры

this.onDebounce('change:x', () => {
	alert(`x = ${this.x}`); // x = 100
}, 300);

this.x = 1;

for(let i = 0; i < 100; i++) {
	this.x++;
}
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#onDebounce(evtnameHandlerObject, debounceDelay, triggerOnInit, context) object

Альтернативный синтаксис: пары "событие-обработчик"

В метод Matreshka#onDebounce можно передать объект с парами событие-обработчик, чтобы избежать многократного вызова метода и сократить код.

Возвращает object - self

Аргументы

Имя Тип Описание
evtnameHandlerObject object

Объект с обработчиками событий

debounceDelay optional number

Задержка

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчики будут вызван немедленно после инициализации

context optional object

Контекст обработчиков

Ссылки

Примеры

this.onDebounce({
	'custom': evt => { ... },
	'click::x': evt => { ... },
	'change:y': evt => { ... }
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#once(names, callback, context) object

Добавляет обработчик событий, который может быть вызван однажды

Метод работает так же, как и Matreshka#on но передаваемый обработчик может быть вызван только один раз.

Обратите внимание, что у метода есть статичный аналог

Возвращает object - self

Генерирует события addevent addevent:NAME

Аргументы

Имя Тип Описание
names eventNames

Имя события или несколько имен, разделенных пробелом (например, "change:x ajaxcomplete change:y")

callback eventHandler

Функция, которая вызывается по событию

context optional object

Контекст обработчика

Ссылки

Примеры

this.x = 1;

this.once('change:x', () => {
	alert('x is changed');
});

this.x = 2; // выводит 'x is changed'

this.x = 3; // ничего не делает
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#once(evtnameHandlerObject, context) object

Альтернативный синтаксис: пары "событие-обработчик"

В метод Matreshka#once можно передать объект с парами событие-обработчик, чтобы избежать многократного вызова метода и сократить код.

Возвращает object - self

Аргументы

Имя Тип Описание
evtnameHandlerObject object

Объект с событиями

context optional object

Контекст обработчиков

Ссылки

Примеры

this.once({
	'custom': evt => { ... },
	'click::x': evt => { ... },
	'change:y': evt => { ... }
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#parseBindings(node, eventOptions) $nodes

Парсит DOM дерево, объявляя привязки свойств, заключенных в двойные фигурные скобки.

Начиная с версии 1.1, Matreshka.js включает в себя простой DOM парсер, обрабатывающий синтаксические конструкции, заключенные в двойные фигурные скобки. Метод parseBindings первым аргументом принимает HTML строку, DOM узел или селектор, соответствующий DOM узлу.

Так как метод является DOM шаблонизатором (а не строковым HTML шаблонизатором), все дочерние DOM узлы переданного элемента остаются в своём прежнем состоянии (например, DOM события не затираются).

Поддерживаемый синтаксис.

  1. HTML привязка

    <!--
    Создаст текстовый узел на месте {{user.name}}
    и свяжет свойство name из объекта user с этим узлом
    JS: this.user = {name: 'Joe'}
    -->
    <span>Hello, {{user.name}}</span>
    
  2. Привязка элементов форм.

    <!--
    Свяжет свойство "x" экземпляра с текстовым
    полем (двусторонняя привязка)
    JS: this.x = 'some value';
    -->
    <input type="text" value="{{x}}">
    
    <!--
    Для привязки textarea и select нужно использовать атрибут value
    -->
    <textarea value="{{x}}"></textarea>
    <select value="{{x}}">...</select>
    
    <!--
    Свяжет свойство "x" экземпляра с чекбоксом
    (двусторонняя привязка)
    JS: this.x = true;
    -->
    <input type="checkbox" checked="{{x}}">
    
  3. Привязка атрибутов.

    <!--
    Значение атрибута href будет зависеть
    от значений свойств "category" и "someObject.page"
    (односторонняя привязка)
    JS:
     this.category = 'matreshka';
     this.someObject = { page: 42 };
    -->
    <a href="http://example.com/{{category}}/{{someObject.page}}">A link</a>
    <!--
    Результат:
    <a href="http://example.com/matreshka/42">A link</a>
    -->
    

Если фигурные скобки не устраивают, поменяйте их на что-то другое, используя Matreshka.parserBrackets

Зачем нужен такой метод?

В случае, если вы разрабатываете большую форму со стандартными HTML5 полями, метод поможет сохранить время на объявление многочисленных привязок. Кроме этого, parseBindings полезен в случае создания очень простой коллекции, не требующей реализации сложной модели.

Возвращает $nodes - Коллекция DOM узлов, переданная в функцию в качестве аргумента

Аргументы

Имя Тип Описание
node string node $nodes

HTML строка, селектор, DOM узел или коллекция DOM узлов

eventOptions optional eventOptions

Объект события, который будет передан во все вызовы метода Matreshka#bindNode

Примеры

Парсинг заданного узла

this.parseBindings(node);

Парсинг узла по селектору

this.parseBindings('.my-node');

Парсинг HTML строки

const $node = this.parseBindings('<h3>Hello, {{name}}</h3>');
this.name = 'Arthur Philip Dent';
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#remove(key, eventOptions) matreshka

Удаляет свойство

Возвращает matreshka - self

Генерирует события delete delete:KEY

Аргументы

Имя Тип Описание
key string

Имя свойства или массив имен свойств, которые следует удалить

eventOptions optional eventOptions

Объект события

Примеры

this.remove('myKey');
this.remove(['myKey1', 'myKey2']);

Использование eventOptions

this.remove('myKey', {
	silent: true
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#select(selector) node null

Возвращает элемент из песочницы, соответствующий селектору

Метод очень похож на Matreshka#selectAll, но возвращает лишь один элемент или null

У метода есть статичный аналог.

Возвращает node null

Аргументы

Имя Тип Описание
selector string

Селектор

Примеры

this.bindNode('sandbox', '.app');
this.select('.my-element');
// то же самое, что и
this.nodes.sandbox.querySelector('.my-element');
// и то же самое, что и
$('.app').find('.my-element')[0];
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#selectAll(selector) $nodes

Синоним: Matreshka#$

Возвращает элементы из песочницы, соответствующие селектору

После создания песочницы методом Matreshka#bindNode, можно получать и использовать элементы, находящиеся в ней. Кроме этого, метод поддерживает селектор :bound(KEY).

У метода есть статичный аналог.

Возвращает $nodes

Аргументы

Имя Тип Описание
selector string

Cелектор

Примеры

this.bindNode('sandbox', '.app');
nodes = this.selectAll('.my-element');
// то же самое, что и
nodes = this.$('.my-element'); // $ - ссылка на метод selectAll
// то же самое, что и
nodes = this.$nodes.sandbox.find('.my-element');
// и то же самое, что и
nodes = $('.app').find('.my-element');

Селектор :bound(KEY)

this.bindNode('myKey', '.my-element');
nodes = this.selectAll(':bound(myKey) .my-another-element');
// то же самое, что и
nodes = this.$nodes.myKey.find('.my-another-element');
// и то же самое, что и
nodes = $('.my-element').find('.my-another-element');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#set(key, value, eventOptions)

Устанавливает значение свойства, позволяя передать объект события в качестве третьего аргумента

Список поддерживаемых флагов:

  • silent - не вызывать события change и change:KEY
  • silentHTML - не менять состояние привязанных элементов
  • force - вызвать события change и change:KEY даже если значение свойства не изменилось
  • forceHTML - изменить состояние привязанного элемента, даже если значение свойства не изменилось. Эта опция нужна, если привязанный элемент был отрисован после привязки (например, в select были добавлены теги option)
  • skipMediator - предотвращает трансформацию свойства медиатором (см. Matreshka#mediate)
  • skipCalc - предотвращает работу зависимостей, созданных с помощью Matreshka#calc

У метода есть статичный аналог.

Генерирует события change change:KEY beforechange beforechange:KEY

Аргументы

Имя Тип Описание
key string

Ключ

value *

Значение

eventOptions optional eventOptions

Объект события

Примеры

this.on('change:myKey', evt => {
	alert(evt.value);
});

// то же самое, что и this['myKey'] = 3
// или this.myKey = 3
// выводит на экран 3
this.set('myKey', 3);

Используя eventOptions

this.on('change:myKey', evt => {
	alert(evt.value);
});

// alert не срабатывает
this.set('myKey', 4, {
	silent: true
});

Передача произвольных данных в обработчик

this.on('change:myKey', evt => {
	alert(evt.myCustomFlag);
});

// выводит на экран 42
this.set('myKey', 4, {
	myCustomFlag: 42
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#set(keyValuePairs, eventOptions)

Альтернативный синтаксис метода Matreshka#set "ключ-значение"

Аргументы

Имя Тип Описание
keyValuePairs object

Объект, содержащий пары ключ-значение

eventOptions optional eventOptions

Объект события

Примеры

this.set({
	myKey1: 1,
	myKey2: 2
});

Передача eventOptions в качестве второго аргумента

this.set({
	myKey: 3
}, {
	myFlag: 'foo'
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#trigger(names, arg) object

Генерирует событие

После добавление обработчиков событий с помощью метода Matreshka#on, Matreshka#onDebounce или Matreshka#once, событие можно генерировать вручную с помощью этого метода.

Обратите внимание, что у метода есть статичный аналог.

Возвращает object - self

Аргументы

Имя Тип Описание
names optional eventNames

Имя события или несколько имен, разделенных пробелом

arg optional *

Аргументы, которые будут переданы обработчикам

Ссылки

Примеры

this.on('foo bar', (a, b, c) => {
	alert(a + b + c);
});
this.trigger('bar', 1, 2, 3); // alerts 6
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#unbindNode(key, node, eventOptions) matreshka

Разрывает связь между свойством и HTML элементом

Используя этот метод, можно удалить недавно добавленную, но уже не нужную связь между свойством и элементом.

Возвращает matreshka - self

Генерирует события unbind unbind:KEY

Аргументы

Имя Тип Описание
key string null

Ключ или список ключей, разделенных пробелами. Если вместо ключа передать null, удалятся все привязки для данного экземпляра

node optional string node $nodes

HTML элемент, с которым свойство больше не хочет иметь дела

eventOptions optional eventOptions

Объект события, в который можно передать какие-нибудь данные для обработчика или ключ "silent", который отключает генерацию событий "unbind" и "unbind:KEY"

Примеры

this.bindNode('myKey', '.my-element');

// меняет значение свойства и состояние HTML элемента
this.myKey = true;

this.unbindNode('myKey', '.my-element');

// теперь меняется только значение свойства
this.myKey = false;
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#unbindNode(bindings, eventOptions) matreshka

Альтернативный синтаксис unbindNode, позволяющий передать объект с байндингами. См. Matreshka#bindNode(2)

Возвращает matreshka - self

Аргументы

Имя Тип Описание
bindings object

(см. пример)

eventOptions optional eventOptions

(см. выше)

Примеры

this.unbindNode({
	foo: '.aaa'
	bar: {
		node: '.bbb'
	},
	baz: [{
		node: '.ccc'
	}, {
		node: '.ddd'
	}]
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#unbindNode(batch, eventOptions)

Альтернативный синтаксис, позволяющий удалить неограниченное количество байндингов одним вызовом метода.

Вариация метода позволяет передать масссив объектов, содержащих информацию об одном байндинге каждый. Элемент массива должен содержать следующие свойства:

  • key - имя свойства
  • node - элемент, для которого был объявле байндинг с key (не обязательно)

Эта вариация метода удобна тем, что её синтаксис совпадает с одной из вариаций метода Matreshka#bindNode, позволяя присвоить байндинги переменной для быстрого удаления.

Аргументы

Имя Тип Описание
batch array

Массив байндингов

eventOptions optional eventOptions

(см. выше)

Примеры

const temporaryBindings = [{
	key: 'a',
	node: '.my-node',
	binder: {
		setValue(v) {
			doSomething(v);
		}
	}
}, {
	key: 'b',
	node: document.querySelectorAll('.bar')
	event: {
		foo: 'bar'
	}
}, {
	key: 'c.d.e',
	node: jQuery('.baz'),
	binder: Matreshka.binders.html(),
	event: {
		silent: true,
		exactKey: true
	}
}]

this.bindNode(temporaryBindings);

// больше не нужны эти привязки
this.unbindNode(temporaryBindings);
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#$nodes: $nodes

Объект содержит коллекции (jQuery, Zepto, инстанс встроенной микро-библиотеки, унаследованной от Array.prototype) привязанных элементов для быстрого доступа.

Ссылки

Примеры

this.bindNode('myKey', '.my-node');
this.$nodes.myKey; // то же самое, что и $('.my-node')
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka#nodes: node

Объект содержит привязанные элементы для быстрого доступа, в виде отдельных DOM узлов.

Обратите внимание, каждое свойство объекта содержит первый узел из связанных с соотвутствующим свойством. Для получения всех узлов, связанных с определенным свойством, используйте Matreshka#$nodes.

Ссылки

Примеры

this.bindNode('myKey', '.my-node');
this.nodes.myKey; // то же самое, что и $('.my-node')[0]
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Class(prototype, statics) class

Путь к модулю CommonJS: 'matreshka/class'

Реализация классов, основанная на прототипном наследовании

Функция Class позволяет использовать классическое ООП в тех случаях, когда нельзя воспользоваться синтаксисом ECMAScript 2015 classes.

Возвращает class - class (точнее, конструктор класса)

Аргументы

Имя Тип Описание
prototype object

Методы и свойства

statics optional object

Статичные методы и свойства

Примеры

const A = Matreshka.Class({
	method1() { ... }
});

const B = Matreshka.Class({
	// B наследуется от A
	extends: A,
	method2() { ... }
});

const C = Matreshka.Class({
	// С наследуется от B
	extends: B,
	method2() {
		// вызов родительского метода
		B.prototype.method2.apply(this, arguments);
	},
	method3(a, b) { ... }
});

const D = Matreshka.Class({
	// D наследуется от C
	extends: C,
	method3(a, b) {
		// вызов родительского метода
		C.prototype.method2.call(this, arguments);
	}
});

Передача объекта со статичными методами и свойствами

const MyClass = Matreshka.Class({
	method() { ... }
}, {
	staticProp: 'foo',
	staticMethod() {
		return 'bar';
	}
});

alert(MyClass.staticProp); // foo
alert(MyClass.staticMethod()); // bar
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.bindNode() object

Путь к модулю CommonJS: 'matreshka/bindnode'

Связывает свойство объекта с HTML элементом

Этот статичный метод работает так же, как и Matreshka#bindNode и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.bindNode(object, 'x', '.my-node');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.bindOptionalNode() object

Путь к модулю CommonJS: 'matreshka/bindoptionalnode'

Связывает элемент со свойством, но не бросает исключение, если аргумент node - пустой массив, undefined или не существует

Этот статичный метод работает так же, как и Matreshka#bindOptionalNode и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.bindOptionalNode(object, 'x', '.my-node');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.bindSandbox() object

Путь к модулю CommonJS: 'matreshka/bindsandbox'

Связывает свойство sandbox с элементом и отвязывает предыдущий элемент, если таковой существует

Этот статичный метод работает так же, как и Matreshka#bindSandbox и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.bindSandbox(object, '.my-node');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.calc() object

Путь к модулю CommonJS: 'matreshka/calc'

Создает зависимость значения одного свойства от значений других

Этот статичный метод работает так же, как и Matreshka#calc и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
object.a = 40;
object.b = 2;
Matreshka.calc(object, 'sum', ['a', 'b'], (a, b) => a + b);
alert(object.sum); // 42
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.chain(object) object

Путь к модулю CommonJS: 'matreshka/chain'

Позволяет вызывать универсальные методы цепочкой

Функция принимает любой объект и возвращает экземпляр недоступного извне класса, который перенимает универсальные методы, позволяя их цепной вызов для работы с переданным объектом.

Универсальные методы - это такие методы, которые одновременно есть в прототипе Matreshka и имеют статичный аналог (например, Matreshka#bindNode и Matreshka.bindNode).

Возвращает object - Экземпляр недоступного извне класса

Аргументы

Имя Тип Описание
object object function

Объект

Примеры

const object = {};
Matreshka.chain(object)
    .calc('a', 'b', b => b * 2)
    .set('b', 3)
    .bindNode('c', '.node');

// то же самое, что и
// Matreshka.calc(object, 'a', 'b', b => b * 2)
// Matreshka.set(object, 'b', 3)
// Matreshka.bindNode(object, 'c', '.node');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.instantiate() object

Путь к модулю CommonJS: 'matreshka/instantiate'

Создаёт фиксированный экземпляр класса

Этот статичный метод работает так же, как и Matreshka#instantiate и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.instantiate(object, 'x', SomeClass);
object.x = { a: 42 };
alert(this.x instanceof SomeClass); // true
alert(this.x.a); // 42
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.lookForBinder(node) binder

Путь к модулю CommonJS: 'matreshka/lookforbinder'

Возвращает байндер, соответствующий элементу. Если таковой не найден, возвращает undefined. Функция перебирает Matreshka.defaultBinders для поиска байндера.

Возвращает binder - binder

Аргументы

Имя Тип
node node

Ссылки

Примеры

const element = document.createElement('input');
element.type = 'text';

console.log(Matreshka.lookForBinder(element));

// вернет примерно такой объект
{
	on: 'input',
	getValue() {
		return this.value;
	},
	setValue(v) {
		this.value = v;
	}
}
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.mediate() object

Путь к модулю CommonJS: 'matreshka/mediate'

Трансформирует значение свойства при его изменении

Этот статичный метод работает так же, как и Matreshka#mediate и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.mediate(object, 'x', String);
object.x = 42;
alert(typeof object.x); // string
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.off() object

Путь к модулю CommonJS: 'matreshka/off'

Удаляет обработчик события

Этот статичный метод работает так же, как и Matreshka#off и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.on(object, 'foo', evt => {
	//...
});

Matreshka.off(object, 'foo');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.on() object

Путь к модулю CommonJS: 'matreshka/on'

Добавляет обработчик события

Этот статичный метод работает так же, как и Matreshka#on и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.on(object, 'foo', evt => {
	alert(evt.hello);
});

Matreshka.trigger(object, 'foo', { hello: 'World' });
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.onDebounce() object

Путь к модулю CommonJS: 'matreshka/ondebounce'

Добавляет обработчик события, вызываемый лишь однажды за определенный промежуток времени

Этот статичный метод работает так же, как и Matreshka#onDebounce и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.onDebounce(object, 'foo', evt => {
	//...
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.once() object

Путь к модулю CommonJS: 'matreshka/once'

Добавляет обработчик события, который может быть вызван однажды

Этот статичный метод работает так же, как и Matreshka#once и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.once(object, 'foo', evt => {
	//...
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.parseBindings() $nodes

Путь к модулю CommonJS: 'matreshka/parsebindings'

Парсит DOM дерево, объявляя привязки свойств, заключенных в двойные фигурные скобки.

Этот статичный метод работает так же, как и Matreshka#parseBindings и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает $nodes - Коллекция обработанных DOM узлов, переданная в функцию в качестве аргумента

Ссылки

Примеры

const object = {};
const $node = Matreshka.parseBindings(object, `<h3>
        Hello, {{name}}
    </h3>`);
object.name = 'World';
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.remove() object

Путь к модулю CommonJS: 'matreshka/remove'

Удаляет свойство

Этот статичный метод работает так же, как и Matreshka#remove и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

Matreshka.remove(object, 'x');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.select() node null

Путь к модулю CommonJS: 'matreshka/select'

Возвращает элемент из песочницы, соответствующий селектору

Этот статичный метод работает так же, как и Matreshka#select и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает node null - найденный элемент

Ссылки

Примеры

const object = {};
Matreshka.bindNode(object, 'sandbox', '.app');
Matreshka.select(object, '.my-element');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.selectAll() $nodes

Путь к модулю CommonJS: 'matreshka/selectall'

Возвращает элементы из песочницы, соответствующие селектору

Этот статичный метод работает так же, как и Matreshka#selectAll и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает $nodes - найденные элементы

Ссылки

Примеры

const object = {};
Matreshka.bindNode(object, 'sandbox', '.app');
Matreshka.selectAll(object, '.my-element');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.set() object

Путь к модулю CommonJS: 'matreshka/set'

Устанавливает значение свойства, позволяя передать объект события в качестве третьего аргумента

Этот статичный метод работает так же, как и Matreshka#set и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.set(object, 'x', 42, {
	someOption: true
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.toMatreshka() matreshka

Путь к модулю CommonJS: 'matreshka/tomatreshka'

Функция, конвертирующая произвольную структуру объектов и массивов в экземпляры Matreshka.Object и Matreshka.Array

Возвращает matreshka - новосозданный экземпляр Matreshka

Примеры

const mk = Matreshka.toMatreshka({
	a: 1,
	b: {
		c: 2
	},
	d: [{e: 1}, {e: 2}, {e: 3}]
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.trigger() object

Путь к модулю CommonJS: 'matreshka/trigger'

Генерирует событие

Этот статичный метод работает так же, как и Matreshka#trigger и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.on(object, 'foo', evt => {
	alert(evt.hello);
});

Matreshka.trigger(object, 'foo', { hello: 'World' });
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.unbindNode() object

Путь к модулю CommonJS: 'matreshka/unbindnode'

Разрывает связь между свойством и HTML элементом

Этот статичный метод работает так же, как и Matreshka#unbindNode и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

const object = {};
Matreshka.unbindNode(object, 'x', '.my-node');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.useDOMLibrary($)

Путь к модулю CommonJS: 'matreshka/usedomlibrary'

Заставляет использовать определенную библиотеку для работы с DOM

По умолчанию, Matreshka.js использует в качестве библиотеки ту, которая находится по ссылке window.$. Если такой переменной нет в глобальном пространстве имен, либо же она не включает в себя необходимый набор методов, то используется встроенная микро библиотека.

Метод useDOMLibrary заставляет фреймворк использовать ту библиотеку, которую вы захотите использовать, не смотря на отсутствие таковой в глобальном пространстве имен или по другой причине (например, если используется две разных версии jQuery на странице). Необходимо, чтобы метод был запущен перед объявлением каких-либо байндингов.

Аргументы

Имя Тип Описание
$ function

Любая библиотека (jQuery, Zepto, null для использования встроенной микро-библиотеки)

Примеры

Matreshka.useDOMLibrary(jQuery.noConflict());
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.defaultBinders: array

Путь к модулю CommonJS: 'matreshka/defaultbinders'

Массив функций, возвращающих соответствующий байндер или undefined

defaultBinders - массив функций, которые по очереди проверяют элемент на соответствие заданным в этих функциях правилам и возвращающих байндер (см. binder). Этот массив используется тогда, когда в метод Matreshka#bindNode не был передан третий аргумент. Подробную информацию о привязках смотрите в документации к Matreshka#bindNode.

Ссылки

Примеры

Matreshka.defaultBinders.unshift(element => {
	// проверяем, есть ли у элемента класс "foo"
	if(element.classList.contains('foo')) {
		// если проверка пройдена, возвращаем новый байндер
		return {
			on: ...,
			getValue: ...,
			setValue: ...
		};
	}
});

// ...

this.bindNode('myKey', '.foo.bar');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.parserBrackets: object

Путь к модулю CommonJS: 'matreshka/parserbrackets'

Содержит скобки для парсера

Объект parserBrackets позволяет изменить стандартный синтаксис парсера привязок. Он содержит два свойства: left (левая скобка, по умолчанию "{{") и right (правая скобка, по умолчанию "}}")

Примеры

Заменяет поведение парсера, используя синтаксис [[=property]] вместо {{property}}

Matreshka.parserBrackets.left = '[[=';
Matreshka.parserBrackets.right = ']]';
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders object

Путь к модулю CommonJS: 'matreshka/binders'

Пространство имен для байндеров. Из коробки содержит байндеры общего назначения (для связывания атрибутов и пр.). Этот объект можно расширять собственными свойствами, чтоб не засорять глобальное пространство имен.

Примите во внимание небольшое соглашение: каждое свойство из коллекции Matreshka.binders должно быть оформлено в виде функции (такие функции иногда называют "binder creator"), возвращающей байндер.

В этой документации свойства из Matreshka.binders используются напрямую, но для улучшения читаемости кода, рекомендуется выносить их в отдельные переменные.

const html = Matreshka.binders.html;

// ...
this.bindNode('x', node, html());

Либо импортировать в качестве CJS модуля:

// импорт сразу нескольких байндеров
import { html, text, prop } from 'matreshka/binders';

// импорт байндеров по-отдельности
import html from 'matreshka/binders/html';

Ссылки

Примеры

Matreshka.binders.myCoolBinder = (var1, var2) => {
	return {
		on: 'click',
		getValue() { ... },
		setValue() { ... },
		initialize() { ... },
		destroy() { ... }
	};
};

this.bindNode('myKey', '.my-element',
	Matreshka.binders.myCoolBinder('Hello', 'World'));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.attr(attribute, mappingFn) binder

Путь к модулю CommonJS: 'matreshka/binders/attr'

Возвращает байндер, меняющий атрибут DOM элемента на значение свойства объекта

Значение свойства можно преобразить с помощью переданной функции mappingFn.

Возвращает binder

Аргументы

Имя Тип Описание
attribute string

Имя атрибута

mappingFn optional function

Отображающая функция

Примеры

this.bindNode('image', 'img.my-image', Matreshka.binders.attr('src'));

this.image = 'http://example.com/cats.jpg';

Использование отображающей функции

this.bindNode('myKey', '.my-node',
    Matreshka.binders.attr('foo', value => `Hello, ${value}`));

this.myKey = 'World'; // атрибут foo имеет значение "Hello, World"
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.className(className, bool=true) binder

Путь к модулю CommonJS: 'matreshka/binders/classname'

Возвращает байндер, который переключает имя класса DOM элемента в зависимости от значения свойства объекта. Если значение свойства нестрого равно true, имя класса добавляется, в противном случае - убирается. Логику можно изменить, передав false вторым аргументом, и, таким образом, имя класса будет добавляться, когда значение свойства нестрого равно false и наоборот.

Возвращает binder

Аргументы

Имя По умолчанию Тип
className string
bool optional true boolean

Примеры

this.bindNode('myKey', '.my-element',
        Matreshka.binders.className('blah'));

this.myKey = true; // добавляет класс 'blah'

this.myKey = false; // убирает класс 'blah'
this.bindNode('myKey', '.my-element',
        Matreshka.binders.className('blah', false));

this.myKey = false; // добавляет класс 'blah'

this.myKey = true; // убирает класс 'blah'
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.dataset(property, mappingFn) binder

Путь к модулю CommonJS: 'matreshka/binders/dataset'

Возвращает байндер, меняющий заданное свойство объекта dataset DOM элемента в зависимости от значения свойства объекта.

Значение свойства можно преобразить с помощью переданной функции mappingFn.

Возвращает binder

Аргументы

Имя Тип Описание
property string

Свойство dataset

mappingFn optional function

Отображающая функция

Примеры

this.bindNode('myKey', '.my-element', Matreshka.binders.dataset('myProp'));
this.myKey = 'foo';

Использование отображающей функции

this.bindNode('myKey', '.my-element',
    Matreshka.binders.dataset('myProp', value => `Hello, ${value}`));
    
this.myKey = 'foo'; // атрибут data-my-prop имеет значение "Hello, foo"
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.display(bool=true) binder

Путь к модулю CommonJS: 'matreshka/binders/display'

Возвращает байндер для одностороннего связывания, меняющий видимость DOM элемента (используя style.display), в зависимости от значения свойства объекта

Возвращает binder

Аргументы

Имя По умолчанию Тип Описание
bool optional true boolean

Если аргумент равен true, то элемент прячется при ложном значении свойства, если равен false, прячется при правдивом значении

Примеры

this.bindNode('myKey', '.my-element', Matreshka.binders.display(true));
this.bindNode('myKey', '.my-element', Matreshka.binders.display(false));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.existence(bool=true) binder

Путь к модулю CommonJS: 'matreshka/binders/existence'

Возвращает байндер для одностороннего связывания, переключающий наличие элемента в DOM дереве, в зависимости от значения свойства объекта

Байндер работает так же, как и Matreshka.binders.display, но вместо изменения видимости элемента, изменяется наличие элемента на странице. Байндер полезен для:

  • Крупных приложений: в зависимости от состояния роутера показать ту или иную страницу;
  • Для реализации бесконечного скроллинга;
  • Для других задач, где нужно спрятать элемент, но его наличие в DOM дереве не обязательно.

Возвращает binder

Аргументы

Имя По умолчанию Тип Описание
bool optional true boolean

Если аргумент равен true, то элемент исчезает при ложном значении свойства, если равен false, исчезает при правдивом значении

Примеры

this.bindNode('myKey', '.my-element', Matreshka.binders.existence(true));
this.bindNode('myKey', '.my-element', Matreshka.binders.existence(false));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.html(mappingFn) binder

Путь к модулю CommonJS: 'matreshka/binders/html'

Возвращает байндер, меняющий innerHTML DOM элемента в зависимости от значения свойства объекта

Значение свойства можно преобразить с помощью переданной функции mappingFn.

Возвращает binder

Аргументы

Имя Тип Описание
mappingFn optional function

Отображающая функция

Примеры

this.bindNode('myKey', '.my-element', Matreshka.binders.html());
// установит innerHTML элемента как "<div>foo</div>"
this.myKey = '<div>foo</div>';

Использование отображающей функции

this.bindNode('myKey', '.my-element',
    Matreshka.binders.html(value => `Hello, ${value}`));
    
// установит innerHTML элемента как "Hello, <div>foo</div>"
this.myKey = '<div>foo</div>';
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.input(type) binder

Путь к модулю CommonJS: 'matreshka/binders/input'

Возвращает байндер, связывающий свойство объекта с элементом input. Напрямую байндер использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Аргументы

Имя Тип Описание
type optional string

Тип инпута

Примеры

this.bindNode('myKey', '.my-input', Matreshka.binders.input('range'));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.output() binder

Путь к модулю CommonJS: 'matreshka/binders/output'

Возвращает байндер, связывающий свойство объекта с элементом output. Напрямую байндер использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-output', Matreshka.binders.output());
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.progress() binder

Путь к модулю CommonJS: 'matreshka/binders/progress'

Возвращает байндер, связывающий свойство объекта с элементом progress. Напрямую байндер использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-progress', Matreshka.binders.progress());
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.prop(property, mappingFn) binder

Путь к модулю CommonJS: 'matreshka/binders/prop'

Возвращает байндер, меняющий свойство DOM элемента на значение свойства объекта

Значение свойства можно преобразить с помощью переданной функции mappingFn.

Возвращает binder

Аргументы

Имя Тип Описание
property string

Имя свойства

mappingFn optional function

Отображающая функция

Примеры

this.bindNode('disabled', '.my-button',
    Matreshka.binders.prop('disabled'));

// устанавливает свойство disabled = true для элемента
this.disabled = true;

// устанавливает свойство disabled = false для элемента
this.disabled = false;

Использование отображающей функции

this.bindNode('myProp', '.my-node'
    Matreshka.binders.prop('foo', value => `Hello, ${value}`));

this.myProp = 'World'; // свойство елемента foo имеет значение "Hello, World"
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.select(multiple) binder

Путь к модулю CommonJS: 'matreshka/binders/select'

Возвращает байндер, связывающий свойство объекта с элементом select. Напрямую байндер использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Аргументы

Имя Тип Описание
multiple optional boolean

Является ли селект multiple

Примеры

this.bindNode('myKey', '.my-select', Matreshka.binders.select(true));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.style(property, mappingFn) binder

Путь к модулю CommonJS: 'matreshka/binders/style'

Возвращает байндер, меняющий заданное свойство стиля DOM элемента в зависимости от значения свойства объекта.

Значение свойства можно преобразить с помощью переданной функции mappingFn.

Возвращает binder

Аргументы

Имя Тип Описание
property string

Свойство style (camel-cased)

mappingFn optional function

Отображающая функция

Примеры

this.bindNode('myKey', '.my-element',
    Matreshka.binders.style('backgroundColor'));
this.myKey = 'red'; // цвет фона .my-element стал красным

Использование отображающей функции

this.bindNode('myKey', '.my-element',
  Matreshka.binders.style('backgroundImage', value => `url("${value}")`));
  
this.myKey = 'cats.jpg'; // backgroundImage теперь равен "url("cats.jpg")"
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.text(mappingFn) binder

Путь к модулю CommonJS: 'matreshka/binders/text'

Возвращает байндер, меняющий textContent (текстовое содержимое) DOM элемента в зависимости от значения свойства объекта.

Matreshka.binders.text позволяет вывести содержимое свойства как есть. Значение свойства можно преобразить с помощью переданной функции mappingFn.

Возвращает binder

Аргументы

Имя Тип Описание
mappingFn optional function

Отображающая функция

Примеры

this.bindNode('myKey', '.my-element', Matreshka.binders.text());
this.myKey = 'foo'; // установит textContent элемента как "foo"

Использование отображающей функции

this.bindNode('myKey', '.my-element',
    Matreshka.binders.text(value => `Hello, ${value}`));
    
this.myKey = 'foo'; // установит textContent элемента как "Hello, foo"
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.binders.textarea() binder

Путь к модулю CommonJS: 'matreshka/binders/textarea'

Возвращает байндер, связывающий свойство объекта с элементом textarea. Напрямую байндер использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-textarea', Matreshka.binders.textarea());
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Класс Matreshka.Object

Путь к модулю CommonJS: 'matreshka/object'

Matreshka.Object - класс, который отвечает за данные вида ключ-значение. Его задачей является отделение служебных свойств от данных, которые можно передать на сервер или сохранить в локальном хранилище. Класс наследуется от класса Matreshka и включает все его свойства и методы.

Представьте себе, что вы создаёте класс, включающий свойства "a", "b" и "c". Допустим "a" и "b" - свойства которые должны быть отправлены на сервер, а свойство "c" лишь отвечает за некоторое состояние приложения (например, содержит сумму "a" и "b"). Свойство "c" не нужно серверу. Поэтому нам нужно отделить свойства отвечающие за данные от свойств, которые таковыми не являются.

Для того, чтоб отделить такие свойства от остальных, можно воспользоваться методом Matreshka.Object#addDataKeys.

this.addDataKeys(['a', 'b']);

this.a = 1;
this.b = 2;
this.c = 3;

Если вы заранее не знаете, какие свойства являются данными, можно всегда использовать метод Matreshka.Object#setData, который не только объявляет свойства, отвечающие за данные, но и сразу устанавливает значения.

this.setData({
    a: 1,
    b: 2
});

this.c = 3;

После того, как приложение получило информацию о том, что является данными, экземпляр Matreshka.Object можно сконвертировать в обычный объект методом Matreshka.Object#toJSON и передать на сервер или сохранить в локальной БД (например, в localStorage).

// вернет объект { a: 1, b: 2 }
this.toJSON();

События

При добавлении и изменении свойств, отвечающих за данные генерируется события set и modify, при удалении - remove и modify. Т. е. любые изменения данных можно слушать с помощью modify.

this.on('modify', () => {
    alert('Object is modified');
});

Аргументы

Имя Тип Описание
data optional object Данные, входящие в новый экземпляр

Примеры

Создание экземпляра с двумя свойствами-данными

// то же самое, что и new MK.Object().setData({ a: 1, b: 2 });
new MK.Object({ a: 1, b: 2 });

Наследование

class MyClass extends Matreshka.Object {
	constructor(data) {
		super(data).sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Наследование при помощи функции Matreshka.Class

const MyClass = Matreshka.Class({
	extends: Matreshka.Object,
	constructor(data) {
		this.setData(data).sayHello();
	},
	sayHello() {
		alert("Hello World!");
	}
});

Перебор данных, используя цикл for..of

const mkObject = new Matreshka.Object({ a: 1, b: 2 });
for(let item of mkObject) {
	console.log(item); // 1 .. 2
}
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#addDataKeys(keys) matreshkaObject

Добавляет заданные имена свойств в список имен свойств, отвечающих за данные

Этот метод применяется тогда, когда нужно объявить свойства, отвечающие за данные, но значения этих свойств еще не известны.

Возвращает matreshkaObject - self

Генерирует события set modify

Аргументы

Имя Тип Описание
keys string array

Массив имен свойств либо список аргументов с именами свойств

Примеры

this.addDataKeys(['a', 'b']);
this.addDataKeys('a', 'b');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#each(callback, thisArg) matreshkaObject

Перебирает свойства, отвечающие за данные

Метод очень похож на Array.prototype.forEach и является альтернативой циклу for..of.

Возвращает matreshkaObject - self

Аргументы

Имя Тип Описание
callback function

Функция, которая вызывается на каждой итерации

thisArg optional *

Контекст функции

Примеры

this
	.setData({ a: 1, b: 2 })
	.addDataKeys('c')
	.each((value, key) => {
		console.log(key, value);
	});
;
// >>> a 1, b 2, c undefined
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#keyOf(value) string null

Ищет заданное значение свойства среди свойств, отвечающих за данные, и возвращает имя первого совпавшего свойства, если такое значение найдено

Возвращает string null - имя свойства

Аргументы

Имя Тип Описание
value *

значение любого типа, которое следует найти среди данных

Примеры

const mkObject = new Matreshka.Object({
	a: 1,
	b: 2
});

mkObject.c = 3;

mkObject.keyOf(1); // 'a'

mkObject.keyOf(2); // 'b'

mkObject.keyOf(3); // null
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#removeDataKeys(keys) matreshkaObject

Удаляет заданные имена свойств из списка имен свойств, отвечающих за данные (но не удаляет само свойство)

Возвращает matreshkaObject - self

Генерирует события remove modify

Аргументы

Имя Тип Описание
keys string array

Массив имен свойств либо список аргументов с именами свойств

Примеры

this.removeDataKeys(['a', 'b']);
this.removeDataKeys('a', 'b');
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#setData(key, value, eventOptions) matreshkaObject

Синоним: Matreshka.Object#jset

Устанавливает значение свойству и добавляет его имя в список имен, отвечающих за данные

Этот метод делает две вещи:

  1. Устанавливает заданное значение заданному свойству.

  2. Добавляет ключ свойства в список данных, что делает свойство доступным для использования в методах Matreshka.Object#each, Matreshka.Object#keys, Matreshka.Object#toJSON).

Если передать флаг replaceData, установленный как true объект события, то остальные свойства будут удалены из списка свойств, отвечающих за данные.

В остальном, метод работает так же, как и Matreshka#set.

Возвращает matreshkaObject - self

Генерирует события change change:KEY modify set

Аргументы

Имя Тип Описание
key string

Ключ

value *

Значение

eventOptions optional eventOptions

Объект события

Ссылки

Примеры

this.setData('a', 1).setData('b', 2);

// присваиваем свойству 'c' тройку,
// но не добавляем ключ 'c' в список ключей, отвечающих за данные
this.set('c', 3);

this.each((value, key) => {
	console.log(key, value);
});

// выводит 'a' 1 и 'b' 2

console.log(this.keys()); // выводит ['a', 'b']

console.log(this.toJSON()); // выводит { a: 1, b: 2 }

После использования метода setData со свойством можно работать, как с обычным свойством

this.setData('a', 1).setData('b', 2);
this.set('a', 3);
this.b = 4;

Использование альтернативного имени метода: jset

this.jset('a', 1);
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#setData(keyValuePairs, evtOpts) matreshkaObject

Альтернативный синтаксис метода Matreshka.Object#setData, который принимает объект ключ-значение для установки нескольких свойств сразу

Возвращает matreshkaObject - self

Аргументы

Имя Тип Описание
keyValuePairs object

Объект ключ-значение

evtOpts eventOptions

Объект события

Примеры

this.setData({
	a: 1,
	b: 2
});

Если передать флаг replaceData, установленный как true в объект события, то свойства, которые не входят в переданный объект, будут удалены из списка свойств, отвечающих за данные

this
	.addDataKeys(['a', 'b', 'c'])
	.setData({
		a: 1,
		b: 2
	}, {
		replaceData: true
	});

console.log(this.keys()); // ['a', 'b']
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Object#toJSON(recursive=true) object

Конвертирует экземпляр Matreshka.Object в обычный объект

Метод работает рекурсивно, вызывая toJSON для всех свойств, у которых есть метод с таким именем. Для отмены рекурсии передайте false первым аргументом.

Возвращает object

Аргументы

Имя По умолчанию Тип
recursive optional true boolean

Примеры

const mkObject = new Matreshka.Object({
	a: 1,
	b: 2,
	c: new Matreshka.Object({
		d: 3,
		e: 4
	})
});

// возвращает {a: 1, b: 2, c: { d: 3, e: 4 }}
console.log(mkObject.toJSON());

// возвращает {a: 1, b: 2, c: MatreshkaObject}
console.log(mkObject.toJSON(false));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Класс Matreshka.Array

Путь к модулю CommonJS: 'matreshka/array'

Класс Matreshka.Array служит коллекцией во фреймворке Matreshka.js. Он наследуется от класса Matreshka и включает все его свойства и методы. Кроме этого, Matreshka.Array имеет все методы, которые есть у обычного массива, тем самым упрощая изучение его возможностей.

Все методы, позаимствованные у встроенного Array работают аналогично их оригиналам

Программист, знакомый с методами нативного Array сразу может понять, каким методом можно добавить элемент (push, unshift, splice), каким удалить (pop, shift, splice), каким отсортировать (sort, reverse) и т. д.

По причине того, что методы работают так же, как и оригинальные (с небольшими исключениями), они не приведены в этой документации по отдельности, а выведены в раздел Matreshka.Array#METHOD.

this.push(1, 2, 3);
this.pop();

Все методы, позаимствованные у встроенного Array, которые модифицируют массив могут быть вызваны с передачей объекта события

Для этого используется синтаксис метод_, где нижнее подчеркивание в конце имени метода означает, что последним аргументом является объект события. Такие методы не приведены в этой документации, так как требуется запомнить только их синтаксис. См. Matreshka.Array#METHOD_.

this.push_(1, 2, 3, {
    silent: true
});

this.pop_({
    foo: 'bar'
});

Разработчик имеет возможность отлавливать любые модификации данных

При использовании методов, позаимствованных у встроенного Array генерируются события с соответствующим именем. Вызывая метод push, генерируется событие push, вызывая метод shift генерируется событие shift, вызывая метод sort, генерируется событие sort и так далее.

this.on('push', evt => {
    console.log('push is called');
});

this.push(1, 2, 3);

При добавлении элементов генерируются события add и addone. Первое генерируется один раз на добавление (например, вы добавили несколько элементов с помощью push, событие вызвалось только один раз), второе генерируется один раз на каждый добавленный элемент.

При срабатывании события add, значением свойства added объекта события передается массив добавленных элементов, а при срабатывании addone, значением свойства addedItem - каждый отдельный добавленный элемент.

this.on('add', evt => {
    console.log(evt.added); // [1,2,3]
});

this.push(1, 2, 3);
// обработчик запустится трижды,
// так как в массив добавили три новых элемента
this.on('addone', evt {
    console.log(evt.addedItem); // 1 ... 2 ... 3
});

this.push(1, 2, 3);

При удалении элементов действует та же логика: remove срабатывает один раз, даже если удалено несколько элементов, а событие removeone срабатывает для каждого удаленного элемента индивидуально. При генерации события remove удаленные элементы содержатся в свойстве removed объекта события, а при генерации события removeone - каждый удаленный элемент содержится в свойстве removedItem.

this.push(1, 2, 3, 4, 5);

this.on('remove', evt => {
    console.log(evt.removed); // [2, 3, 4]
});

this.splice(1, 3);
this.push(1, 2, 3, 4, 5);

// обработчик запустится трижды,
// так как из массива удалили три элемента
this.on('removeone', evt => {
    console.log(evt.removedItem); // 2 ... 3 ... 4
});

this.splice(1, 3);

При каждой модификации массива генерируется событие modify, позволяя отловить все без исключения изменения в массиве (добавление, удаление, пересортировку).

this.on('modify', evt => {
    console.log(evt.added);
    console.log(evt.removed);
});

length - это обычное свойство которое можно связывать с HTML элементом или отлавливать изменения с помощью события change:length.

Например, при добавлении трех элементов с помощью метода push с тремя аргументами, генерируются следующие события: push, add, addone (трижды), modify, change:length.

Model

Свойство Matreshka.Array#Model определяет класс элементов, которые будет содержать коллекция. Рекомендуется наследовать Model от класса Matreshka.Object или Matreshka.Array (на случай, если требуется получить коллекцию коллекций), чтобы получить возможность конвертации массива в обычный массив рекурсивно методом Matreshka.Array#toJSON.

Автоматический рендеринг

Matreshka.Array умеет автоматически отрисовывать элементы на странице при любых модификациях массива. За подробностями обратитесь к документации Matreshka.Array#itemRenderer.

Ссылки

Примеры

Создание экземпляра с нулевой длиной

new Matreshka.Array();

Создание экземпляра с указанием длины

new Matreshka.Array(42);

Передача элементов при создании

new Matreshka.Array('Hi', { a: 'b' });

Наследование

class MyClass extends Matreshka.Array {
	constructor(items) {
		super(...items).sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Наследование, используя функцию Matreshka.Class

const MyClass = Matreshka.Class({
	extends: Matreshka.Array,
	constructor(items) {
		this.recreate(items).sayHello();
	},
	sayHello() {
		alert("Hello World!");
	}
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#METHOD()

Любой метод из Array.prototype

Matreshka.Array включает в себя все методы, входящие в нативный JavaScript массив:

При этом, они работают точно так же, как и методы Array.prototype. Есть лишь несколько оговорок:

  • Метод forEach возвращает себя вместо undefined
  • Методы, которые в оригинальном виде возвращают новый массив (splice, slice, filter, map...), возвращают новый экземпляр Matreshka.Array.
  • Методы keys, values и entries возвращают массив вместо итератора.

Кроме всего, методы генерируют события связанные с любой модификацией массива. Подробнее см. Matreshka.Array.

Ссылки

Примеры

this.push(1, 2, 3);
const mkArray = this
	.forEach((value, index) => {
		//...
	})
	.map((value, index) => {
		//...
	});

console.log(mkArray.isMatreshkaArray); // true
this.reverse();
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#METHOD_()

Любой метод из Array.prototype с возможностью передать объект события

Ознакомившись с Matreshka.Array#METHOD становится понятно, что методы не поддерживают передачу объекта события, так как в точности повторяют синтаксис и количество аргументов встроенного Array. Синтаксис МЕТОД_ позволяет передать в обработчик события какие-нибудь данные либо установить служебные флаги, отвечающие за поведение массива после вызова метода.

Список доступных флагов:

Ссылки

Примеры

this.push_(1, 2, 3, {
    silent: true
});

this.pop_({
    silent: true
});
this.on('modify', evt => {
	alert(evt.flag); // 42
});

this.push_(1, 2, 3, {
	flag: 42
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

<virtual>Matreshka.Array#Model(data, mkArray, index)

Свойство определяет класс элементов, которые будет содержать коллекция

При каждом добавлении элементов в массив, встроенный обработчик проверяет, является ли добавленный элемент экземпляром Model и конвертирует его в таковой, если проверка не пройдена. Рекомендуется наследовать Model от класса Matreshka.Object или Matreshka.Array (на случай, если требуется получить коллекцию коллекций), чтоб получить возможность конвертации массива в обычный массив методом Matreshka.Array#toJSON.

Для более гибкого контроля класса элементов (например, если для одних элементов нужно использовать одну Модель, а для других - другую), используйте Matreshka.Array#mediateItem.

Аргументы

Имя Тип Описание
data object

Данные, переданные в конструктор

mkArray matreshkaArray

Массив, в который добавили элемент

index number

Текущий индекс объекта в родительском массиве

Ссылки

Примеры

// определяем Модель
class MyModel extends Matreshka.Object {
	constructor(data, parentArray, index) {
		super(data);
		this.doSomething();
	}
	doSomething() { ... }
}

// определяем класс для коллекции
class MyArray extends Matreshka.Array {
	get Model() {
		return MyModel;
	}
}

// создаем экземпляр класса
const myArray = new MyArray();

// добавляем два элемента
myArray.push({
    a: 1,
    b: 2
}, {
    a: 3,
    b: 4
});

console.log(myArray[0] instanceof MyModel); // true
console.log(myArray[1] instanceof MyModel); // true

// вернет [{ a: 1, b: 2 }, { a: 3, b: 4 }]
myArray.toJSON();
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#mediateItem(mediator)

Трансформирует значение элементов массива

Этот метод служит для того, чтоб перехватить и трансформировать добавленные в массив элементы. Обратите внимание, метод переопределяет свойство Matreshka.Array#Model.

Аргументы

Имя Тип Описание
mediator function

Функция, возвращающая трансформированный элемент массива

Ссылки

Примеры

// все элементы массива - целые числа
this.mediateItem(item => parseInt(item) || 0);
this.push(1, 2, 3, 4, 5);

// все элементы массива - строки
this.mediateItem(String);

this.push(6, 7);

this.unshift(true, {});

// ["true", "[object Object]", "1", "2", "3", "4", "5", "6", "7"]
console.log(mkArray.toJSON());
this.mediateItem(item => {
	if(item.something) {
		return new FirstModel(item);
	} else {
		return new SecondModel(item);
	}
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

<virtual>Matreshka.Array#onItemRender(item, renderEvent)

Функция, которая запускается перед событием render.

Виртуальный метод onItemRender можно использовать в качестве замены события render.

При этом, у отрисованного элемента вызывается виртуальный метод onRender с единственным аргументом - объектом события.

Аргументы

Имя Тип Описание
item object

Отрисованный элемент коллекции

renderEvent object

Объект события render

Примеры

class MyModel extends Matreshka.Object {
	constructor(data) {
		super(data);
	}
	onRender(renderEvt) {
		this.bindNode('isChecked', ':sandbox .my-checkbox');
		this.bindNode('text', ':sandbox .text', Matreshka.binders.html());
	}
});

class MyArray extends Matreshka.Array {
	get Model() {
		return MyModel;
	}
	itemRenderer() {
		return '<li>'
	}
	constructor() {
		this.bindNode('sandbox', '.my-form');
	}
	onItemRender(item, renderEvt) {
		// ...
	}
});

const app = new MyArray();
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#orderBy(keys, orders=asc) matreshkaArray

Сортирует массив по значениям свойств объектов, которые в него входят

Этот метод работает почти так же, как и метод orderBy из lodash. Он принимает ключ или массив ключей - первым аргументом, порядок (asc/desc) или массив порядков - вторым.

Возвращает matreshkaArray - self

Генерирует события sort

Аргументы

Имя По умолчанию Тип Описание
keys string array

Ключ свойства или массив нескольких ключей, по которым коллекция будет отсортирована

orders optional asc string array

Порядок или массив порядков, соответствующих массиву ключей

Примеры

this.recreate([
    { 'user': 'fred',   'age': 48 },
    { 'user': 'barney', 'age': 34 },
    { 'user': 'fred',   'age': 42 },
    { 'user': 'barney', 'age': 36 }
]);

// сортирует по значениям свойств 'user' по возрастанию и значениям свойств 'age' по убыванию
this.orderBy(['user', 'age'], ['asc', 'desc']);
// → [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":42}]
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#pull(indexOrValue, eventOptions) * null

Удаляет элемент по индексу или по значению

Возвращает * null - Удаленный элемент или null

Генерирует события pull remove removeone modify

Аргументы

Имя Тип Описание
indexOrValue object number

Индекс элемента, который нужно удалить (число) либо удаляемый элемент (объект)

eventOptions optional eventOptions

Объект события на случай, если нужно передать в обработчик события какие-нибудь данные или установить служебные флаги (например, silent)

Примеры

Передача индекса массива

let removed;

this.recreate(['a', 'b', 'c']);

removed = this.pull(1);

console.log(removed); // 'b'

console.log(this.join(',')); // 'a,c'

Передача удаляемого элемента

const object1 = {};
const object2 = {};
const object3 = {};
let removed;

this.push(object1, object2, object3);

removed = this.pull(object2);

console.log(removed === object2); // true

console.log(this.length); // 2
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#recreate(array, eventOptions) matreshkaArray

Пересоздает экземпляр Matreshka.Array

Метод позволяет конвертировать любой массив (или объект, подобный массиву) в экземпляр Matreshka.Array. Если ничего не передано в качестве первого аргумента, экземпляр очищается.

Возвращает matreshkaArray - self

Генерирует события recreate modify add addone remove removeone

Аргументы

Имя Тип Описание
array optional array

Массив или массивоподобный объект

eventOptions optional eventOptions

Объект события

Ссылки

Примеры

// очищаем массив и добавляем 5 новых элементов
this.recreate([1, 2, 3, 4, 5]);

// очищаем массив
this.recreate();
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#rerender(eventOptions) matreshkaArray

Перерисовывает DOM узлы элементов, входящих в массив

Этот метод заново рендерит элементы массива в контейнере массива. Если узел, который ассоциирован с элеменом масива уже создан, метод, вместо перерисовки с нуля, "перевставляет" его в контейнер или песочницу массива.

Метод может быть полезным на случай, когда элементы добавлены в массив перед объявлением песочницы или контейнера.

Чтоб заставить массив перерисоваться, независимо от наличия отрендеренных узлов (например, вы используете кастомный шаблонизатор в itemRenderer), передайте в метод объект со свойством forceRerender равным true.

Возвращает matreshkaArray - self

Аргументы

Имя Тип Описание
eventOptions optional eventOptions

Объект события

Примеры

this.rerender({
	forceRerender: true
});
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#restore(selector, eventOptions) matreshkaArray

Воссоздаёт Matreshka.Array из HTML узлов на странице.

В случае, если коллекция заранее отрисована на странице (например, с помощью сервера), метод может воссоздать коллекцию из отрендеренных HTML узлов.

<!-- One, Two, Three заранее отрисованы -->
<ul class="collection-node">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <script type="text/html" class="renderer">
        <li></li>
    </script>
</ul>
class MyModel extends Matreshka.Object {
    constructor(data) {
        super(data);
        this.addDataKeys('value');
    }
    onRender() {
        this.bindNode('value', ':sandbox', Matreshka.binders.html())
    }
});

class MyCollection extends Matreshka.Array {
    get itemRenderer() {
        return ':sandbox .renderer';
    }
    constructor() {
        this
            .bindNode('sandbox', '.collection-node')
            .restore(':sandbox li');
    }
});

const myCollection = new MyCollection();
myCollection.push({
    value: 'Four'
});

console.log(myCollection.toJSON());
// [{value: 'One'}, {value: 'Two'}, {value: 'Three'}, {value: 'Four'}]

Если аргумент selector не задан, то коллекция будет воссоздана из элементов, входящих в контейнер ("container" или "sandbox").

При воссоздании, на каждом элементе массива генерируется событие render и вызываются методы onRender и onItemRender (см документацию), как и при обычном рендеринге.

Возвращает matreshkaArray - self

Генерирует события recreate modify add addone

Аргументы

Имя Тип Описание
selector optional selector

Селектор

eventOptions optional eventOptions

Объект события

Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array#toJSON(recursive=true) array

Конвертирует экземпляр Matreshka.Array в обычный массив

Метод работает рекурсивно, вызывая toJSON для входящих объектов, у которых есть метод с таким именем. Для отмены рекурсии передайте false первым аргументом.

Возвращает array

Аргументы

Имя По умолчанию Тип
recursive optional true boolean

Примеры

const mkArray = new Matreshka.Array([1, 2, new MatreshkaArray(3, 4)]);

// возвращает [1, 2, [3, 4]]
console.log(mkArray.toJSON());

// возвращает [1, 2, MatreshkaArray]
console.log(mkArray.toJSON(false));
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

<virtual>Matreshka.Array#itemRenderer: string function

HTML строка, селектор или функция, отвечающая за отрисовку элементов массива на странице

Свойство itemRenderer - это переопределяемое (виртуальное) свойство, которое позволяет рендерить элементы массива без дополнительного кода. При вставке нового элемента в массив, автоматически создается HTML узел. Этот узел становится песочницей (см. Matreshka#bindNode) (это поведение можно отменить, см. ниже) для вставленного элемента и встраивается в HTML контейнер, определенный в массиве.

Для краткости, в примерах к этой статье будет использоваться синтаксис class fields.

Куда вставляется созданный элемент?

Для того, чтобы определить место, в которое будут вставляться отрисованные HTML узлы, нужно определить контейнер. Для этого следует объявить HTML песочницу для массива либо связать специальный ключ container с HTML контейнером. Подробнее о привязках и песочнице см. Matreshka#bindNode. Пример использования песочницы в качестве контейнера:

<ul class="my-list"></ul>
class MyArray extends Matreshka.Array {
    itemRenderer = '<li>';
    Model = MyModel;
    constructor() {
        super();
        // определяем песочницу
        this.bindNode('sandbox', '.my-list');
    }
});

Теперь все новосозданные узлы <li> попадут в узел .my-list

Если вы не хотите вставлять HTML узлы непосредственно в песочницу, можете связать ключ container с необходимым элементом. Такая логика нужна в том случае, если песочница не ограничена одними лишь элементами коллекции и включает в себя другие HTML узлы.

<div class="my-widget">
    <h1>This is my awesome list</h1>
    <ul class="my-list"></ul>
</div>
class MyArray extends Matreshka.Array {
    itemRenderer = '<li>';
    Model = MyModel;
    constructor() {
        super();
        // определяем песочницу
        this.bindNode('sandbox', '.my-widget');
        // определяем контейнер для HTML элементов
        this.bindNode('container', '.my-list');
    }
}

В примере выше HTML узлы будут вставляться в .my-list вместо .my-widget.

Свойство itemRenderer поддерживает несколько вариантов определения, но все они должны содержать или возвращать единственный HTML узел.

HTML строка в качестве значения свойства

Как видно из примера выше, itemRenderer может быть определен, как HTML строка.

class MyArray extends Matreshka.Array {
    Model = MyModel;
    itemRenderer = '<div class="my-div">foo</div>';
    constructor() { ... }
}

Селектор в качестве значения свойства

На случай, если вы выносите шаблоны для элементов на HTML страницу, itemRenderer поддерживает селектор в качестве значения. В этом случае, Matreshka.Array будет искать HTML элемент в DOM дереве и извлечет innerHTML найденого элемента. В случае, если элемент не найден, бросается исключение.

HTML текст от селектора отличается наличием символа < в строке.

<script type="text/html" id="my-template">
    <div class="my-div">foo</div>
</script>
class MyArray extends Matreshka.Array {
    Model = MyModel;
    itemRenderer = '#my-template';
    constructor() { ... }
}

Функция в качестве значения свойства

Использование функции в качестве значения свойства itemRenderer может пригодиться, когда есть нужда динамически генерировать элемент для рендеринга. Функция может возвращать:

HTML строку

class MyArray extends Matreshka.Array {
    itemRenderer() {
        return '<div class="my-div">foo</div>';
    }
}

Селектор

class MyArray extends Matreshka.Array {
    itemRenderer: function() {
        return '#my-template';
    }
}

DOM узел

class MyArray extends Matreshka.Array {
    itemRenderer() {
        return document.createElement('div');
    }
}

Перекрытие родительского рендерера свойством render

Иногда удобно объявлять рендерер внутри класса Matreshka.Array#Model, а не на уровне коллекции. Свойство renderer перекрывает значение itemRenderer, если оно задано для элемента коллекции.

class MyModel extends Matreshka.Object {
    renderer = '<div class="my-div">foo</div>';
}

class MyArray extends Matreshka.Array {
    Model = MyModel,
    itemRenderer = '<frameset>bar</frameset>';
    constructor() { ... }
}

В этом случае, можно вовсе не указывать itemRenderer, так как render дочернего элемента перенимает все его возможности. Синтаксис остаётся такими же: можно использовать HTML, селектор или функцию.

Событие render и afterrender

После того, как объект вставлен в массив, а его HTML узел уже создан, но еще не вставлен в контейнер, генерируется событие render на вставленном элементе. После его генерации можно объявить привязки свойств к HTML узлам, содержащимся внутри этого элемента.

afterrender, в свою очередь, генерируется после вставки HTML элемента в контейнер массива.

<form class="my-form"></form>
class MyModel extends Matreshka.Object {
    constructor(data) {
        super(data);

        // ждем генерации события
        this.on('render', () => {
            // объявляем байндинги
            this.bindNode('isChecked', ':sandbox .my-checkbox');
            this.bindNode('text', ':sandbox .text',
                Matreshka.binders.html());
        });
    }
});

class MyArray extends Matreshka.Array {
    Model = MyModel;
    itemRenderer = `<label>
        <input type="checkbox" class="my-checkbox">
        <span class="text"></span>
    </label>`;
    constructor() {
        super();
        this.bindNode('sandbox', '.my-form');
        this.push({
            isChecked: true,
            text: 'Buy a raccoon'
        }, {
            isChecked: false,
            text: 'Sell the raccoon'
        });
    }
});

const app = new MyArray();

Код выше создаст такое HTML дерево:

<form class="my-form">
    <label>
        <input type="checkbox" class="my-checkbox">
        <span class="text">Buy a raccoon</span>
    </label>
    <label>
        <input type="checkbox" class="my-checkbox">
        <span class="text">Sell the raccoon</span>
    </label>
</form>

И свяжет чекбоксы с соответствующими свойствaми isChecked и text.

Не забывайте, что в Matreshka.js реализована возможность отлова делегированных событий. Т. е. сам массив может отловить событие рендеринга элемента, используя имя события *@render (см. документацию к eventNames).

this.on('*@render', () => {
    alert('Child element is rendered');
});

Отрисованный HTML узел становится песочницей для вставленного элемента, позволяя использовать селектор :sandbox и другие возможности после рендеринга. Если элемент входит сразу в несколько коллекций, установите ему свойство bindRenderedAsSandbox: false, чтобы отменить это поведение.

class MyModel extends Matreshka.Object {
    bindRenderedAsSandbox = false;
    // ...
});

onItemRender и onRender

Для улучшения читаемости кода в одной из предыдущих версий появился виртуальный метод Matreshka.Array#onItemRender, который можно использовать вместо события render. В качестве альтернативы, у "моделей" вызывается метод onRender, так же позволяющий сделать код более "плоским" и избавиться от вложенных функций.

class MyModel extends Matreshka.Object {
    constructor(data) {
        super(data);
    }
    onRender(evt) {
        this.bindNode('isChecked', ':sandbox .my-checkbox');
        this.bindNode('text', ':sandbox .text',
                Matreshka.binders.html());
    }
}

class MyArray extends Matreshka.Array {
    Model = MyModel;
    itemRenderer = '...';
    constructor() {
        //...
    },
    onItemRender(item, evt) {
        //...
    }
}

const app = new MyArray();

Шаблонизатор

Взглянув на примеры использования Matreshka.Array и Matreshka.Array#itemRenderer можно обратить внимание на то, что вся логика, отвечающая за двустороннюю и одностороннюю привязку данных заключена в JavaScript коде. Но когда разрабатываешь очень простую коллекцию, не включающую в себя сложную логику, массу привязок и пр. хотелось бы иметь более краткий вариант объявления привязок. Для этого, в itemRenderer может быть передан шаблон, включающий привязки, заключенные в фигурные скобки (см. Matreshka#parseBindings).

class MyArray extends Matreshka.Array {
    itemRenderer: `<label>
        <input type="checkbox" checked="{{isChecked}}">{{text}}
    </label>`
    // ...
}

const app = new MyArray();

Отмена рендеринга

Как видно выше, если у дочернего элемента задано свойство render, Matreshka.Array попробует его отрисовать. Для того, чтоб полностью отменить рендеринг для массива, присвойте свойству массива renderIfPossible значение false.

class MyArray extends Matreshka.Array {
    renderIfPossible = false;
    // ...
}

Перемещение объекта из одного массива в другой

По умолчанию, при вставке объекта в массив фреймворк попытается его отрисовать, используя itemRenderer. Это даёт преимущество в случаях, когда у вас на странице есть два или более списка, включающих в себя один и тот же объект. При изменении этого объекта, все списки моментально реагируют на изменение, обновляя DOM.

Но иногда стоит задача перемещения объекта между коллекциями, не перерисовывая его заново. Для перемещения объекта из одного массива в другой, включая его песочницу, используйте флаг moveSandbox.

this.push_(item, {
    moveSandbox: true
});

Переопределение itemRenderer

При переустановке свойства itemRenderer, коллекция автоматически перерисовывается.

this.itemRenderer = '<div>';

Эта возможность полезна в том случае, когда разработчик желает загрузить шаблон с сервера.

fetch('templates/template.html')
    .then(resp => resp.text())
    .then(data => {
        this.itemRenderer = data;
    });

Для отрисовки только тех объектов, которые еще не были отрисованы, воспользуйтесь методом Matreshka#set с флагом forceRerender со значением false

this.set('itemRenderer', renderer, {
    forceRerender: false
});

Такая необходимость может возникнуть тогда, когда вы используете серверный пререндеринг (см. Matreshka.Array#restore), а шаблон подгружается динамически.

class MyArray extends Matreshka.Array {
    constructor() {
        super()
            .bindNode('sandbox', '.some-node')
            .restore();

        fetch('templates/template.html')
            .then(resp => resp.text())
            .then(data => {
                this.set('itemRenderer', data, {
                    forceRerender: false
                });
            });
    }
}

Рендеринг коллекции, состоящей из обычных объектов

Объект, входящий в коллекцию, не обязательно должен быть экземпляром Matreshka, можно рендерить любой объект. Байндинги для таких объектов можно объявить используя статичный метод Matreshka.bindNode.

class MyArray extends Matreshka.Array {
    // Model не определена
    itemRenderer: ...
    onItemRender(item) {
        Matreshka.bindNode(item, 'x', ':sandbox .some-node');
    }
})

Еще небольшой пример: рендеринг простого списка.

class MyArray extends Matreshka.Array {
    itemRenderer = '<li>{{value}}</li>';
    constructor() {
        super().bindNode('sandbox', '.my-list');
    }
});

const arr = new MyArray();
arr.push({ value: 'Item 1' }, { value: 'Item 2' });

Ссылки

Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

<virtual>Matreshka.Array#trackBy: string

Свойство trackBy указывает на имя свойства идентификатора объектов, входящих в массив

В случае, если клиент и сервер активно обмениваются данными (например, списком пользователей), а объекты, входящие в массив имеют уникальный ID (например, идентификатор пользователя), то перерисовка всей коллекции с нуля не имеет смысла. После того, как сервер вернул новую коллекцию, намного рациональнее проверить, есть ли в коллекции объект с таким же ID и, если объект найден, обновить его. Таким образом, не создаётся новый объект (экземпляр Matreshka.Array#Model) и не рисуется новый DOM узел.

trackBy работает только при использовании метода Matreshka.Array#recreate, так как это единственный метод "пересоздающий" коллекцию заново.

В примере ниже используется _id в качестве значения (значение может быть любым).

class MyArray extends Matreshka.Array {
    get trackBy() {
        return '_id';
    }
    constructor() {
        //...
    }
});

const arr = new MyArray();

// добавит три объекта в массив
arr.recreate([
    {_id: 0, name: 'Foo'},
    {_id: 1, name: 'Bar'},
    {_id: 2, name: 'Baz'}
]);

// удалит объект с идентификатором 0
// добавит объект с идентификатором 3
// обновит объект с идентификатором 1, обновив name: Bar -> BarNew
// обновит объект с идентификатором 2, обновив name: Baz -> BazNew
// пересортирует коллекцию в соответствие с переданным данным
arr.recreate([
    {_id: 1, name: 'BarNew'},
    {_id: 3, name: 'Qux'},
    {_id: 2, name: 'BazNew'}
]);

Свойство может содержать специальное значение "$index", которое позволяет обновлять объект по индексу в коллекции.

class MyArray extends Matreshka.Array {
    get trackBy() {
        return '$index';
    }
    constructor() {
        //...
    }
});

const arr = new MyArray();

// добавит три объекта в массив
arr.recreate([
    {name: 'Foo'},
    {name: 'Bar'},
    {name: 'Baz'}
]);

// обновит все три объекта новыми данными
// и добавит новый объект с именем Qux
arr.recreate([
    {name: 'NewFoo'},
    {name: 'NewBar'},
    {name: 'NewBaz'},
    {name: 'Qux'}
]);

Ссылки

Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array.from(arrayLike, mapFn, thisArg) matreshkaArray

Метод создаёт новый экземпляр Matreshka.Array из массивоподобного или итерируемого объекта

Возвращает matreshkaArray

Аргументы

Имя Тип Описание
arrayLike object

Массивоподобный или итерируемый объект

mapFn optional function

Отображающая функция, вызываемая для каждого элемента массива

thisArg optional *

Объект, который используется в качестве this при вызове mapFn

Ссылки

Примеры

const mkArray = Matreshka.Array.from([1, 2, 3, 4]);
const mkArray = Matreshka.Array.from([1, 2, 3, 4], item => item * 2);

Наследование метода

class MyClass extends Matreshka.Array {
    // ...
}

const myArray = MyClass.from([1, 2, 3, 4]);
console.log(myArray instanceof MyClass); // true
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

Matreshka.Array.of() matreshkaArray

Метод создаёт новый экземпляр Matreshka.Array из произвольного числа агрументов, вне зависимости от числа или типа аргумента

Возвращает matreshkaArray

Ссылки

Примеры

const mkArray = Matreshka.Array.of(1, 2, 3, 4);

Наследование метода

class MyClass extends Matreshka.Array {
    // ...
}

const myArray = MyClass.of(1, 2, 3, 4);
console.log(myArray instanceof MyClass); // true
Нашли ошибку в статье? Пришлите патч с исправлением. Задать вопрос

eventHandler: function

Функция-обработчик события. Принимает любые аргументы, переданные в Matreshka#trigger

Аргументы

Имя Тип Описание
options * любые аргументы, переданные в вызов Matreshka#trigger после имени события

Примеры

const eventHandler = (...args) => {
	console.log(args);
};
this.on('fyeah', eventHandler);
// logs 'foo', 'bar', 'baz'
this.trigger('fyeah', 'foo', 'bar', 'baz');

matreshka: object

Экземпляр класса Matreshka

Примеры

const mk = new Matreshka();
obj.calc('a', 'b');

matreshkaObject: object

Экземпляр класса Matreshka.Object

Примеры

const obj = new Matreshka.Object({ foo: 'x' });
obj.setData({ bar: 'y' });

matreshkaArray: object

Экземпляр класса Matreshka.Array

Примеры

const arr = new Matreshka.Array(1, 2, 3);
arr.push(4);

eventNames: string

Имя события или несколько имен, разделенных пробелами.

Здесь представлен краткий список событий с небольшими примерами. Для получения полной информации, прочтите эту статью на Хабре.

Произвольные события
this.on('myevent', () => {...});
this.trigger('myevent');
change:KEY, вызывающееся, когда свойство меняется
this.on('change:x', evt => {...});
this.x = 42;
beforechange:KEY, вызывающееся перед изменением свойства
this.on('beforechange:x', evt => {...});
this.x = 42;
addevent:NAME и addevent, вызывающееся при инициализации события
// для всех событий
this.on('addevent', evt => {...});
// для события "someevent"
this.on('addevent:someevent', evt => {...});
// генерирует события "addevent" и "addevent:someevent"
this.on('someevent', evt => {...});
removeevent:NAME и removeevent, вызывающееся при удалении обработчика события
// для всех событий
this.on('removeevent', evt => {...});
// для события "someevent"
this.on('removeevent:someevent', evt => {...});
// генерирует события "removeevent" и "removeevent:someevent"
this.off('someevent', evt => {...});
DOM_EVENT::KEY, где DOM_EVENT - имя DOM события, KEY - ключ. Генерируется тогда, когда событие DOM_EVENT срабатывает на элементе, который связан с KEY.
this.bindNode('x', '.my-div');
this.on('click::x', evt => {
    alert('clicked ".my-div"');
});
DOM_EVENT::KEY(SELECTOR), где DOM_EVENT - имя DOM события, KEY - ключ, SELECTOR - селектор. Генерируется тогда, когда событие DOM_EVENT срабатывает на элементе, который соответствует селектору SELECTOR, и находится в элементе, который связан со свойством KEY.
<div class="my-div">
    <button class="my-button"></button>
</div>
this.bindNode('x', '.my-div');
this.on('click::x(.my-button)', evt => {
    alert('clicked ".my-button"');
});
DOM_EVENT::(SELECTOR), где DOM_EVENT - имя DOM события, SELECTOR - селектор. Генерируется тогда, когда событие DOM_EVENT срабатывает на элементе, который соответствует селектору SELECTOR, и находится в песочнице текущего объекта.
this.bindNode('sandbox', '.my-div');
this.on('click::(.my-button)', evt => {
    alert('clicked ".my-button"');
});

То же самое, что и:

this.bindNode('sandbox', '.my-div');
this.on('click::sandbox(.my-button)', evt => {
    alert('clicked ".my-button"');
});
Делегированные события PATH@EVENT, где PATH - путь к объекту, события которого мы желаем прослушивать, EVENT - имя события.
this.on('a@someevent', () => {...});
this.on('a.b.c@change:d', () => {...});

При возникновении необходимости слушать изменения во всех элементах Matreshka.Array или во всех свойствах, отвечающих за данные Matreshka.Object, вместо имени свойства можно указать звездочку "*".

this.on('*@someevent', () => {...});
this.on('*.b.*.d@change:e', () => {...});

Всевозможные комбинации

Все приведенные выше варианты синтаксиса можно комбинировать произвольным способом.

this.on('x.y.z@click::(.my-selector)', () => {...});

binder: object

binder (байндер, привязчик) содержит всю информацию о том, как синхронизировать значение свойства с привязанным к нему DOM элементом. Для всех методов байндера контекст (this) - соответствующий DOM узел.

Свойства

Имя Тип Описание
on optional string function

Имя DOM события (или список имен событий, разделенных пробелами), после срабатывания которого извлекается состояние DOM элемента и устанавливается свойство. Кроме этого, значением свойства может быть функция, которая устанавливает обработчик произвольным образом.

getValue optional function

Функция, которая отвечает за то, как извлечь состояние DOM элемента

setValue optional function

Функция, которая отвечает за то, как установить значение свойства DOM элементу

initialize optional function

Функция, которая запускается при инициализации привязки. Например, может быть использована для инициализации jQuery плагина.

destroy optional function

Функция, которая вызывается после вызова метода unbindNode. Если байндер достаточно сложен, destroy может содержать удаление логики, навешаной байндером

Примеры

const binder = {
	on: 'click',
	getValue(bindingOptions) {
		return this.value;
	},
	setValue(v, bindingOptions) {
		this.value = v;
	},
	initialize(bindingOptions) {
		alert('A binding is initialized');
	},
	destroy(bindingOptions) {
		alert('A binding is destroyed');
	}
};

this.bindNode('a', '.my-checkbox', binder);
const binder = {
	on(callback, bindingOptions) {
		this.onclick = callback;
	}
	// ...
};
// ...

eventOptions: object

Это обычный объект, который может содержать служебные флаги или произвольные данные, которые попадут в обработчик события

Примеры

const eventOptions = { silent: true };

this.a = 1;

this.on('change:a', () => {
	alert('a is changed');
});

this.set('a', 2, eventOptions); // no alert
const eventOptions = { f: 'yeah' };

this.a = 1;

this.on('change:a', eventOptions => {
	alert(eventOptions.f);
});

this.set('a', 2, eventOptions); // alerts "yeah"

class: function

Класс созданный при помощи синтаксиса ECMAScript 2015 либо возвращаемый функцией Matreshka.Class

Примеры

class MyClass {
	method() { ... }
};
const MyClass = Matreshka.Class({
	method() { ... }
});

node

DOM узел

Примеры

const node = document.querySelector('.foo');

$nodes

Коллекция DOM узлов. Например, jQuery или NodeList.

Примеры

let $nodes = $('.foo');
$nodes = document.querySelectorAll('.bar');

string

Строка

Примеры

const foo = 'bar';

boolean

Логический тип

Примеры

const bool = true;

number

Число

Примеры

const num = 42;

object

Объект

Примеры

const obj = {
	foo: 'x',
	['bar']: 'y'
};

array

Массив

Примеры

const arr = ['foo', undefined, null, () => {}];

function

Функция

Примеры

function comeOnBarbieLetsGoParty() {
	alert("I'm a Barbie girl, in a Barbie world");
}

null

null

Примеры

const x = null;

*

Любой тип

Примеры

let whatever = 'foo';
whatever = 42;

FAQ

Как работает Matreshka.js?

Matreshka.js использует акцессоры (accessors) для реализации двустороннего связывания данных и отлова событий изменения свойств.

В качестве примера того, как работает двустороннее связывание (в частности, функция Matreshka.bindNode), взгляните на этот код:

function bindNode(object, key, node, binder) {
    const value = object[key];
    Object.defineProperty(object, key, {
        get() {
            return value;
        },
        set(v) {
            binder.setValue.call(node, v);
        }
    });

    node.addEventListener(binder.on, () => {
        value = binder.getValue.call(node);
    });
};

Для упрощения, функция не поддерживает связь многие-ко-многим и другие фичи оригинала.

Есть ли во фреймворке роутинг?

Да, matreshka-router реализует двустороннее связывание свойства и части URL в стиле Matreshka.js. Подробное описание на русском можно прочесть в статье на Хабре.

Как предварительно отрендерить приложение на сервере?

Можно использовать Matreshka.js на сервере Node.js (требуется наличие jsdom, точнее, объекта window, доступного глобально) либо воспользоваться совершенно любым шаблонизатором на любой серверной платформе. Первый вариант подходит для статичной генерации HTML, второй - для страниц, которые генерируются при каждом обращении пользователя.

Задача клиентской стороны - восстановить приложение из HTML. Matreshka#bindNode извлечет состояние элемента и присвоит его свойству, а Matreshka.Array#restore восстановит состояние коллекции.

Что такое debounce?

В документации часто встречается фраза "микропаттерн debounce". Это распространенный паттерн, который превращает несколько вызовов функции в течение определенного времени в один вызов. Подробнее в статье на Хабрахабр или на англоязычном ресурсе.

Что из себя должно представлять крупное приложение?

Приложение на базе Matreshka.js, как правило, представляет из себя один вложенный JavaScript объект, каждая ветвь которого - экземпляр Matreshka. Новые ветви приложения создаются при помощи Matreshka#instantiate, что гарантирует целостность приложения и возможность вернуть предыдущее состояние приложения или одной его ветви обычными присваиванием.

Как отрендерить один объект в контейнерах нескольких коллекций?

Первое: нужно установить классу этого объекта свойство bindRenderedAsSandbox со значением false. Это отключает автоматическое создание песочницы при рендеринге объекта в массиве (т. к. запрещено одному объекту иметь две песочницы).

Второе: по событию render проверить, в какой массив был вставлен объект и объявить байндинги, соответствующие массиву. Родительский массив и отрисованный элемент можно получить, обратившись к свойствам parentArray и node объекта события.

Пример. Есть класс объекта User и две коллекции: UsersA и UsersB (их Matreshka.Array#itemRenderer может отличаться). Для обоих коллекций User используется в качестве Matreshka.Array#Model.

class User extends Matreshka.Object {
    constructor() {
        super();

        this.bindRenderedAsSandbox = false;

        setInterval(() => {
            // изменив name изменятся и все связанные
            // с этим свойством элементы
            this.name = Math.random();
        }, 5000);
    }
    onRender(evt) {
        const { parentArray, node } = evt;

        if(parentArray instanceof UsersA) {
            this.bindNode({
                // создаём псевдо-песочницу
                // для синтаксического сахара в селекторах
                // (это не обязательно)
                nodeA: node,
                name: ':bound(nodeA) .name',
                email: ':bound(nodeA) .email',
            });
        } else if(parentArray instanceof UsersB) {
            this.bindNode({
                nodeB: node,
                name: ':bound(nodeB) .user-name',
            });
        }
    }
}

На самом деле есть много способов решения этой задачи. Например, можно объявлять байндинги на уровне массива (т. е. массив будет слушать событие render вставленных объектов) или на уровне массива привязывать только псевдо-песоницу, а на уровне объекта слушать событие bind и объявлять остальные привязки...

Нашли опечатку?
Выберите текст и нажмите
+
Ошибка на сайте