До вмісту
Matreshka.js 3.0

Matreshka.js

<output class="out"></output>
<input class="in" type="text">

<script src="https://cdn.jsdelivr.net/npm/matreshka@3/dist/matreshka.min.js"></script>
<script>
const app = new Matreshka();
app.bindNode('x', '.in, .out');
app.x = 'Простий фреймворк для створення односторінкових веб додатків';
</script>

Навіщо Matreshka

Для сторінок, у яких HTML уже готовий: серверний рендеринг, віджети, старі проєкти, сторінка з одного HTML-файлу. Підключіть один тег <script> і прив’яжіть властивості об’єкта до елементів просто в JavaScript — розмітку змінювати не потрібно. Проєкт розвивається з 2013 року; версія 3.0 — це один пакет з ES-модулями та типами TypeScript, без залежностей.

Розмір: matreshka.min.js важить 62,1 кБ у мініфікованому вигляді, 20,1 кБ зі стисненням gzip і 18,0 кБ з brotli — так CDN віддає його сучасним браузерам. matreshka.core.min.js, те саме без роутера й парсера форм, важить 16,9 кБ з brotli.

Фічі

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

Детальніше у вступі, або одразу до довідника API.

Встановлення

npm install matreshka
import Matreshka from 'matreshka';

Для ШІ-агентів, що пишуть код (Claude Code, Cursor, Codex та інших), додайте скіл Matreshka:

npx skills add finom/matreshka

Щоб дати мовній моделі всю документацію одним файлом, скопіюйте в чат llms-full.txt.

Документація також є англійською і російською.

Знайшли помилку в статті? Надішліть патч з виправленням.

Вступ

Matreshka.js поєднує JavaScript-об’єкти з HTML, який уже є на сторінці. Ви прив’язуєте властивість до DOM-вузла, і відтепер вони синхронізовані. Змінюєте властивість — оновлюється вузол; вводите текст у вузол — змінюється властивість. Без шаблонів, без віртуального DOM і без збирання.

Як це працює

Прив’язка додає властивості геттер і сеттер. Присвоєння app.x = 'hi' викликає сеттер: він оновлює всі вузли, прив’язані до x, і генерує подію change:x. Залежні властивості, перетворення значень і колекції побудовані на цьому ж механізмі.

Де вона доречна

  • Сторінки, HTML яких приходить із сервера: сайти із серверним рендерингом, теми CMS, старі застосунки. Matreshka додає поведінку до цієї розмітки, не забираючи її під свій контроль.
  • Віджети та окремі HTML-файли: один тег <script> із CDN, без npm і без збирача.
  • Наявний код: прив’язка працює з будь-яким звичайним об’єктом, тож її можна додавати частинами.

Що ви отримуєте

  • Двосторонню прив’язку до полів введення, тексту, атрибутів і класів
  • Залежні властивості (calc) і перетворення значень (mediate)
  • Списки, що рендерять кожен елемент і лишаються синхронізованими (Matreshka.Array)
  • Події змін, зокрема для вкладених даних
  • Роутер і парсер форм

Близько 20 кБ у gzip, з типами TypeScript.

Чим вона не є

Компонентним фреймворком. У ній немає JSX, однофайлових компонентів і серверного рендерингу. Якщо ви пишете весь інтерфейс на JavaScript з нуля, краще підійдуть React або Vue.

Знайшли помилку в статті? Надішліть патч з виправленням.

Як почати

Встановлення

npm install matreshka
import Matreshka from 'matreshka';
// або через CommonJS (Node.js 22.12+)
const { Matreshka } = require('matreshka');

Роутер і парсер форм — у тому ж пакеті: matreshka/router пов’язує властивості з частинами URL, matreshka/parse-form пов’язує іменовані поля форми з властивостями.

initRouter(object, '/a/b/') синхронізує object.a і object.b з частинами location.hash після #! (#!/foo/bar/); в URL значення закодовані, у властивостях — декодовані. Щоб натомість використовувати шлях через History API, передайте 'history' третім аргументом. parseForm(object, form) повертає форму або null, якщо форму не знайдено. Докладніше: Matreshka.initRouter, Matreshka.parseForm.

import { initRouter } from 'matreshka/router';
import { parseForm } from 'matreshka/parse-form';

Тег script

Без збирача підключіть браузерний бандл. Він визначає глобальну змінну Matreshka з роутером і парсером форм: Matreshka.initRouter, Matreshka.Router і Matreshka.parseForm. Бандл розрахований на сучасні браузери.

<script src="https://cdn.jsdelivr.net/npm/matreshka@3/dist/matreshka.min.js"></script>

Цей самий файл віддає і цей сайт: /matreshka.min.js.

ES-модуль з CDN

Без збирача можна імпортувати matreshka.min.mjs — той самий код одним ES-модулем: усі іменовані експорти matreshka, а також initRouter, Router і parseForm. Це один запит, і важить він стільки ж, скільки файл для тегу script.

<script type="module">
  import { bindNode, calc, binders, initRouter } from 'https://cdn.jsdelivr.net/npm/matreshka@3/dist/matreshka.min.mjs';
</script>

Модулі

Кожна статична функція або клас — іменований експорт головного модуля.

import { MatreshkaArray, bindNode, binders } from 'matreshka';

const { prop } = binders;

Рівні важливості

Документація розбита на три рівні важливості.

Перший рівень — найважливіше

Вивчивши найважливіші властивості і методи, ви можете сміливо приступати до роботи. Почніть з Matreshka#bindNode, Matreshka#calc, Matreshka#on, Matreshka.Object і Matreshka.Array.

Другий рівень — рекомендується вивчити

Після того, як ви освоїли необхідні для швидкого старту можливості, можете ознайомитися з іншими, менш важливими (але все ще важливими) властивостями і методами фреймворку.

Третій рівень — інші методи і властивості

Для того, щоб не лякати новачків речами, які використовуються відносно рідко, інші методи і властивості за замовчуванням приховані. Якщо ви хочете знати про фреймворк все, без винятку, оберіть на перемикачі зліва, в меню.

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

Далі: Hello World та інші приклади.

Знайшли помилку в статті? Надішліть патч з виправленням.

Як користуватися документацією

Рівні важливості

Документація розбита на три рівні важливості.

Перший рівень - найважливіше

Вивчивши найважливіші властивості і методи, ви можете сміливо приступати до роботи. З класами, методами і властивостями, поміченими значком необхідно розібратися в першу чергу.

Другий рівень - рекомендується вивчити

Після того, як ви освоїли необхідні для швидкого старту можливості, можете ознайомитися з іншими, менш важливими (але все ще важливими) властивостями і методами фреймворку.

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

Для того, щоб не лякати новачків речами, які використовуються відносно рідко, інші методи і властивості за замовчуванням приховані. Якщо ви хочете знати про фреймворк все, без винятку, оберіть на перемикачі зліва, в меню.

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

Помилки в документації

У кінці кожної статті документації є посилання на код цієї статті. Виправити помилку можна прямо в редакторі на Github.

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

Модулі

Фреймворк - один пакет з трьома точками входу.

import Matreshka from 'matreshka';
import { initRouter } from 'matreshka/router';
import { parseForm } from 'matreshka/parse-form';

Знайшли помилку в статті? Надішліть патч з виправленням.

Приклади

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://cdn.jsdelivr.net/npm/matreshka@3/dist/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!';

Запустити приклад.

Посилання

Живі приклади

Кожен приклад працює на цьому сайті; його код лежить у папці examples репозиторію.

  1. TodoMVC – список справ. (Код з анотаціями, код)
  2. TreeView – деревовидний список необмеженої вкладеності. (Код)
  3. Markdown editor – найпростіший редактор Markdown. (Код)
  4. Contact List – дозволяє додавати, видаляти, сортувати, змінювати і шукати контакти. (Код)
  5. Форма входу на Matreshka.Object. (Посібник, англійською)
  6. Таблиця користувачів на Matreshka.Array. (Посібник, англійською)
  7. Демо matreshka/router – властивості, зв’язані з частинами URL. (Код)
  8. Демо matreshka/parse-form – поля форми, зв’язані з властивостями за іменами. (Код)
  9. Форма реєстрації – форма, відрендерена на сервері: email перевіряється під час введення, смужка показує надійність пароля. (Код)
  10. Таблиця товарів – пошук, сортування і фільтр по рядках, які рендерить Matreshka.Array. (Код)
  11. Віджет ціни – віджет на чужій сторінці, який bindSandbox тримає всередині його кореня. (Код)

Посібники

  • Події (англійською) – стаття про механізм подій, на якому працюють calc, bindNode, instantiate та інші методи.
  • Matreshka.Object і Matreshka.Array крок за кроком (англійською), з живими прикладами вище.

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka

НайважливішеКлас

Імпорт:

import Matreshka from 'matreshka';

Клас Matreshka - це ядро фреймворка Matreshka.js, від якого успадковуються Matreshka.Array, Matreshka.Object і кожен клас створюваного додатка. Він містить основний функціонал фреймворка: медіатори, залежності, прив'язки до DOM, механізм подій тощо.

Як правило, цей клас, (як і Matreshka.Array і Matreshka.Object), не використовуються безпосередньо. Замість цього, від нього успадковуються класи, створювані розробником.

Посилання

Приклади

Створення екземпляру

const matreshka = new Matreshka();

Спадкування

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

Спадкування за допомогою функції Matreshka.Class

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

Методи і властивості

  • bindNode – Пов'язує властивість об'єкта з HTML елементом
  • bindOptionalNode – Працює в точності так само, як і Matreshka#bindNode але не кидає виняток, якщо аргумент node - порожній масив, undefined або не існує
  • bindSandbox – Прив'язує пісочницю
  • calc – Створює залежність значення однієї властивості від значень інших
  • instantiate – Створює фіксований екземпляр класу
  • isMatreshka – isMatreshka завжди дорівнює true для экземплярів Matreshka
  • mediate – Трансформує значення властивості при його зміні
  • $nodes – Об'єкт містить масиви прив'язаних елементів для швидкого доступу.
  • nodes – Об'єкт містить прив'язані елементи для швидкого доступу, у вигляді окремих DOM вузлів.
  • off – Видаляє обробник події
  • on – Додає обробник події
  • onDebounce – Додає обробник події, що викликається лише одного разу за певний проміжок часу
  • once – Додає обробник подій, який може бути викликаний один раз
  • parseBindings – Парсить DOM дерево, оголошуючи прив'язки властивостей, взятих в подвійні фігурні дужки.
  • remove – Видаляє властивість
  • select – Повертає елемент з пісочниці, відповідний селектору
  • selectAll – Повертає елементи з пісочниці, відповідні селектору
  • set – Встановлює значення властивості, дозволяючи передати об'єкт події в якості третьої аргументу
  • trigger – Генерує подію
  • unbindNode – Розриває зв'язок між властивістю і HTML елементом

Статичні методи

  • Class – Реалізація класів, заснована на прототипному спадкуванні
  • bindNode – Пов'язує властивість об'єкта з HTML елементом
  • bindOptionalNode – Пов'язує елемент із властивістю, але не кидає виняток, якщо аргумент node - порожній масив, undefined або не існує
  • bindSandbox – Пов'язує властивість sandbox з елементом і одв'язує попередній елемент, якщо такий існує
  • calc – Створює залежність значення одної властивості від значень інших
  • chain – Дозволяє викликати універсальні методи ланцюгом
  • defaultBinders – Масив функцій, які повертають відповідний Байндер або undefined
  • instantiate – Створює фіксований екземпляр класу
  • initRouter – Вмикає двостороннє зв'язування даних між властивостями і частинами URL
  • lookForBinder
  • mediate – Трансформує значення властивості при його зміні
  • off – Видаляє обробник події
  • on – Додає обробник події
  • onDebounce – Додатє обробник події, що викликається лише однин раз за певний проміжок часу
  • once – Додає обробник події, який може бути викликаний лише один раз
  • parseBindings – Парсить DOM дерево, оголошуючи прив'язки властивостей, взятих в подвійні фігурні дужки
  • parseForm – Прив'язує іменовані поля HTML форми до відповідних властивостей
  • parserBrackets – Містить дужки для парсера
  • remove – Видаляє властивість
  • select – Повертає елемент з пісочниці, відповідний селектору
  • selectAll – Повертає елементи з пісочниці, відповідні селектору
  • set – Встановлює значення властивості, дозволяючи передати об'єкт події в якості третьої аргументу
  • toMatreshka – Функція, яка конвертує довільну структуру об'єктів і масивів в екземпляри Matreshka.Object та Matreshka.Array
  • trigger – Генерує подію
  • unbindNode – Розриває зв'язок між властивістю і HTML елементом

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#bindNode

НайважливішеМетод

Matreshka#bindNode(key, node, [binder], [eventOptions]) → object

Пов'язує властивість об'єкта з HTML елементом

bindNode - це єдиний метод класу Matreshka, який відповідає за зміни DOM. Він створює міст між значенням властивості і станом HTML елемента на сторінці: від простого інпут до складного віджета (складність елементів не обмежена). Після зв'язування властивості екземпляра і HTML елемента не потрібно більше стежити за синхронізацією даних та виду.

Зверніть увагу, що у метода є статичний аналог, який працює в точності так само, але приймає будь-який об'єкт в якості першого аргументу, зсовуючи інші аргументи вправо.

import { bindNode } from 'matreshka';
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 });
	}
});
// Встановить значення слайдера 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)', () => {...});

Якщо елемент не знайдений, кидається виняток Binding error: node is missing for key "KEY" (мініфіковані файли кидають коротке Matreshka error binding:node_missing (key: "KEY")). Для того, щоб уникнути помилки використовуйте метод 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 передати строку, що містить точку, то така строка буде інтерпрітірована як шлях до властивості у вкладеному об'єкті. Matreshka.js буде слухати зміни в усьому дереві, розриваючи зв'язок для старих гілок, і створюючи його для нових.

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 i/або 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 (необов'язковий) binder Байндер, що містить властивості on, getValue, setValue, initialize, destroy, див. binder.
eventOptions (необов'язковий) eventOptions Об'єкт події, в який можна передати ключ "silent" (щоб не генерувати події "bind" і "bind:KEY"), прапори, описані вище або кастомні дані

Посилання

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

Matreshka#bindNode(bindings, [binder], [eventOptions]) → object

У метод Matreshka#bindNode можна передати об'єкт щоб уникнути багаторазового виклику методу і скоротити код. Ключі об'єкта - це імена властивостей, а значення можуть бути наступними:

  • HTML елемент
  • Об'єкт з властивостями node (HTML елемент) і binder
  • Масив об'єктів з властивостями node (HTML елемент) і binder

Якщо binder переданий другим аргументом, то він служить байндером для тих елементів, для яких байднер не вказано явно.

Повертає: object – self

Аргументи

Ім'я Тип Опис
bindings object (див. приклад)
binder (необов'язковий) binder (див. вище)
eventOptions (необов'язковий) 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 (необов'язковий) 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#bindOptionalNode()

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

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

Посилання

Приклади

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

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#calc

НайважливішеМетод

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

Створює залежність значення однієї властивості від значень інших

Метод calc створює залежність значення властивості (аргумент target) від значень інших властивостей (аргумент source). При зміні source, target обчислюється автоматично.

Зверніть увагу, що у метода є статичний аналог, який працює в точності так само, але приймає будь-який об'єкт в якості першого аргументу, зсуваючи інші аргументи вправо.

import { calc } from 'matreshka';
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 someObject = {
	b: 1,
	c: 2
};
const someObjectY = {
	d: 3
};

this.calc('a', [{
	object: someObject,
	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: someObject,
	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
	key: ['b', 'c']
}, {
	object: someObject,
	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' });

Якщо джерело змінюється з прапором silent, ціль теж змінюється «тихо». Кастомні дані зміни джерела також потрапляють в обробники цілі. Прапори force, forceHTML, silentHTML і skipMediator зміни джерела на ціль не діють.

Прапор 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(b + c)
		}, 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 (необов'язковий) (v)=>v function Функція, що повертає нове значення
eventOptions (необов'язковий) 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, що дозволяє оголосити кілька обчислюваних властивостей одним викликом

Matreshka#calc(batch, [commonEventOptions])

Перший аргумент - об'єкт, ключі якого - імена властивостей, які потрібно обчислювати, а значення - об'єкти, що містять:

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

Другий аргумент - загальний об'єкт події, що розширює event для кожної шуканої властивості (властивості з event мають більший приоритет).

source може приймати будь-який вид опис вище (рядок, масив рядків, об'єкт з властивостями key і object, масив таких об'єктів).

Аргументи

Ім'я Тип Опис
batch array Об'єкт містить інформацію про обчислюваних властивості
commonEventOptions (необов'язковий) 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

Рекомендується вивчитиМетод

Matreshka#instantiate(key, class, [updateCallback]) → object

Створює фіксований екземпляр класу

Зверніть увагу, що у метода є статичний аналог.

Метод створює і фіксує екземпляр класу в якості значення заданогї властивості. При спробі перевизначити властивість, замість самого перевизначення, екземпляр оновлюється. Таким чином досягається цілісність програми, зробленої на базі Matreshka.js.

Метод є надбудовою над 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 (необов'язковий) 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) {
		super();
		// parent - це екземпляр MyParentClass,
        // який створив властивість
		// key - им'я властивості ("х")
	}
}

class MyParentClass extends Matreshka {
	constructor() {
		super().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) {
		super();
		this.appData = appData;
		this.instantiate('appData', AppData);
	}
}

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

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

// friends.js
class Friends extends Matreshka.Array {
	get Model() { return 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, який дозволяє приймати об'єкт ключ-клас в якості аргументу

Matreshka#instantiate(keyClassPairs, [updateCallback]) → object

Повертає: object – self

Аргументи

Ім'я Тип Опис
keyClassPairs object Об'єкт з властивостями ключ-клас
updateCallback (необов'язковий) function Функція, яка викликається при кожній спробі присвоїти нові данні властивості.

Приклади

this.instantiate({
	x: Class1,
	y: Class2,
	z: Class3
}, (instance, data) => {
	instance.doSomethingWith(data);
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#mediate

Рекомендується вивчитиМетод

Matreshka#mediate(key, mediator)

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

Цей метод використовується для перетворення значення властивості при його зміні. Наприклад, вам потрібно, щоб значення властивості завжди було або певного типу, або цілим числом, або бути не менше нуля і не більше ста тощо.

Зверніть увагу, що у метода є статичний аналог, який працює в точності так само, але приймає будь-який об'єкт в якості першого аргументу, зсуваючи інші аргументи вправо.

import { mediate } from 'matreshka';
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, приймаючий в якості аргументу об'єкт "ключ-медіатор"

Matreshka#mediate(keyMediatorPairs)

Аргументи

Ім'я Тип Опис
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

НайважливішеМетод

Matreshka#off([names], [callback], [context]) → matreshka

Видаляє обробник події

Видаляє створений раніше обробник. Всі три аргументи опційні. Ви можете видалити як всі події (не передаючи жодного аргументу), так і окремі (передавши тільки ім'я події, передавши ім'я події і обробник, передавши і ім'я події, і обробник, і контекст)

Без аргументів off видаляє всі обробники, додані через on, once і onDebounce, і генерує removeevent для кожного з них. Прив'язки, залежності calc і внутрішні події Matreshka.Object та Matreshka.Array залишаються.

Повертає: matreshka – self

Генерує події: removeevent, removeevent:NAME

Аргументи

Ім'я Тип Опис
names (необов'язковий) eventNames Розділений пробілами список імен подій (наприклад, "change:x ajaxcomplete change:y")
callback (необов'язковий) eventHandler Функція-обробник
context (необов'язковий) 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

НайважливішеМетод

Matreshka#on(names, callback, [triggerOnInit=false], [context]) → object

Додає обробник події

Метод Matreshka#on додає обробник події для екземпляра класу Matreshka. Повний список можливих подій з описом см. Тут: eventNames.

Зверніть увагу, що у методва є статичний аналог, який працює в точності так само, але приймає будь-який об'єкт в якості першого аргументу, зсуваючи інші аргументи вправо.

import { on } from 'matreshka';
const object = {};
on(object, names, callback, triggerOnInit, context);
// Замість this.on(names, callback, triggerOnInit, context);

Повторне додавання того самого обробника з тим самим контекстом для тієї самої події нічого не змінює. Для DOM подій (click::x) діє те саме правило.

Повертає: object – self

Генерує події: addevent, addevent:NAME

Аргументи

Ім'я За замовчуванням Тип Опис
names eventNames Ім'я події або кілька імен, розділених пробілом (наприклад, "change:x ajaxcomplete change:y")
callback eventHandler Функція, яка викликається за подією
triggerOnInit (необов'язковий) false boolean Якщо аргумент triggerOnInit дорівнює true, то обробник буде викликаний негайно після ініціалізації.
context (необов'язковий) 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=false], [context]) → object

У метод Matreshka#on можна передати об'єкт з парами подія-обробник, щоб уникнути багаторазового виклику методу і скоротити код.

Повертає: object – self

Аргументи

Ім'я За замовчуванням Тип Опис
evtnameHandlerObject object Об'єкт з подіями
triggerOnInit (необов'язковий) false boolean Якщо аргумент triggerOnInit дорівнює true, то обробники будуть викликані негайно після ініціалізації
context (необов'язковий) object Контекст обробника

Приклади

this.on({
	'custom': evt => ...,
	'click::x': evt => ...,
	'change:y': evt => ...,
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#once

Рекомендується вивчитиМетод

Matreshka#once(names, callback, [context]) → object

Додає обробник подій, який може бути викликаний один раз

Метод працює так само, як і Matreshka#on але переданий обробник може бути викликаний тільки один раз.

Зверніть увагу, що у метода є статичний аналог

Повертає: object – self

Генерує події: addevent, addevent:NAME

Аргументи

Ім'я Тип Опис
names eventNames Ім'я події або кілька імен, розділених пробілом (наприклад, <code>"change:x ajaxcomplete change:y" </code>)
callback eventHandler Функція, яка викликається за подією
context (необов'язковий) 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 (необов'язковий) object Контекст обробників

Посилання

Приклади

this.once({
	'custom': evt => { ... },
	'click::x': evt => { ... },
	'change:y': evt => { ... }
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#onDebounce

Рекомендується вивчитиМетод

Matreshka#onDebounce(names, callback, [debounceDelay=0], [triggerOnInit=false], [context]) → object

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

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

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

Повертає: object – self

Генерує події: addevent, addevent:NAME

Аргументи

Ім'я За замовчуванням Тип Опис
names eventNames Ім'я події або кілька імен, розділених пробілом (наприклад, <code>"change:x ajaxcomplete change:y" </code>)
callback eventHandler Функція, яка викликається за подією
debounceDelay (необов'язковий) 0 number Затримка
triggerOnInit (необов'язковий) false boolean Якщо аргумент triggerOnInit дорівнює true, то обробник буде викликаний негайно після ініціалізації
context (необов'язковий) object Контекст обробника

Посилання

Приклади

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

this.x = 1;

for(let i = 0; i < 100; i++) {
	this.x++;
}

Альтернативний синтаксис: пари "подія-обробник"

Matreshka#onDebounce(evtnameHandlerObject, [debounceDelay=0], [triggerOnInit=false], [context]) → object

У метод Matreshka#onDebounce можна передати об'єкт з парами подія-обробник, щоб уникнути багаторазового виклику методу і скоротити код.

Повертає: object – self

Аргументи

Ім'я За замовчуванням Тип Опис
evtnameHandlerObject object Об'єкт з обробниками подій
debounceDelay (необов'язковий) 0 number Затримка
triggerOnInit (необов'язковий) false boolean Якщо аргумент triggerOnInit дорівнює true, то обробники будуть викликаний негайно після ініціалізації
context (необов'язковий) object Контекст обробників

Посилання

Приклади

this.onDebounce({
	'custom': evt => { ... },
	'click::x': evt => { ... },
	'change:y': evt => { ... }
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#parseBindings

Рекомендується вивчитиМетод

Matreshka#parseBindings(node, [eventOptions]) → $nodes

Парсить DOM дерево, оголошуючи прив'язки властивостей, взятих в подвійні фігурні дужки.

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>
  1. Прив'язка елементів форм.
<!--
Зв'яже властивість "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}}">
  1. Прив'язка атрибутів.
<!--
Значення атрибута 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 вузлів HTML
eventOptions (необов'язковий) 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#select

Рекомендується вивчитиМетод

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

Рекомендується вивчитиМетод

Matreshka#selectAll(selector) → $nodes

Повертає елементи з пісочниці, відповідні селектору

Синонім: Matreshka#$

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

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

Повертає: $nodes

Аргументи

Ім'я Тип Опис
selector string Селектор

Приклади

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

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

this.bindNode('myKey', '.my-element');
nodes = this.selectAll(':bound(myKey) .my-another-element');
// те ж саме, що і
nodes = $('.my-element').find('.my-another-element');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#set

НайважливішеМетод

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 (необов'язковий) 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 "ключ-значення"

Matreshka#set(keyValuePairs, [eventOptions])

Аргументи

Ім'я Тип Опис
keyValuePairs object Об'єкт, що містить пари ключ-значення
eventOptions (необов'язковий) eventOptions Об'єкт події

Приклади

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

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

this.set({
	myKey: 3
}, {
	myFlag: 'foo'
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#trigger

НайважливішеМетод

Matreshka#trigger(names, [arg]) → object

Генерує подію

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

Зверніть увагу, що у метода є статичний аналог.

Повертає: object – self

Аргументи

Ім'я Тип Опис
names eventNames Ім'я події або кілька імен, розділених пробілом
arg (необов'язковий) ...* Аргументи, які будуть передані обробникам

Посилання

Приклади

this.on('foo bar', (a, b, c) => {
	alert(a + b + c);
});
this.trigger('bar', 1, 2, 3); // alerts 6

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#unbindNode

Рекомендується вивчитиМетод

Matreshka#unbindNode(key, [node], [eventOptions]) → matreshka

Розриває зв'язок між властивістю і HTML елементом

Використовуючи цей метод, можна видалити доданий раніше, але вже не потрібний зв'язок між властивістю і елементом.

Ключ з крапками — це шлях до вкладеної властивості, як і в Matreshka#bindNode; з опцією події exactKey: true він використовується як є. null замість ключа видаляє також прив'язки вкладених властивостей ("a.b").

Повертає: matreshka – self

Генерує події: unbind, unbind:KEY

Аргументи

Ім'я Тип Опис
key string | null Ключ або список ключів, розділених пробілами. Якщо замість ключа передати null, будуть видалені всі прив'язки для даного об'єкта.
node (необов'язковий) string | node | $nodes HTML елемент, з яким властивість більше не хоче мати справи
eventOptions (необов'язковий) eventOptions Об'єкт події, в який можна передати якісь дані для обробника або ключ "silent", який відключає генерацію подій "unbind" і "unbind:KEY"

Приклади

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

// Змінює значення властивості і стан HTML елемента
this.myKey = true;

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

// Тепер змінюється лише значення властивості
this.myKey = false;

Альтернативний синтаксис unbindNode, що дозволяє передати об'єкт з байндінгамі. Див. Matreshka#bindNode(2)

Matreshka#unbindNode(bindings, [eventOptions]) → matreshka

Повертає: matreshka – self

Аргументи

Ім'я Тип Опис
bindings object (див. приклад)
eventOptions (необов'язковий) 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 (необов'язковий) 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#bindSandbox

Інші методи і властивостіМетод

Matreshka#bindSandbox(node, [eventOptions])

Прив'язує пісочницю

При цьому, "одв'язує" попередню, якщо така існує.

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

Ключ sandbox зарезервований для прив'язки: він не потрапляє в Object.keys і JSON.stringify, а читання або присвоєння this.sandbox кидає помилку. Прив'язаний вузол доступний як this.nodes.sandbox.

Генерує події: bind, bind:sandbox

Аргументи

Ім'я Тип Опис
node string | node | $nodes Елемент, який повинен стати пісочницею
eventOptions (необов'язковий) eventOptions Об'єкт події

Посилання

Приклади

this.bindSandbox('.my-element');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#remove

Інші методи і властивостіМетод

Matreshka#remove(key, [eventOptions]) → matreshka

Видаляє властивість

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

Повертає: matreshka – self

Генерує події: delete, delete:KEY

Аргументи

Ім'я Тип Опис
key string Им'я властивості або масив имен властивостей, які треба видалити
eventOptions (необов'язковий) eventOptions Об'ект події

Приклади

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

Використання eventOptions

this.remove('myKey', {
	silent: true
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#$nodes

Інші методи і властивостіВластивість

Matreshka#$nodes: $nodes

Об'єкт містить масиви прив'язаних елементів для швидкого доступу.

Посилання

Приклади

this.bindNode('myKey', '.my-node');
this.$nodes.myKey; // масив вузлів, як Array.from(document.querySelectorAll('.my-node'))

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka#nodes

Інші методи і властивостіВластивість

Matreshka#nodes: node

Об'єкт містить прив'язані елементи для швидкого доступу, у вигляді окремих DOM вузлів.

Зверніть увагу, кожна властивість об'єкта містить перший вузол з пов'язаних з соотвутствующий властивістю. Для отримання всіх вузлів, пов'язаних з певною властивістю, використовуйте Matreshka#$nodes.

Посилання

Приклади

this.bindNode('myKey', '.my-node');
this.nodes.myKey; // Те ж саме, що і $('.my-node')[0]

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.bindNode

НайважливішеМетод

Імпорт:

import { bindNode } from 'matreshka';
Matreshka.bindNode() → object

Пов'язує властивість об'єкта з HTML елементом

Цей статичний метод працює так само, як і Matreshka#bindNode та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.bindNode(object, 'x', '.my-node');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.calc

НайважливішеМетод

Імпорт:

import { calc } from 'matreshka';
Matreshka.calc() → object

Створює залежність значення одної властивості від значень інших

Цей статичний метод працює так само, як і 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

Рекомендується вивчитиМетод

Імпорт:

import { chain } from 'matreshka';
Matreshka.chain(object) → object

Дозволяє викликати універсальні методи ланцюгом

Функція приймає будь-який об'єкт і повертає екземпляр недоступного ззовні класу, який переймає універсальні методи, дозволяючи їх ланцюговий виклик для роботи з переданим об'єктом.

Універсальні методи - це такі методи, які одночасно є в прототипі 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.Class

Рекомендується вивчитиМетод

Імпорт:

import { Class } from 'matreshka';
Matreshka.Class(prototype, [statics]) → class

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

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

Якщо prototype не має власної властивості constructor, клас викликає батьківський конструктор з тими самими аргументами, як клас ECMAScript 2015 без конструктора. Як constructor можна передати клас ECMAScript 2015: він викликається при створенні екземпляра, але методи, оголошені в його тілі, не успадковуються; додайте їх у prototype.

Повертає: class – клас (точніше, конструктор класу)

Аргументи

Ім'я Тип Опис
prototype object Методи та властивості
statics (необов'язковий) 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.method3.apply(this, arguments);
	}
});

Передача об'єкта зі статичними методами і властивостями

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

alert(MyClass.staticProp); // foo
alert(MyClass.staticMethod()); // bar

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.mediate

НайважливішеМетод

Імпорт:

import { mediate } from 'matreshka';
Matreshka.mediate() → object

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

Цей статичний метод працює так само, як і Matreshka#mediate та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.mediate(object, 'x', String);
object.x = 42;
alert(typeof object.x); // string

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.on

НайважливішеМетод

Імпорт:

import { on } from 'matreshka';
Matreshka.on() → object

Додає обробник події

Цей статичний метод працює так само, як і Matreshka#on та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

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

Matreshka.trigger(object, 'foo', { hello: 'World' });

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.bindOptionalNode

Інші методи і властивостіМетод

Імпорт:

import { bindOptionalNode } from 'matreshka';
Matreshka.bindOptionalNode() → object

Пов'язує елемент із властивістю, але не кидає виняток, якщо аргумент node - порожній масив, undefined або не існує

Цей статичний метод працює так само, як і Matreshka#bindOptionalNode та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.bindOptionalNode(object, 'x', '.my-node');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.bindSandbox

Інші методи і властивостіМетод

Імпорт:

import { bindSandbox } from 'matreshka';
Matreshka.bindSandbox() → object

Пов'язує властивість sandbox з елементом і одв'язує попередній елемент, якщо такий існує

Цей статичний метод працює так само, як і Matreshka#bindSandbox та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.bindSandbox(object, '.my-node');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.instantiate

Інші методи і властивостіМетод

Імпорт:

import { instantiate } from 'matreshka';
Matreshka.instantiate() → object

Створює фіксований екземпляр класу

Цей статичний метод працює так само, як і Matreshka#instantiate та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.instantiate(object, 'x', SomeClass);
object.x = { a: 42 };
alert(object.x instanceof SomeClass); // true
alert(object.x.a); // 42

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.initRouter

Рекомендується вивчитиМетод

Імпорт:

import { initRouter } from 'matreshka/router';
Matreshka.initRouter(object, route, [type="hash"]) → object

Вмикає двостороннє зв'язування даних між властивостями і частинами URL

За замовчуванням роутер працює з хешем: він використовує location.hash з hashbang (#!/a/b/). Щоб натомість використовувати шлях (/a/b/) через History API, передайте "history" третім аргументом.

// використовується location.hash
initRouter(object, '/a/b/c/');
object.a = 'foo';
object.b = 'bar';
object.c = 'baz';

// location.hash стає #!/foo/bar/baz/

Якщо потрібно використовувати History API замість хешу, передайте "history" третім аргументом.

initRouter(object, '/a/b/c/', 'history');

Як працює «традиційний» роутинг? Розробник задає правило (маршрут) і функцію, яка викликається, коли поточний шлях відповідає правилу.

route("books/:id", id => {
	// щось робимо
});

Принцип initRouter інший. Ви вказуєте, яка частина URL (підтримуються і хеш, і HTML5 History) синхронізується з якою властивістю.

Скажімо, потрібно синхронізувати "x" з першою частиною location.hash, а "y" з другою.

initRouter(object, '/x/y/');

Тепер, коли ви пишете...

object.x = 'foo';
object.y = 'bar';

...location.hash автоматично змінюється на #!/foo/bar/

І навпаки. Коли URL змінюється вручну або кнопками «назад» і «вперед», властивості змінюються автоматично.

location.hash = '#!/baz/qux/';

// ... за мить
console.log(object.x, object.y); // 'baz', 'qux'

Як завжди, зміни властивостей можна слухати методом Matreshka#on.

Matreshka.on(object, 'change:x', handler);
// для екземплярів Matreshka: this.on('change:x', handler);

Значення кодуються в URL і декодуються назад: object.x = 'a b/c' дає #!/a%20b%2Fc/, а object.x залишається 'a b/c'. Хеш, який не починається з #! (якір на кшталт #top), не є маршрутом.

Синтаксис зірочки

Якщо якусь частину шляху не потрібно синхронізувати з властивістю, поставте на її місце зірочку.

initRouter(object, '/x/*/y');

Якщо хеш має вигляд #!/foo/bar/baz/, то object.x = "foo", а object.y = "baz".

Це зручно, коли різні класи керують різними частинами шляху.

class1.js

initRouter(this, '/x/*/');

class2.js

initRouter(this, '/*/y/');

Дві речі, які треба запам'ятати

1. Якщо властивість має значення (не undefined, null і не ''), URL змінюється одразу після виклику initRouter. Властивість без значення отримує значення з URL.

object.x = 'foo';

initRouter(object, '/x/y/');

2. Якщо властивість отримує null, undefined або '', усі наступні за нею властивості отримують null.

initRouter(object, '/x/y/z/u/');

object.y = null; // object.z і object.u теж стають null

Ідея в тому, щоб властивості відображали актуальний стан URL. Було б дивно отримати "z" зі значенням "foo", коли відповідної частини URL немає.

HTML5 History API

Роутер підтримує і HTML5 History. Для цього передайте функції initRouter необов'язковий аргумент type зі значенням "history" (за замовчуванням type дорівнює "hash").

initRouter(object, '/x/y/z/', 'history');

Роутер читає і пише location.pathname; рядок запиту і хеш залишаються як є.

На сторінці з бандлом, підключеним тегом script, функція доступна як Matreshka.initRouter.

Повертає: object – Перший аргумент

Аргументи

Ім'я За замовчуванням Тип Опис
object object Об'єкт
route string Маршрут: імена властивостей через скісну риску, * для частини, яка не синхронізується
type (необов'язковий) "hash" string "hash" або "history"

Посилання

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.lookForBinder

Інші методи і властивостіМетод

Імпорт:

import { lookForBinder } from 'matreshka';
Matreshka.lookForBinder(node) → binder

Повертає байндер, відповідний елементу. Якщо байндер не знайдений, повертає 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.off

Інші методи і властивостіМетод

Імпорт:

import { off } from 'matreshka';
Matreshka.off() → object

Видаляє обробник події

Цей статичний метод працює так само, як і Matreshka#off та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Якщо передати тільки об'єкт, метод видаляє всі обробники, додані через on, once і onDebounce; прив'язки й залежності calc залишаються.

Повертає: object – Перший аргумент

Посилання

Приклади

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

Matreshka.off(object, 'foo');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.once

Інші методи і властивостіМетод

Імпорт:

import { once } from 'matreshka';
Matreshka.once() → object

Додає обробник події, який може бути викликаний лише один раз

Цей статичний метод працює так само, як і Matreshka#once та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

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

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.onDebounce

Інші методи і властивостіМетод

Імпорт:

import { onDebounce } from 'matreshka';
Matreshka.onDebounce() → object

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

Цей статичний метод працює так само, як і Matreshka#onDebounce та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

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

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.parseBindings

Інші методи і властивостіМетод

Імпорт:

import { parseBindings } from 'matreshka';
Matreshka.parseBindings() → $nodes

Парсить DOM дерево, оголошуючи прив'язки властивостей, взятих в подвійні фігурні дужки

Цей статичний метод працює так само, як і Matreshka#parseBindings та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: $nodes – Колекція оброблених DOM вузлів, передана в функцію як аргумент

Посилання

Приклади

const object = {};
const $node = Matreshka.parseBindings(object, `<h3>
        Hello, {{name}}
    </h3>`);
object.name = 'World';

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.parseForm

Рекомендується вивчитиМетод

Імпорт:

import { parseForm } from 'matreshka/parse-form';
Matreshka.parseForm(object, form, [callback], [eventOptions]) → node|null

Функція прив'язує іменовані поля HTML форми (input, select, textarea тощо) до відповідних властивостей.

<form class="my-form">
    <input type="text" value="foo" name="x">
</form>
const object = {};
parseForm(object, '.my-form');

// ...
console.log(object.x); // 'foo'
object.x = 'bar'; // змінює значення поля на 'bar'

Третій аргумент корисний, коли parseForm використовується з Matreshka.Object: у ньому можна викликати метод Matreshka.Object#addDataKeys.

const form = parseForm(this, ':sandbox .foo', key => this.addDataKeys(key), {
    getValueOnBind: false
});

На сторінці з бандлом, підключеним тегом script, функція доступна як Matreshka.parseForm.

Повертає: node | null – Елемент форми або null, якщо форму не знайдено

Аргументи

Ім'я Тип Опис
object object Об'єкт
form string | node | $nodes Селектор, DOM вузол тощо форми (кастомні селектори :sandbox і :bound(KEY) теж підходять)
callback (необов'язковий) function Функція, яка викликається для кожного знайденого поля; отримує ім'я поля і сам елемент
eventOptions (необов'язковий) eventOptions Опції події, які передаються в кожен внутрішній виклик Matreshka#bindNode

Посилання

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.remove

Інші методи і властивостіМетод

Імпорт:

import { remove } from 'matreshka';
Matreshka.remove() → object

Видаляє властивість

Цей статичний метод працює так само, як і Matreshka#remove та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

Matreshka.remove(object, 'x');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.select

Інші методи і властивостіМетод

Імпорт:

import { select } from 'matreshka';
Matreshka.select() → node|null

Повертає елемент з пісочниці, відповідний селектору

Цей статичний метод працює так само, як і Matreshka#select та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: node | null – знайдений елемент

Посилання

Приклади

const object = {};
Matreshka.bindNode(object, 'sandbox', '.app');
Matreshka.select(object, '.my-element');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.selectAll

Інші методи і властивостіМетод

Імпорт:

import { selectAll } from 'matreshka';
Matreshka.selectAll() → $nodes

Повертає елементи з пісочниці, відповідні селектору

Цей статичний метод працює так само, як і Matreshka#selectAll та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: $nodes – найденные элементы

Посилання

Приклади

const object = {};
Matreshka.bindNode(object, 'sandbox', '.app');
Matreshka.selectAll(object, '.my-element');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.set

Інші методи і властивостіМетод

Імпорт:

import { set } from 'matreshka';
Matreshka.set() → object

Встановлює значення властивості, дозволяючи передати об'єкт події в якості третьої аргументу

Цей статичний метод працює так само, як і Matreshka#set та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.set(object, 'x', 42, {
	someOption: true
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.toMatreshka

Інші методи і властивостіМетод

Імпорт:

import { toMatreshka } from 'matreshka';
Matreshka.toMatreshka() → matreshka

Функція, яка конвертує довільну структуру об'єктів і масивів в екземпляри Matreshka.Object та Matreshka.Array

Тільки масиви та екземпляри Matreshka.Array стають Matreshka.Array; будь-який інший об'єкт, навіть з властивістю length, стає Matreshka.Object. З переданого Matreshka.Object беруться тільки ключі, що відповідають за дані.

Повертає: matreshka – новостворений екземпляр Matreshka

Приклади

const matreshka = Matreshka.toMatreshka({
	a: 1,
	b: {
		c: 2
	},
	d: [{e: 1}, {e: 2}, {e: 3}]
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.trigger

Інші методи і властивостіМетод

Імпорт:

import { trigger } from 'matreshka';
Matreshka.trigger() → object

Генерує подію

Цей статичний метод працює так само, як і Matreshka#trigger та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

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

Matreshka.trigger(object, 'foo', { hello: 'World' });

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.unbindNode

Інші методи і властивостіМетод

Імпорт:

import { unbindNode } from 'matreshka';
Matreshka.unbindNode() → object

Розриває зв'язок між властивістю і HTML елементом

Цей статичний метод працює так само, як і Matreshka#unbindNode та всі його варіації, але приймає в якості першого аргументу будь-який JavaScript об'єкт.

Повертає: object – Перший аргумент

Посилання

Приклади

const object = {};
Matreshka.unbindNode(object, 'x', '.my-node');

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.defaultBinders

Рекомендується вивчитиВластивість

Імпорт:

import { defaultBinders } from 'matreshka';
Matreshka.defaultBinders: array

Масив функцій, які повертають відповідний Байндер або 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

Інші методи і властивостіВластивість

Імпорт:

import { parserBrackets } from 'matreshka';
Matreshka.parserBrackets: object

Містить дужки для парсера

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

Дужками можуть бути будь-які символи.

Приклади

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

Matreshka.parserBrackets.left = '[[=';
Matreshka.parserBrackets.right = ']]';

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object

НайважливішеКласextends Matreshka

Імпорт:

import { MatreshkaObject } from 'matreshka';

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 (необов'язковий) object Дані, що входять в новий екземпляр

Приклади

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

// те ж саме, що і new Matreshka.Object().setData({ a: 1, b: 2 });
new Matreshka.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 matreshkaObject = new Matreshka.Object({ a: 1, b: 2 });
for(let item of matreshkaObject) {
	console.log(item); // 1 .. 2
}

Методи і властивості

  • addDataKeys – Додає задані імена властивостей в список імен властивостей, що відповідають за дані
  • each – Перебирає властивості, що відповідають за дані
  • entries – Повертає масив пар імен і значень властивостей, що відповідають за дані
  • isDataKey – Перевіряє, чи входить строка до списку імен властивостей, що відповідають за дані
  • isMatreshkaObject – Властивість isMatreshkaObject завжди дорівнює true для екземплярів Matreshka.Object.
  • keyOf – Шукає задане значення властивості серед властивостей, що відповідають за дані, і повертає ім'я властивості, якщо таке значення знайдено
  • keys – Повертає масив імен властивостей, що відповідають за дані
  • removeDataKeys – Видаляє задані імена властивостей зі списку імен властивостей, що відповідають за дані (але не видаляє властивість)
  • setData – Встановлює значення властивості і додає його ім'я в список імен властивостей, що відповідають за дані
  • toJSON – Конвертує екземпляр Matreshka.Object в звичайний об'єкт
  • values – Повертає масив значень властивостей, що відповідають за дані

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object#addDataKeys

НайважливішеМетод

Matreshka.Object#addDataKeys(keys) → matreshkaObject

Додає задані імена властивостей в список імен властивостей, що відповідають за дані

Цей метод застосовується тоді, коли потрібно оголосити властивості, що відповідають за дані, але значення цих властивостей ще не відомі.

Повертає: matreshkaObject – self

Генерує події: set, modify

Аргументи

Ім'я Тип Опис
keys string | array Масив імен властивостей або список аргументів з іменами властивостей

Приклади

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

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object#each

Рекомендується вивчитиМетод

Matreshka.Object#each(callback, [thisArg]) → matreshkaObject

Перебирає властивості, що відповідають за дані

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

Повертає: matreshkaObject – self

Аргументи

Ім'я Тип Опис
callback function Функція, яка викликається на кожній ітерації
thisArg (необов'язковий) * Контекст функції

Приклади

this
	.setData({ a: 1, b: 2 })
	.addDataKeys('c')
	.each((value, key) => {
		console.log(key, value);
	});
;
// >>> a 1, b 2, c undefined

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object#isDataKey

Рекомендується вивчитиМетод

Matreshka.Object#isDataKey(key) → boolean

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

Повертає: boolean – результат перевірки

Аргументи

Ім'я Тип Опис
key string

Приклади

console.log(this.isDataKey('a'));

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object#keyOf

Рекомендується вивчитиМетод

Matreshka.Object#keyOf() → string|null

Шукає задане значення властивості серед властивостей, що відповідають за дані, і повертає ім'я властивості, якщо таке значення знайдено

Повертає: string | null – перше знайдене ім'я властивості

Властивості

Ім'я Тип Опис
value * значення будь-якого типу, яке слід знайти серед даних

Приклади

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

matreshkaObject.c = 3;

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

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

matreshkaObject.keyOf(3); // null

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object#removeDataKeys

Рекомендується вивчитиМетод

Matreshka.Object#removeDataKeys(keys) → matreshkaObject

Видаляє задані імена властивостей зі списку імен властивостей, що відповідають за дані (але не видаляє властивість)

Подія remove генерується раніше за modify, як і в Matreshka#remove.

Повертає: matreshkaObject – self

Генерує події: remove, modify

Аргументи

Ім'я Тип Опис
keys string | array Масив імен властивостей або список аргументів з іменами властивостей

Приклади

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

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Object#setData

НайважливішеМетод

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 (необов'язковий) 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, який приймає об'єкт ключ-значення для встановлення декількох властивостей одночасно

Matreshka.Object#setData(keyValuePairs, evtOpts) → matreshkaObject

Повертає: 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

НайважливішеМетод

Matreshka.Object#toJSON([recursive=true]) → object

Конвертує екземпляр Matreshka.Object в звичайний об'єкт

Метод працює рекурсивно, викликаючи toJSON для всіх властивостей, у яких є метод з таким ім'ям. Для скасування рекурсії передайте false першим аргументом.

Повертає: object

Аргументи

Ім'я За замовчуванням Тип Опис
recursive (необов'язковий) true boolean

Приклади

const matreshkaObject = 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(matreshkaObject.toJSON());

// повертає {a: 1, b: 2, c: MatreshkaObject}
console.log(matreshkaObject.toJSON(false));

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array

НайважливішеКласextends Matreshka

Імпорт:

import { MatreshkaArray } from 'matreshka';

Клас 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);

Як і нативний Array, одне число, яке не є допустимою довжиною (від'ємне, дробове або NaN), кидає RangeError.

Передача елементів при створенні

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!");
	}
});

Методи і властивості

  • METHOD – Будь-який метод із Array.prototype
  • METHOD_ – Будь-який метод із Array.prototype з можливістю передати об'єкт події
  • Model – Властивість визначає клас елементів, які буде містити колекція
  • isMatreshkaArray – isMatreshkaArray завжди дорівнює true для экземплярів Matreshka.Array
  • itemRenderer – HTML строка, селектор або функція, яка відповідає за рендерінг элементів масива на сторінці
  • mediateItem – Трансформує значення елементів масиву
  • onItemRender – Функція, яка запускається перед подією render.
  • orderBy – Сортує масив за значеннями властивостей об'єктів, які в нього входять
  • pull – Видаляє елемент за індексом або за значенням
  • recreate – Перестворює екземпляр Matreshka.Array
  • renderIfPossible – Властивість renderIfPossible скасовує рендеринг масиву якщо має значення false
  • rerender – Перемальовує DOM вузли об'єктів, що входять в масив
  • restore – Відтворює Matreshka.Array з HTML вузлів на сторінці.
  • toJSON – Конвертує екземпляр Matreshka.Array в звичайний масив
  • trackBy – Властивість trackBy вказує на ім'я властивості ідентифікатора об'єктів, що входять в масив
  • from – Метод створює новий екземпляр Matreshka.Array з масивоподібного або ітеруємого об'єкта
  • of – Метод створює новий екземпляр Matreshka.Array з довільного числа агрумент, незалежно від числа або типу аргументів

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#mediateItem

Рекомендується вивчитиМетод

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(matreshkaArray.toJSON());
this.mediateItem(item => {
	if(item.something) {
		return new FirstModel(item);
	} else {
		return new SecondModel(item);
	}
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#METHOD

НайважливішеМетод

Matreshka.Array#METHOD()

Будь-який метод із Array.prototype

Matreshka.Array включає в себе всі методи, що входять в нативний JavaScript масив:

При цьому, вони працюють точно так же, як і методи Array.prototype. Є лише кілька застережень:

  • Метод forEach повертає себе замість undefined
  • Методи, які в оригінальному вигляді повертають новий масив (splice, slice, filter, map ...), повертають новий екземпляр Matreshka.Array.
  • Методи keys, values та entries повертають масив замість ітератора.
  • fill передає замінені елементи як removed у події remove і modify, а added містить по одному елементу на кожен заповнений індекс.
  • fill і copyWithin кидають помилку на відрендереному масиві (у якого є container або sandbox).

Крім усього, методи генерують події пов'язані з будь-якою модифікацією масиву. Детальніше див. Matreshka.Array.

Посилання

Приклади

this.push(1, 2, 3);
const matreshkaArray = this
	.forEach((value, index) => {
		//...
	})
	.map((value, index) => {
		//...
	});

console.log(matreshkaArray.isMatreshkaArray); // true
this.reverse();

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#METHOD_

НайважливішеМетод

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
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#Model

НайважливішеМетодВизначається вами

Matreshka.Array#Model(data, matreshkaArray, index)

Властивість визначає клас елементів, які буде містити колекція

При кожному додаванні елементів в масив, вбудований обробник перевіряє, чи є доданий елемент екземпляром Model і конвертує його в такий, якщо перевірка не пройдена. Рекомендується наслідувати Model від класу Matreshka.Object або Matreshka.Array (на випадок, якщо потрібно отримати колекцію колекцій), щоб отримати можливість конвертації масиву в звичайний масив методом Matreshka.Array#toJSON.

Для більш гнучкого контролю класу елементів (наприклад, якщо для одних елементів потрібно використовувати одну "модель", а для інших - іншу), використовуйте Matreshka.Array#mediateItem.

Model можна оголосити як поле класу (Model = MyModel;), а не лише як геттер. Поля класу встановлюються після повернення з super(...), тому елементи, передані в super(...), конвертуються, коли масив наступного разу змінює якийсь метод; геттер get Model() конвертує їх одразу.

Якщо змінити Model пізніше, елементи, які вже є в масиві, конвертуються, а їх відрендерені вузли замінюються.

Аргументи

Ім'я Тип Опис
data object Дані, передані в конструктор
matreshkaArray 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#onItemRender

Рекомендується вивчитиМетодВизначається вами

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() {
		super().bindNode('sandbox', '.my-form');
	}
	onItemRender(item, renderEvt) {
		// ...
	}
}

const app = new MyArray();

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#orderBy

Рекомендується вивчитиМетод

Matreshka.Array#orderBy(keys, [orders=asc]) → matreshkaArray

Сортує масив за значеннями властивостей об'єктів, які в нього входять

Цей метод працює майже так само, як і метод orderBy з lodash. Він приймає ключ або масив ключів першим аргументом, порядок (asc/desc) або масив порядків - другим.

Повертає: matreshkaArray – self

Генерує події: sort

Аргументи

Ім'я За замовчуванням Тип Опис
keys string | array Ключ властивості або масив декількох ключів, за якими колекція буде відсортована
orders (необов'язковий) 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

Рекомендується вивчитиМетод

Matreshka.Array#pull(indexOrValue, [eventOptions]) → *|null

Видаляє елемент за індексом або за значенням

Повертає: * | null – Видалений елемент або null

Генерує події: pull, remove, removeone, modify

Аргументи

Ім'я Тип Опис
indexOrValue object | number Індекс елемента, який потрібно видалити або видаляємий об'єкт
eventOptions (необов'язковий) 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

НайважливішеМетод

Matreshka.Array#recreate([array], [eventOptions]) → matreshkaArray

Перестворює екземпляр Matreshka.Array

Метод дозволяє конвертувати будь-який масив (або об'єкт, подібний масиву) в екземпляр Matreshka.Array. Якщо нічого не передано в якості першого аргументу, екземпляр очищується.

Повертає: matreshkaArray – self

Генерує події: recreate, modify, add, addone, remove, removeone

Аргументи

Ім'я Тип Опис
array (необов'язковий) array Масив або масивоподібний об'єкт
eventOptions (необов'язковий) eventOptions Об'єкт події

Посилання

Приклади

// очищаємо масив і додаємо 5 нових айтемів
this.recreate([1, 2, 3, 4, 5]);

// очищаємо масив
this.recreate();

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#restore

Рекомендується вивчитиМетод

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() {
		super()
			.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 (необов'язковий) selector Селектор
eventOptions (необов'язковий) eventOptions Об'єкт події

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#toJSON

НайважливішеМетод

Matreshka.Array#toJSON([recursive=true]) → array

Конвертує екземпляр Matreshka.Array в звичайний масив

Метод працює рекурсивно, викликаючи toJSON для внутрішніх об'єктів, у яких є метод з таким ім'ям. Для скасування рекурсії передайте false першим аргументом.

Повертає: array

Аргументи

Ім'я За замовчуванням Тип Опис
recursive (необов'язковий) true boolean

Приклади

const matreshkaArray = new Matreshka.Array(1, 2, new MatreshkaArray(3, 4));

// повертає [1, 2, [3, 4]]
console.log(matreshkaArray.toJSON());

// повертає [1, 2, MatreshkaArray]
console.log(matreshkaArray.toJSON(false));

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#rerender

Інші методи і властивостіМетод

Matreshka.Array#rerender([eventOptions]) → matreshkaArray

Перемальовує DOM вузли об'єктів, що входять в масив

Цей метод заново рендерить елементи масиву в контейнері масиву. Якщо вузол, який асоційований з айтемом вже створений, метод, замість перемальовування з нуля, "перевставляє" його в контейнер масиву.

Метод може бути корисним на випадок, коли елементи додані в масив перед оголошенням контейнера.

Щоб змусити масив перемалюватися, незалежно від наявності відрендерених вузлів (наприклад, ви використовуєте кастомний шаблонізатор в itemRenderer), передайте в метод об'єкт з властивістю forceRerender рівною true.

Повертає: matreshkaArray – self

Аргументи

Ім'я Тип Опис
eventOptions (необов'язковий) eventOptions Об'єкт події

Приклади

this.rerender({
	forceRerender: true
});

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#itemRenderer

НайважливішеВластивістьВизначається вами

Matreshka.Array#itemRenderer: string|function

HTML строка, селектор або функція, яка відповідає за рендерінг элементів масива на сторінці

Властивість itemRenderer - це перевизначаєма (віртуальна) властивість, яка дозволяє рендерити айтеми масиву без додаткового коду. При вставці нового об'єкта в масив, автоматично створюється HTML елемент. Цей елемент стає пісочницею (див. Matreshka#bindNode) (цю поведінку можна скасувати, див. нижче) для вставленого об'єкта і вставляється в HTML контейнер, визначений у масиві.

Для скорочення, в прикладах до цієї статті буде використовуватися синтаксис class fields.

itemRenderer і Model працюють і як поля класу, і як геттери; нове значення поля itemRenderer перерендерює елементи. Про елементи, передані в super(...), див. Matreshka.Array#Model.

Куди вставляється створений елемент?

Для того, щоб визначити місце, в яке будуть вставлятися відмальовані HTML вузли, потрібно визначити **контейнер **. Для цього слід оголосити HTML пісочницю для масиву або зв'язати спеціальний ключ container з HTML контейнером. Детальніше про привязки і пісочницю див. Matreshka#bindNode. Приклад використання пісочниці як контейнера:

<ul class="my-list"></ul>
class MyArray extends Matreshka.Array {
	itemRenderer = '<li>';
	get Model() { return 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>';
	get Model() { return 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 {
	get Model() { return 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 {
	get Model() { return 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() {
		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 {
	get Model() { return 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>

І зв'яже чекбокси з відповідними властивостями 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 {
	get Model() { return MyModel; }
	itemRenderer = '...';
	constructor() {
		super();
		//...
	}
	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;
	// ...
}
Переміщення об'єкта з одного масиву в інший

За замовчуванням, при вставці об'єкта в масив Matreshka.js спробує його змалювати, використовуючи 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' });

Аргументи

Ім'я Тип Опис
item object об'єкт, який буде рендериться (на випадок необхідності визначення умов для рендеринга різних елементів в різних випадках)

Посилання

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array#trackBy

Рекомендується вивчитиВластивістьВизначається вами

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() {
		super();
		//...
	}
}

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() {
		super();
		//...
	}
}

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#renderIfPossible

Інші методи і властивостіВластивість

Matreshka.Array#renderIfPossible: boolean

Властивість renderIfPossible скасовує рендеринг масиву якщо має значення false

Посилання

Приклади

class MyArray extends Matreshka.Array {
    get renderIfPossible() {
        return false;
    }
    // ...
}

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Array.from

Рекомендується вивчитиМетод

Matreshka.Array.from(arrayLike, [mapFn], [thisArg]) → matreshkaArray

Метод створює новий екземпляр Matreshka.Array з масивоподібного або ітеруємого об'єкта

Повертає: matreshkaArray

Аргументи

Ім'я Тип Опис
arrayLike object Массивоподібний або ітеруємий об'єкт
mapFn (необов'язковий) function Відображаюча функція, що викликається для кожного елемента масиву
thisArg (необов'язковий) * Об'єкт, який використовується в якості this при виклику mapFn

Посилання

Приклади

const matreshkaArray = Matreshka.Array.from([1, 2, 3, 4]);
const matreshkaArray = 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

Рекомендується вивчитиМетод

Matreshka.Array.of() → matreshkaArray

Метод створює новий екземпляр Matreshka.Array з довільного числа агрумент, незалежно від числа або типу аргументів

Повертає: matreshkaArray

Посилання

Приклади

const matreshkaArray = 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

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders

НайважливішеПростір імен

Імпорт:

import { binders } from 'matreshka';

Простір імен для байндерів. З коробки містить байндери загального призначення (для зв'язування атрибутів і ін.). Цей об'єкт можна розширювати власними властивостями, щоб не засмічувати глобальний простір імен.

Візьміть до уваги невелику угоду: кожна властивість з неймспейсу Matreshka.binders має бути оформлено у вигляді функції (такі функції іноді називають "binder creator"), що повертає байндер-об'єкт.

У цій документації властивості з Matreshka.binders використовуються безпосередньо, але для поліпшення читабельності коду, рекомендується виносити їх в окремі змінні.

const html = Matreshka.binders.html;

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

Або імпортувати в якості CJS модуля:

// імпорт відразу декількох байндерів
import { binders } from 'matreshka';

const { html, text, prop } = binders;

Біндери входять до пакета matreshka.

Посилання

Приклади

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

this.bindNode('myKey', '.my-element',
	Matreshka.binders.myCoolBinder('Hello', 'World'));

Байндери

  • attr – Повертає байндер, який змінює атрибут DOM елемента на значення властивості об'єкту
  • className – Повертає байндер, який перемикає ім'я класу DOM елемента в залежності від значення властивості об'єкта. Якщо значення властивості нестрого дорівнює true, ім'я класу додається, в іншому випадку - забирається. Логіку можна змінити, передавши false другим аргументом, і, таким чином, ім'я класу буде додаватися, коли значення властивості нестрого дорівнює false і навпаки.
  • dataset – Повертає байндер, який змінює властивість dataset DOM элемента в залежності від значення властивості об'єкта.
  • display – Повертає байндер для одностороннього зв'язування, який змінює видимість DOM елементу (використовуючи style.display), в залежності від значення властивості об'єкта
  • existence – Повертає байндер для одностороннього зв'язування, що перемикає наявність елемента в DOM дереві, в залежності від значення властивості об'єкта
  • html – Повертає байндер, який змінює innerHTML DOM елемента в залежності від значення властивості об'єкта
  • input – Повертає байндер, що зв'язує властивість об'єкта з елементом input. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.
  • output – Повертає байндер, що зв'язує властивість об'єкта з елементом output. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.
  • progress – Повертає байндер, що зв'язує властивість об'єкта з елементом progress. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.
  • prop – Повертає байндер, який змінює властивість DOM елемента на значення властивості об'єкта
  • select – Повертає байндер, що зв'язує властивість об'єкта з елементом select. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.
  • style – Повертає байндер, який змінює задану властивість стилю DOM елемента в залежності від значення властивості об'єкта
  • text – Повертає байндер, який змінює textContent (текстовий вміст) DOM елемента в залежності від значення властивості об'єкта.
  • textarea – Повертає байндер, що зв'язує властивість об'єкта з елементом textarea. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.attr

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { attr } = binders;
Matreshka.binders.attr(attribute, [mappingFn]) → binder

Повертає байндер, який змінює атрибут DOM елемента на значення властивості об'єкту

Значення властивості можна перетворити за допомогою переданої функції mappingFn.

undefined і null встановлюють порожній атрибут; атрибут не видаляється.

Повертає: binder

Аргументи

Ім'я Тип Опис
attribute string Ім'я атрибута
mappingFn (необов'язковий) function Відображаюча функція

Приклади

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

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

Використання mappingFn

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

this.myKey = 'World'; // атрибут foo має значення "Hello, World"

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.className

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { className } = binders;
Matreshka.binders.className(className, [bool=true]) → binder

Повертає байндер, який перемикає ім'я класу DOM елемента в залежності від значення властивості об'єкта. Якщо значення властивості нестрого дорівнює true, ім'я класу додається, в іншому випадку - забирається. Логіку можна змінити, передавши false другим аргументом, і, таким чином, ім'я класу буде додаватися, коли значення властивості нестрого дорівнює false і навпаки.

Повертає: binder

Аргументи

Ім'я За замовчуванням Тип Опис
className string
bool (необов'язковий) 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

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { dataset } = binders;
Matreshka.binders.dataset(property, [mappingFn]) → binder

Повертає байндер, який змінює властивість dataset DOM элемента в залежності від значення властивості об'єкта.

Значення властивості можна перетворити за допомогою переданої функції mappingFn.

undefined і null показуються як порожній рядок.

Повертає: binder

Аргументи

Ім'я Тип Опис
property string Властивість dataset
mappingFn (необов'язковий) function Відображаюча функція

Приклади

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

Використання mappingFn

this.bindNode('myKey', '.my-element',
    Matreshka.binders.dataset('myProp', value => `Hello, ${value}`));

this.myKey = 'foo'; // атрибут data-my-prop має значення "Hello, foo"

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.display

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { display } = binders;
Matreshka.binders.display([bool=true]) → binder

Повертає байндер для одностороннього зв'язування, який змінює видимість DOM елементу (використовуючи style.display), в залежності від значення властивості об'єкта

Повертає: binder

Аргументи

Ім'я За замовчуванням Тип Опис
bool (необов'язковий) 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

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { existence } = binders;
Matreshka.binders.existence([bool=true]) → binder

Повертає байндер для одностороннього зв'язування, що перемикає наявність елемента в DOM дереві, в залежності від значення властивості об'єкта

Байндер працює так само, як і Matreshka.binders.display, але замість зміни видимості елемента, змінюється наявність елемента на сторінці. Байндер може бути корисним:

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

Повертає: binder

Аргументи

Ім'я За замовчуванням Тип Опис
bool (необов'язковий) 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

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { html } = binders;
Matreshka.binders.html([mappingFn]) → binder

Повертає байндер, який змінює innerHTML DOM елемента в залежності від значення властивості об'єкта

Значення властивості можна перетворити за допомогою переданої функції mappingFn.

undefined і null показуються як порожній рядок.

Повертає: binder

Аргументи

Ім'я Тип Опис
mappingFn (необов'язковий) function Відображаюча функція

Приклади

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

Використання mappingFn

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

// встановить innerHTML элемента як "Hello, <div>foo</div>"
this.myKey = '<div>foo</div>';

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.prop

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { prop } = binders;
Matreshka.binders.prop(property, [mappingFn]) → binder

Повертає байндер, який змінює властивість DOM елемента на значення властивості об'єкта

Значення властивості можна перетворити за допомогою переданої функції mappingFn.

Повертає: binder

Аргументи

Ім'я Тип Опис
property string Ім'я властивості
mappingFn (необов'язковий) function Відображаюча функція

Приклади

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

// встановлює властивість disabled = true для елемента
this.disabled = true;

// встановлює властивість disabled = false для елемента
this.disabled = false;

Використання mappingFn

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

this.myProp = 'World'; // властивість елемента foo має значення "Hello, World"

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.style

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { style } = binders;
Matreshka.binders.style(property, [mappingFn]) → binder

Повертає байндер, який змінює задану властивість стилю DOM елемента в залежності від значення властивості об'єкта

Значення властивості можна перетворити за допомогою переданої функції mappingFn.

Повертає: binder

Аргументи

Ім'я Тип Опис
property string Властивість style (camel-cased)
mappingFn (необов'язковий) function Відображаюча функція

Приклади

this.bindNode('myKey', '.my-node',
    Matreshka.binders.style('backgroundColor'));
this.myKey = 'red'; // колір фону .my-node став червоним

Використання mappingFn

this.bindNode('myKey', '.my-element',
  Matreshka.binders.style('backgroundImage', value => `url("${value}")`));

this.myKey = 'cats.jpg'; // backgroundImage дорівнює "url("cats.jpg")"

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.text

Рекомендується вивчитиМетод

Імпорт:

import { binders } from 'matreshka';

const { text } = binders;
Matreshka.binders.text([mappingFn]) → binder

Повертає байндер, який змінює textContent (текстовий вміст) DOM елемента в залежності від значення властивості об'єкта.

Matreshka.binders.text дозволяє вивести вміст властивості як є. Значення властивості можна перетворити за допомогою переданої функції mappingFn.

undefined і null показуються як порожній рядок.

Повертає: binder

Аргументи

Ім'я Тип Опис
mappingFn (необов'язковий) function Відображаюча функція

Приклади

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

Використання mappingFn

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

this.myKey = 'foo'; // встановить textContent элемента як "Hello, foo"

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.input

Інші методи і властивостіМетод

Імпорт:

import { binders } from 'matreshka';

const { input } = binders;
Matreshka.binders.input([type]) → binder

Повертає байндер, що зв'язує властивість об'єкта з елементом input. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.

Для текстових полів undefined і null показуються як порожній рядок. Для radio: позначений перемикач встановлює властивості своє value; знятий перемикач властивість не змінює.

Повертає: binder

Аргументи

Ім'я Тип Опис
type (необов'язковий) string Тип інпута

Приклади

this.bindNode('myKey', '.my-input', Matreshka.binders.input('range'));

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.output

Інші методи і властивостіМетод

Імпорт:

import { binders } from 'matreshka';

const { output } = binders;
Matreshka.binders.output() → binder

Повертає байндер, що зв'язує властивість об'єкта з елементом output. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.

undefined і null показуються як порожній рядок.

Повертає: binder

Приклади

this.bindNode('myKey', '.my-output', Matreshka.binders.output());

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.progress

Інші методи і властивостіМетод

Імпорт:

import { binders } from 'matreshka';

const { progress } = binders;
Matreshka.binders.progress() → binder

Повертає байндер, що зв'язує властивість об'єкта з елементом progress. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.

Повертає: binder

Приклади

this.bindNode('myKey', '.my-progress', Matreshka.binders.progress());

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.select

Інші методи і властивостіМетод

Імпорт:

import { binders } from 'matreshka';

const { select } = binders;
Matreshka.binders.select([multiple=false]) → binder

Повертає байндер, що зв'язує властивість об'єкта з елементом select. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.

undefined і null вибирають опцію без значення, якщо вона є. Якщо multiple дорівнює true, властивість може бути масивом значень, одним значенням або null (нічого не вибрано); значення порівнюються як рядки, тому числа теж працюють.

Повертає: binder

Аргументи

Ім'я За замовчуванням Тип Опис
multiple (необов'язковий) false boolean Чи є селект multiple

Приклади

this.bindNode('myKey', '.my-select', Matreshka.binders.select(true));

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.binders.textarea

Інші методи і властивостіМетод

Імпорт:

import { binders } from 'matreshka';

const { textarea } = binders;
Matreshka.binders.textarea() → binder

Повертає байндер, що зв'язує властивість об'єкта з елементом textarea. Безпосередньо байндер використовувати не обов'язково, так як він входить в список Matreshka.defaultBinders.

Повертає: binder

Приклади

this.bindNode('myKey', '.my-textarea', Matreshka.binders.textarea());

Знайшли помилку в статті? Надішліть патч з виправленням.

Matreshka.Router

Інші методи і властивостіКлас

Імпорт:

import { Router } from 'matreshka/router';

Matreshka.initRouter побудований на класі Matreshka.Router. Він приймає єдиний аргумент - тип роутера ("hash", "history" або довільний рядок).

За замовчуванням бібліотека створює два екземпляри Matreshka.Router з типами hash і history. Вони знаходяться в Matreshka.Router.hash і Matreshka.Router.history. Роутер ініціалізується ліниво, тому, якщо просто підключити скрипт до сторінки, бібліотека нічого не робить.

Для цих двох екземплярів використовується патерн «одинак». Це означає, що при спробі створити ще один екземпляр типу hash через new Matreshka.Router('hash') замість нового екземпляра повернеться Matreshka.Router.hash. Так уся робота з URL зібрана в одному місці, це добре для продуктивності і виключає колізії. Об'єкти, передані в initRouter, просто підписуються на зміни роутера потрібного типу.

Власні екземпляри (не hash і не history) Matreshka.Router можна створити вручну, якщо потрібно згенерувати URL для подальшого використання. У цьому випадку зміни властивостей не чіпають hash і не викликають pushState.

Властивості

Екземпляри Matreshka.Router мають 3 властивості.

  • path - актуальний URL, наприклад /foo/bar/baz/.
  • hashPath - актуальний URL з префіксом hashbang, наприклад #!/foo/bar/baz/
  • parts - масив усіх частин шляху, наприклад ['foo', 'bar', 'baz'].

Усі ці властивості створені за допомогою Matreshka#calc, тобто при зміні однієї властивості інші змінюються автоматично.

Matreshka.Router.hash.path = '/foo/bar/baz/';

Змінюючи ці властивості, можна запускати потрібні процедури (оновити шлях, змінити підписані об'єкти тощо)

Методи

  • subscribe(object, route) - підписує об'єкт на зміни маршруту.
  • init() - використовується для лінивої ініціалізації в методі subscribe (викликати вручну не потрібно).

Аргументи

Ім'я Тип Опис
type string "hash", "history" або довільний рядок

Приклади

const customRouter = new Matreshka.Router('myType');
const object = {
	a: 'foo',
	b: 'bar'
};

customRouter.subscribe(object, '/a/b/');

console.log(customRouter.path); // /foo/bar/

Знайшли помилку в статті? Надішліть патч з виправленням.

binder

Рекомендується вивчитиТип

binder (байндер, прів'язчик) містить всю інформацію про те, як синхронізувати значення властивості з прив'язаним до нього DOM елементом. Для всіх методів байндера контекст (this) - відповідний DOM вузол.

Властивості

Ім'я Тип Опис
on (необов'язковий) string | function Ім'я DOM події (або список імен подій, розділених пробілами), після спрацювання якогї витягується стан DOM елемента і встановлюється властивість. Крім цього, значенням властивості може бути функція, яка встановлює обробник довільним чином.
getValue (необов'язковий) function Функція, яка відповідає за те, як витягти стан DOM елемента
setValue (необов'язковий) function Функція, яка відповідає за те, як встановити значення DOM елементу
initialize (необов'язковий) function Функція, яка запускається при ініціалізації прив'язки. Наприклад, може бути використана для ініціалізації jQuery плагіна
destroy (необов'язковий) 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;
	}
	// ...
};
// ...

Знайшли помилку в статті? Надішліть патч з виправленням.

eventHandler

Рекомендується вивчитиТип

Функція-обробник події. Приймає будь-які аргументи, передані в 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');

Знайшли помилку в статті? Надішліть патч з виправленням.

eventNames

Рекомендується вивчитиТип

Ім'я події або кілька імен, розділених пробілами.

Довільні події

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)', () => {...});

Знайшли помилку в статті? Надішліть патч з виправленням.

eventOptions

Рекомендується вивчитиТип

Об'єкт події

Це звичайний об'єкт, котрий може містити службові прапори або довільні дані, які потраплять в обробник події

Приклади

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"

Знайшли помилку в статті? Надішліть патч з виправленням.

FAQ

Як працює Matreshka.js?

Фреймворк використовує акцессори (accessors) для реалізації двостороннього зв'язування даних і вилову подій зміни властивостей.

Для того щоб зрозуміти, як працює двостороннє зв'язування (зокрема, функція Matreshka.bindNode), погляньте на цей код:

function bindNode(object, key, node, binder) {
    let 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.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 і оголошувати інші прив'язки...

Знайшли помилку в статті? Надішліть патч з виправленням.