Рілі сімпл фреймворк для створення односторінкових веб додатків
<output class="out"></output>
<input class="in" type="text">

<script src="seemple.min.js"></script>
<script>
const app = new Seemple();
app.bindNode('x', '.in, .out');
app.x = 'Рілі сімпл фреймворк для створення односторінкових веб додатків';
</script>

Завантажити Github

Приклади та статті

Спонсори

Вступ

Фічі

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

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

Seemple.js заповнює прірву між джуном та сеньором

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

Яку бізнес-задачу вирішує фреймворк?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

У кінці кожної статті документації є посилання на код цієї статті. Виправити помилку можна прямо в редакторі на Github. Якщо з яких-небудь причин не можете відправити виправлення або ви знайшли помилку там де немає такого лінку, виділіть необхідний текст з помилкою і натисніть CTRL+Enter. З'явиться вікно, що дозволяє відправити повідомлення розробнику.

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

Модулі

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

// кожну статичну властивість будь-якого об'єкта
// або функції можна імпортувати в вигляді модуля
const SeempleArray = require('seemple/array');
const propBinder = require('seemple/binders/prop');
const bindNode = require('seemple/bindnode');

Імпорт головного модуля підтягне весь фреймворк. Як правило, це не потрібно.

const Seemple = require('seemple');

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

Приклади

Hello World

Написати перший додаток за допомогою фреймворка Seemple.js дуже просто.

1. Створіть HTML файл з наступним змістом

<!DOCTYPE html>
<html>
    <head>
        <title>Мій перший додаток на базі Seemple.js</title>
    </head>
    <body>
        <input type="text" class="my-input">
        <div class="my-output"></div>

        <script
          src="https://finom.github.io/seemple/seemple.min.js">
        </script>

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

2. Створіть клас у файлі js/app.js

// присвоюємо html байндер змінній з коротким ім'ям
const htmlBinder = Seemple.binders.html;

// створюємо клас, який успадковується від Seemple
class Application extends Seemple {
    constructor() {
        super();

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

        // пов'язуємо властивість x і блок з класом my-output
        this.bindNode('x', '.my-output', htmlBinder());

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

const app = new Application();

3. Це все!

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

app.x = 'Hello World!';

Посилання

Інші приклади

1. TodoMVC - список справ. (Код з анотаціями)

2. TreeView - деревовидний список необмеженої вкладеності.

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

4. Simple SoundCloud player - пошук музики, що використовує SoundCloud API.

5. Contact List - дозволяє додавати, видаляти, сортувати, змінювати і шукати контакти.

Клас Seemple

Шлях до модуля CommonJS: 'seemple/seemple'

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

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

Посилання

Приклади

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

const seemple = new Seemple();

Спадкування

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

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

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

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

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

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

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

const bindNode = require('seemple/bindnode');
const object = {};
bindNode(object, key, node, binder, eventOptions);
// замість this.bindNode(key, node, binder, eventOptions);

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

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

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

Наприклад, ви хочете зв'язати властивість об'єкта з елементом input[type="checkbox"]:

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

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

// Встановлює checked = true
this.myKey = true;

Більш складний приклад: зв'язування властивості об'єкта з віджетом jQuery UI

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

Виглядає просто, але у вас, швидше за все, винекне питанням: "Як зробити так, щоб мені не довелося кожен раз прописувати ці правила?". Дійсно, на сторінці може бути дуже багато однотипних елементів: текстових полів, полів з специфікації HTML5, можуть бути і сторонні віджети (про що говорить приклад вище).

Як видно з документації до аргументів методу bindNode, третій аргумент не обов'язковий. Цю проблему вирішує масив Seemple.defaultBinders, який містить функції, що перевіряють HTML елемент на відповідність заданим правилам і повертають відповідний Байндер або undefined. З'являється можливість багаторазово скоротити код, виносячи правила прив'язки в окрему частину вашого коду, а для прив'язки використовувати синтаксис без третього аргументу:

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

Як це зробити? Потрібно додати функцію, яка перевіряє ваш елемент на відповідність деяким правилам в початок масиву Seemple.defaultBinders.

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

// Метод unshift додає функцію
// у початок масиву Seemple.defaultBinders
Seemple.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;

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

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

Seemple.defaultBinders з коробки містить підтримку всіх без винятку HTML елементів форм: select (включаючи multiple), textarea, output, input (в тому числі і всі типи із специфікації HTML5: text, checkbox, radio, range, number, date, search, time, datetime, datetime-local, color та інших). Це означає, що для стандартних елементів вказувати Байндер не обов'язково.

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

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

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

// Знайде елемент .my-inner-element який є в '.my-element'
this.bindNode('myAnotherKey', ':bound(myKey) .my-inner-element');

І розширюється синтаксис можливих імен подій:

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

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

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

Якщо елемент не знайдений, кидається виняток "Bound element is missing". Для того, щоб уникнути помилки використовуйте метод Seemple#bindOptionalNode

Створення пісочниці

Seemple#bindNode вміє асоціювати екземпляр класу з "головним" HTML елементом, створюючи так звану пісочницю. Це потрібно для того, щоб обмежити вплив об'єкта одним HTML елементом. Для прив'язки пісочниці використовується спеціальна властивість sandbox.

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

Визначення пісочниці додає безліч зручностей програмісту. наприклад:

  • Дозволяє використовувати методи Seemple#select і Seemple#$
  • Додає можливість використовувати селектор :sandbox в методах Seemple#bindNode, Seemple#select, Seemple#$
  • Додає синтаксичний цукор для делегованих DOM подій в методі Seemple#on

Слід мати на увазі, що тільки один HTML елемент може бути пов'язаний з властивістю sandbox, інакше кидається помилка. Для оголошення пісочниці можна скористатися методом Seemple#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 передати строку, що містить точку, то така строка буде інтерпрітірована як шлях до властивості у вкладеному об'єкті. Seemple.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 передати конкретний байндер, фреймворк спробує відшукати байндер у Seemple.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

Аргументи

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

Ім'я властивості

node string node $nodes

HTML елемент, який повинен бути пов'язаний з властивістю об'єкта

binder optional binder

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

eventOptions optional eventOptions

Об'єкт події, в який можна передати ключ "silent" (щоб не генерувати події "bind" і "bind:KEY"), прапори, описані вище або кастомні дані

Посилання

Seemple#bindNode(bindings, binder, eventOptions) object

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

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

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

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

Повертає object - self

Аргументи

Iм'я Тип Опис
bindings object

(див. приклад)

binder optional binder

(див. вище)

eventOptions optional eventOptions

(див. вище)

Приклади

this.bindNode({
	foo: '.custom-checkbox',
	'bar.length': 'textarea'
});
this.bindNode({
	foo: {
		node: ':sandbox .aaa',
		binder: Seemple.binders.html()
	},
	bar: '.bbb',
	baz: [{
		node: '.ccc'
	}, {
		node: document.querySelector('.ddd'),
		binder: Seemple.binders.prop('baz')
	}]
}, {
	// will be used as a binder for .bbb and .ccc
	setValue(value) {
		foo(value);
	}
});

Seemple#bindNode(batch, commonEventOptions) object

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

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

  • key - ім'я властивості
  • node - елемент, для якого оголошуємо зв'язування з key
  • binder - байндер (не обов'язково)
  • event - об'єкт події (не обов'язково)

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

Повертає object - self

Аргументи

Iм'я Тип Опис
batch array

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

commonEventOptions optional eventOptions

Загальні для всіх об'єктів властивості події

Приклади

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

Seemple#bindSandbox(node, eventOptions)

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

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

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

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

Аргументи

Iм'я Тип Опис
node string node $nodes

Елемент, який повинен стати пісочницею

eventOptions optional eventOptions

Об'єкт події

Посилання

Приклади

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

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

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

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

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

const calc = require('seemple/calc');
const object = {};
calc(object, target, source, handler, eventOptions);
// Замість this.calc(target, source, handler, eventOptions);

Аргумент source має кілька варіацій.

Строка

Властивість target буде залежати від властивості source.

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

Масив строк

Властивість target буде залежати від властивостей, перерахованих в source.

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

Об'єкт з властивостями object і key

В цьому випадку можна оголосити залежність властивості target від іншого об'єкта.

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

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

Значенням властивості key можна передати масив ключів.

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

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

Масив об'єктів з властивостями object і key

Так можна оголосити залежність властивості від властивостей різних об'єктів.

const someObjectX = {
    b: 1,
    c: 2
};
const someObjectY = {
    d: 3
};

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

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

Масив, що комбінує строки (власні властивості) і об'єкти

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

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

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

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

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

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

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

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

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

Точка в імені властивості-джерела

Якщо ім'я ключа містить точку, метод ініціює залежність від властивості у вкладеному об'єкті.

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

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

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

Те ж саме стосується і зовнішніх об'єктів

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

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

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

Метод захищений від циклічних залежностей (наприклад a залежить від b, b залежить від c, а c залежить від a) і при помилці обчислень не блокує сторінку і не кидає виняток про переповнення стека.

Як ви могли помітити, аргументи функції handler завжди розташовані в тому ж порядку, що і властивості з source.

У разі, якщо потрібно змінити значення властивості-джерела і зробити це так, щоб цільова властивість не була обчислена заново, використовуйте метод Seemple#set з прапором skipCalc рівним true.

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

Важливі особливості роботи методу і спеціальні прапори

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

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

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

Прапор debounceCalc=true

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

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

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

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

this.b = 10;
this.c = 20;
this.d = 30;
console.log(this.a); // 6 замість 60

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

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

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

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

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

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

Прапор debounceCalcOnInit=false

Як говорилося вище, при виклику методу calc цільова властивість обчислюється відразу, а при зміні властивостей-джерел - ні. Увімкнути debounce і при першому обчисленні властивості можна передавши в якості властивості об'єкта події прапор debounceCalcOnInit=true.

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

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

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

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

На практиці debounceCalcOnInit навряд чи стане в нагоді. Потрібно лише пам'ятати, що є прапор який включає "повний debounce".

Прапор debounceCalcDelay=0

Прапор дозволяє вказати затримку debounce при використанні debounceCalc і debounceCalcOnInit.

Прапор setOnInit=true

Відомо, що при виклику методу calc властивість відразу отримує нове значення. Для того, щоб скасувати цю поведінку і обчислити властивість target тільки тоді, коли властивість-джерело вперше змінено, використовуйте прапор setOnInit рівний false.

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

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

// Але якщо оновити this.b, для властивості a буде обчислено нове значення
this.b = 1;

Прапор exactKey=false

Як говорилося вище, в якості імені властивості-джерела можна передати строку, що містить точки. Таке ім'я буде витлумачено як шлях до властивості у вкладеному об'єкті. У разі, якщо ім'я має бути використано як є, скористайтеся прапором exactKey зі значенням true.

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

Прапор promiseCalc=false

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

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

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

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

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

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

Аргументи

Iм'я За замовчуванням Тип Опис
target string

Ім'я властивості яка залежить від інших властивостей

source string array

Від яких властивостей залежить шукана властивість (див. опис вище)

handler optional (v)=>v function

Функція, що повертає нове значення

eventOptions optional eventOptions

Об'єкт, в який можна передати якісь дані для обробника події, який слухає зміни target або спеціальні прапори (див. опис методу)

Приклади

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

this.name = 'World';

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

Обчислення периметра прямокутника по двох сторонах (і сторін по периметру)

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

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

alert(this.p); // 14

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

this.a = 5;

Seemple#calc(batch, commonEventOptions)

Додаткова можливість методу Seemple#calc, що дозволяє оголосити кілька обчислюваних властивостей одним викликом

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

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

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

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

Аргументи

Iм'я Тип Опис
batch array

Об'єкт містить інформацію про обчислюваних властивості

commonEventOptions optional eventOptions

Загальні властивості для об'єктів події

Приклади

this.calc({
	x: {
    	source: ['a', 'b'],
    	handler: (a, b) => a + b
	},
	y: {
	    source: {
	        object: someObject,
	        key: 'c'
	    },
	    event: {
	        setOnInit: false
	    }
	},
	z: {
	    source: [{
	        object: this,
	        key: 'x'
	    }, {
	        object: someObject,
	        key: 'd'
	    }],
	    handler: (x, d) => x + d
	}
}, {
    debounceCalc: false
});

Seemple#instantiate(key, class, updateCallback) object

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

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

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

Метод є надбудовою над Seemple#mediate і перевизначає медіатор.

Екземпляр класу створюється під час запуску методу instantiate. Першим аргументом конструктора класу стає поточне значення властивості. У конструкторі класу необхідно передбачити те, що в нього потрапить або undefined (якщо властивість не містила до цього ніяких даних), або об'єкт, з яким треба щось зробити (наприклад, розширити екземпляр класу властивостями об'єкта).

На ділі це виглядає просто: ви створюєте звичайний клас, який майже завжди приймає якісь дані, які потрібно обробити (наприклад, використовувати їх в методі Seemple.Object#setData).

При спробі привласнити властивості інше значення, внутрішній механізм методу instantiate, замість присвоювання, робить наступне:

  • Якщо вказана функція updateCallback, метод запускає його з двома аргументами: поточним значенням властивості і даними, які код намагається привласнити.
  • Якщо заданий клас успадкований від Seemple.Object, екземпляр оновлюється новими даними, використовуючи метод Seemple.Object#setData з прапором replaceData=true.
  • Якщо заданий клас успадкований від Seemple.Array, екземпляр оновлюється новими даними, використовуючи метод Seemple.Array#recreate.
  • Якщо не вказана функція updateCallback і якщо класі не успадкований від Seemple.Object або Seemple.Array, екземпляр розширюється властивостями об'єкта, який код намагається привласнити.

Особливістю методу є відсутність обмежень на джерело класу. Класом може виступати будь-яка функція-конструктор. яка ініціалізується за допомогою оператора new, а не тільки спадкоємці Seemple.

Повертає object - self

Аргументи

Iм'я Тип Опис
key string array

Ім'я властивості або масив імен властивостей

class function

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

updateCallback optional function

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

Приклади

class MyClass {
    // ...
}

// ...

this.instantiate('x', MyClass);

// намагаємося привласнити властивості інше значення
this.x = { a: 42 };

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

Використання updateCallback.

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

Отримання батьківского об'єкту та імені властивості. Крім даних (перший аргумент), в конструктор створюваного класу, передається посилання на об'єкт, що викликав instantiate та ім'я створеної властивості

class MyClass extends Seemple {
	constructor(data, parent, key) {
		// parent - це екземпляр MyParentClass,
        // який створив властивість
		// key - им'я властивості ("х")
	}
}

const MyParentClass etends Seemple {
    constructor() {
        this.instantiate('x', MyClass);
    }
}

Нестандартний спосіб використання updateCallback для ігнорування будь-яких змін властивості

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

У разі, якщо ваш клас не підтримує використання оператора new, замість instantiate скористайтеся методом Seemple#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 Seemple {
	constructor(appData) {
		this.appData = appData;
		this.instantiate('appData', AppData);
	}
}

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

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

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

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

// credentials.js
class Credentials extends Seemple.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
	}]
};

Seemple#instantiate(keyClassPairs, updateCallback) object

Альтернативный синтаксис методу Seemple#instantiate, який дозволяє приймати об'єкт ключ-клас в якості аргументу

Повертає object - self

Аргументи

Iм'я Тип Опис
keyClassPairs object

Об'єкт з властивостями ключ-клас

updateCallback optional function

Функція, яка викликається при кожній спробі присвоїти нові данні властивості.

Приклади

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

Seemple#mediate(key, mediator)

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

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

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

const mediate = require('seemple/mediate');
const object = {};
mediate(object, key, mediator);
// Замість this.mediate(key, mediator);

Аргументи

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

Seemple#mediate(keyMediatorPairs)

Альтернативный синтаксис методу Seemple#mediate, приймаючий в якості аргументу об'єкт "ключ-медіатор"

Аргументи

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

Seemple#off(names, callback, context) seemple

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

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

Повертає seemple - self

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

Аргументи

Iм'я Тип Опис
names optional eventNames

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

callback optional eventHandler

Функція-обробник

context optional object

Контекст

Посилання

Приклади

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

Видалення всіх подій

this.off();

Видалення події з певним обробником

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

Видалення події з певним контекстом

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

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

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

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

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

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

Повертає object - self

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

Аргументи

Iм'я Тип Опис
names eventNames

Ім'я події або кілька імен, розділених пробілом (наприклад, "change:x ajaxcomplete change:y")

callback eventHandler

Функція, яка викликається за подією

triggerOnInit optional boolean

Якщо аргумент triggerOnInit дорівнює true, то обробник буде викликаний негайно після ініціалізації.

context optional object

Контекст обробника. Іншими словами, this при виклику callback

Посилання

Приклади

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

this.trigger('foo');

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

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

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

Виклик обробника відразу після ініціалізації

// Виводить на екран "bar" моментально і чекає на подію "foo"
this.on('foo', () => {
	alert('bar');
}, true);

Seemple#on(evtnameHandlerObject, triggerOnInit, context) object

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

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

Повертає object - self

Аргументи

Iм'я Тип Опис
evtnameHandlerObject object

Об'єкт з подіями

triggerOnInit optional boolean

Якщо аргумент triggerOnInit дорівнює true, то обробники будуть викликані негайно після ініціалізації

context optional object

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

Приклади

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

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

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

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

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

Повертає object - self

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

Аргументи

Iм'я Тип Опис
names eventNames

Ім'я події або кілька імен, розділених пробілом (наприклад, "change:x ajaxcomplete change:y" )

callback eventHandler

Функція, яка викликається за подією

debounceDelay optional number

Затримка

triggerOnInit optional boolean

Якщо аргумент triggerOnInit дорівнює true, то обробник буде викликаний негайно після ініціалізації

context optional object

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

Посилання

Приклади

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

this.x = 1;

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

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

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

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

Повертає object - self

Аргументи

Iм'я Тип Опис
evtnameHandlerObject object

Об'єкт з обробниками подій

debounceDelay optional number

Затримка

triggerOnInit optional boolean

Якщо аргумент triggerOnInit дорівнює true, то обробники будуть викликаний негайно після ініціалізації

context optional object

Контекст обробників

Посилання

Приклади

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

Seemple#once(names, callback, context) object

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

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

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

Повертає object - self

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

Аргументи

Iм'я Тип Опис
names eventNames

Ім'я події або кілька імен, розділених пробілом (наприклад, "change:x ajaxcomplete change:y" )

callback eventHandler

Функція, яка викликається за подією

context optional object

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

Посилання

Приклади

this.x = 1;

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

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

this.x = 3; // нічого не робить

Seemple#once(evtnameHandlerObject, context) object

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

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

Повертає object - self

Аргументи

Iм'я Тип Опис
evtnameHandlerObject object

Об'єкт з подіями

context optional object

Контекст обробників

Посилання

Приклади

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

Seemple#parseBindings(node, eventOptions) $nodes

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

Починаючи з версії 1.1, Seemple.js включає в себе простий DOM парсер, що обробляє синтаксичні конструкції, укладені в подвійні фігурні дужки. Метод parseBindings першим аргументом приймає HTML строку, DOM вузол або селектор, відповідний DOM вузлу.

Так як метод є DOM шаблонізатором (а не строковим HTML шаблонізатором), всі дочірні DOM вузли переданого елемента залишаються в своєму колишньому стані (наприклад, DOM події не затираються).

Підтримуваний синтаксис.

  1. HTML прив'язка ```html <!-- Створить текстовий вузол на місці {{user.name}} і зв'яже властивість name з об'єкта user з цим вузлом JS: this.user = {name: 'Joe'}

--> Hello, {{user.name}}


2. Прив'язка елементів форм.
```html
<!--
Зв'яже властивість "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. Прив'язка атрибутів. ```html <!-- Значення атрибута href буде залежати від значень властивостей "category" і "someObject.page" (одностороння прив'язка) JS: this.category = 'seemple'; this.someObject = { page: 42 };

--> A link

```

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

Навіщо потрібен такий метод?

У разі, якщо ви розробляєте велику форму зі стандартними HTML5 полями, метод допоможе зберегти час на оголошення численних прив'язок. Крім цього, parseBindings корисний у разі створення дуже простих колекцій, які не потребують реалізації складної моделі.

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

Аргументи

Iм'я Тип Опис
node string node $nodes

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

eventOptions optional eventOptions

Об'єкт події, який буде переданий у всі внутрішні виклики методу Seemple#bindNode

Приклади

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

this.parseBindings(node);

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

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

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

const $node = this.parseBindings('<h3>Hello, {{name}}</h3>');
this.name = 'Arthur Philip Dent';

Seemple#remove(key, eventOptions) seemple

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

Повертає seemple - self

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

Аргументи

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

Им'я властивості або масив имен властивостей, які треба видалити

eventOptions optional eventOptions

Об'ект події

Приклади

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

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

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

Seemple#select(selector) node null

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

Метод дуже схожий на Seemple#selectAll, але повертає лише один елемент або null

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

Повертає node null

Аргументи

Iм'я Тип Опис
selector string

Селектор

Приклади

this.bindNode('sandbox', '.app');
this.select('.my-element');
// те ж саме, що і
this.nodes.sandbox.querySelector('.my-element');
// те ж саме, що і
$('.app').find('.my-element')[0];

Seemple#selectAll(selector) $nodes

Синонім: Seemple#$

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

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

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

Повертає $nodes

Аргументи

Iм'я Тип Опис
selector string

Cелектор

Приклади

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

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

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

Seemple#set(key, value, eventOptions)

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

Список підтримуваних прапорів:

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

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

Генерує події change change:KEY beforechange beforechange:KEY

Аргументи

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

Ключ

value *

Значення

eventOptions optional eventOptions

Об'єкт події

Приклади

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

// Те ж саме, що і this['myKey'] = 3
// або this.myKey = 3
// виводить на екран 3
this.set('myKey', 3);

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

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

// alert не спрацює
this.set('myKey', 4, {
	silent: true
});

Передача даних в обробник

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

// Виводить на екран 42
this.set('myKey', 4, {
	myCustomFlag: 42
});

Seemple#set(keyValuePairs, eventOptions)

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

Аргументи

Iм'я Тип Опис
keyValuePairs object

Об'єкт, що містить пари ключ-значення

eventOptions optional eventOptions

Об'єкт події

Приклади

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

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

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

Seemple#trigger(names, arg) object

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

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

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

Повертає object - self

Аргументи

Iм'я Тип Опис
names optional eventNames

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

arg optional *

Аргументи, які будуть передані обробникам

Посилання

Приклади

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

Seemple#unbindNode(key, node, eventOptions) seemple

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

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

Повертає seemple - self

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

Аргументи

Iм'я Тип Опис
key string null

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

node optional string node $nodes

HTML елемент, з яким властивість більше не хоче мати справи

eventOptions optional eventOptions

Об'єкт події, в який можна передати якісь дані для обробника або ключ "silent", який відключає генерацію подій "unbind" і "unbind:KEY"

Приклади

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

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

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

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

Seemple#unbindNode(bindings, eventOptions) seemple

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

Повертає seemple - self

Аргументи

Iм'я Тип Опис
bindings object

(див. приклад)

eventOptions optional eventOptions

(див. вище)

Приклади

this.unbindNode({
	foo: '.aaa'
	bar: {
		node: '.bbb'
	},
	baz: [{
		node: '.ccc'
	}, {
		node: '.ddd'
	}]
});

Seemple#unbindNode(batch, eventOptions)

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

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

  • key - ім'я властивості
  • node - елемент, для якого був об'явлений байндінг з key (не обов'язково)

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

Аргументи

Iм'я Тип Опис
batch array

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

eventOptions optional eventOptions

(див. вище)

Приклади

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

this.bindNode(temporaryBindings);

// більше не потрібні ці прив'язки
this.unbindNode(temporaryBindings);

Seemple#$nodes: $nodes

Об'єкт містить колекції (jQuery, Zepto, інстанси вбудованої мікро-бібліотеки, успадкованої від Array.prototype) прив'язаних елементів для швидкого доступу.

Посилання

Приклади

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

Seemple#isSeemple: boolean

isSeemple завжди дорівнює true для экземплярів Seemple

Приклади

alert(object.isSeemple);

Seemple#nodes: node

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

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

Посилання

Приклади

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

Seemple.Class(prototype, statics) class

Шлях до модуля CommonJS: 'seemple/class'

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

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

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

Аргументи

Iм'я Тип Опис
prototype object

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

statics optional object

Статичні методи та властивості

Приклади

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

const B = Seemple.Class({
	// B успадковується від A
	extends: A,
	method2() { ... }
});

const C = Seemple.Class({
	// С успадковується від B
	extends: B,
	method2() {
		// виклик батьківського методу
		B.prototype.method2.apply(this, arguments);
	},
	method3(a, b) { ... }
});

const D = Seemple.Class({
	// D успадковується від C
	extends: C,
	method3(a, b) {
		// виклик батьківського методу
		C.prototype.method2.call(this, arguments);
	}
});

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

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

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

Seemple.bindNode() object

Шлях до модуля CommonJS: 'seemple/bindnode'

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

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

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

Посилання

Приклади

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

Seemple.bindOptionalNode() object

Шлях до модуля CommonJS: 'seemple/bindoptionalnode'

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

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

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

Посилання

Приклади

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

Seemple.bindSandbox() object

Шлях до модуля CommonJS: 'seemple/bindsandbox'

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

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

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

Посилання

Приклади

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

Seemple.calc() object

Шлях до модуля CommonJS: 'seemple/calc'

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

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

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

Посилання

Приклади

const object = {};
object.a = 40;
object.b = 2;
Seemple.calc(object, 'sum', ['a', 'b'], (a, b) => a + b);
alert(object.sum); // 42

Seemple.chain(object) object

Шлях до модуля CommonJS: 'seemple/chain'

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

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

Універсальні методи - це такі методи, які одночасно є в прототипі Seemple і мають статичний аналог (наприклад, Seemple#bindNode і Seemple.bindNode).

Повертає object - Екземпляр недоступного ззовні класу

Аргументи

Iм'я Тип Опис
object object function

Об'єкт

Приклади

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

// те ж саме, що і
// Seemple.calc(object, 'a', 'b', b => b * 2)
// Seemple.set(object, 'b', 3)
// Seemple.bindNode(object, 'c', '.node');

Seemple.instantiate() object

Шлях до модуля CommonJS: 'seemple/instantiate'

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

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

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

Посилання

Приклади

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

Seemple.lookForBinder(node) binder

Шлях до модуля CommonJS: 'seemple/lookforbinder'

Повертає байндер, відповідний елементу. Якщо байндер не знайдений, повертає undefined. Функція перебирає Seemple.defaultBinders для пошуку байндера.

Повертає binder - binder

Аргументи

Iм'я Тип
node node

Посилання

Приклади

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

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

// поверне приблизно такий об'єкт
{
	on: 'input',
	getValue() {
		return this.value;
	},
	setValue(v) {
		this.value = v;
	}
}

Seemple.mediate() object

Шлях до модуля CommonJS: 'seemple/mediate'

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

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

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

Посилання

Приклади

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

Seemple.off() object

Шлях до модуля CommonJS: 'seemple/off'

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

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

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

Посилання

Приклади

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

Seemple.off(object, 'foo');

Seemple.on() object

Шлях до модуля CommonJS: 'seemple/on'

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

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

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

Посилання

Приклади

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

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

Seemple.onDebounce() object

Шлях до модуля CommonJS: 'seemple/ondebounce'

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

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

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

Посилання

Приклади

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

Seemple.once() object

Шлях до модуля CommonJS: 'seemple/once'

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

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

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

Посилання

Приклади

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

Seemple.parseBindings() $nodes

Шлях до модуля CommonJS: 'seemple/parsebindings'

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

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

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

Посилання

Приклади

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

Seemple.remove() object

Шлях до модуля CommonJS: 'seemple/remove'

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

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

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

Посилання

Приклади

Seemple.remove(object, 'x');

Seemple.select() node null

Шлях до модуля CommonJS: 'seemple/select'

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

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

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

Посилання

Приклади

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

Seemple.selectAll() $nodes

Шлях до модуля CommonJS: 'seemple/selectall'

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

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

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

Посилання

Приклади

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

Seemple.set() object

Шлях до модуля CommonJS: 'seemple/set'

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

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

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

Посилання

Приклади

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

Seemple.toSeemple() seemple

Шлях до модуля CommonJS: 'seemple/toseemple'

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

Повертає seemple - новостворений екземпляр Seemple

Приклади

const seemple = Seemple.toSeemple({
	a: 1,
	b: {
		c: 2
	},
	d: [{e: 1}, {e: 2}, {e: 3}]
});

Seemple.trigger() object

Шлях до модуля CommonJS: 'seemple/trigger'

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

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

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

Посилання

Приклади

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

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

Seemple.unbindNode() object

Шлях до модуля CommonJS: 'seemple/unbindnode'

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

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

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

Посилання

Приклади

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

Seemple.useDOMLibrary($)

Шлях до модуля CommonJS: 'seemple/usedomlibrary'

Змушує використовувати певну бібліотеку для роботи з DOM

За замовчуванням, Seemple.js використовує в якості бібліотеки ту, яка знаходиться за посиланням window.$. Якщо такої змінної немає в глобальному просторі імен, або ж вона не включає в себе необхідний набір методів, то використовується вбудована мікро бібліотека.

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

Аргументи

Iм'я Тип Опис
$ function

Будь-яка бібліотека (jQuery, Zepto, null для використання вбудованої мікро-бібліотеки)

Приклади

Seemple.useDOMLibrary(jQuery.noConflict());

Seemple.defaultBinders: array

Шлях до модуля CommonJS: 'seemple/defaultbinders'

Масив функцій, які повертають відповідний Байндер або undefined

defaultBinders - масив функцій, які по черзі перевіряють елемент на відповідність заданим в цих функціях правилам і повертають байндер (див. binder). Цей масив використовується тоді, коли в метод Seemple#bindNode не був переданий третій аргумент. Детальну інформацію про байндінги дивіться в документації до Seemple#bindNode.

Посилання

Приклади

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

// ...

this.bindNode('myKey', '.foo.bar');

Seemple.parserBrackets: object

Шлях до модуля CommonJS: 'seemple/parserbrackets'

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

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

Приклади

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

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

Seemple.binders object

Шлях до модуля CommonJS: 'seemple/binders'

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

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

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

const html = Seemple.binders.html;

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

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

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

// імпорт байндерів окремо
import html from 'seemple/binders/html';

Посилання

Приклади

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

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

Seemple.binders.attr(attribute, mappingFn) binder

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

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

Повертає binder

Аргументи

Iм'я Тип Опис
attribute string

Ім'я атрибута

mappingFn optional function

Відображаюча функція

Приклади

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

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

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

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

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

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

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

Повертає binder

Аргументи

Iм'я За замовчуванням Тип
className string
bool optional true boolean

Приклади

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

this.myKey = true; // додає клас 'blah'

this.myKey = false; // вбирає клас 'blah'
this.bindNode('myKey', '.my-element',
        Seemple.binders.className('blah', false));

this.myKey = false; // додає клас 'blah'

this.myKey = true; // вбирає клас 'blah'

Seemple.binders.dataset(property, mappingFn) binder

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

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

Повертає binder

Аргументи

Iм'я Тип Опис
property string

Властивість dataset

mappingFn optional function

Відображаюча функція

Приклади

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

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

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

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

Seemple.binders.display(bool=true) binder

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

Повертає binder

Аргументи

Iм'я За замовчуванням Тип Опис
bool optional true boolean

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

Приклади

this.bindNode('myKey', '.my-element', Seemple.binders.display(true));
this.bindNode('myKey', '.my-element', Seemple.binders.display(false));

Seemple.binders.existence(bool=true) binder

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

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

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

Повертає binder

Аргументи

Iм'я За замовчуванням Тип Опис
bool optional true boolean

Якщо аргумент дорівнює true, то елемент зникає при неправдивому значенні властивості, якщо дорівнює false, зникає при правдивому значенні

Приклади

this.bindNode('myKey', '.my-element', Seemple.binders.existence(true));
this.bindNode('myKey', '.my-element', Seemple.binders.existence(false));

Seemple.binders.html(mappingFn) binder

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

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

Повертає binder

Аргументи

Iм'я Тип Опис
mappingFn optional function

Відображаюча функція

Приклади

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

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

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

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

Seemple.binders.input(type) binder

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

Повертає binder

Аргументи

Iм'я Тип Опис
type optional string

Тип інпута

Приклади

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

Seemple.binders.output() binder

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

Повертає binder

Приклади

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

Seemple.binders.progress() binder

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

Повертає binder

Приклади

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

Seemple.binders.prop(property, mappingFn) binder

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

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

Повертає binder

Аргументи

Iм'я Тип Опис
property string

Ім'я властивості

mappingFn optional function

Відображаюча функція

Приклади

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

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

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

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

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

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

Seemple.binders.select(multiple) binder

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

Повертає binder

Аргументи

Iм'я Тип Опис
multiple optional boolean

Чи є селект multiple

Приклади

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

Seemple.binders.style(property, mappingFn) binder

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

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

Повертає binder

Аргументи

Iм'я Тип Опис
property string

Властивість style (camel-cased)

mappingFn optional function

Відображаюча функція

Приклади

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

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

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

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

Seemple.binders.text(mappingFn) binder

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

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

Повертає binder

Аргументи

Iм'я Тип Опис
mappingFn optional function

Відображаюча функція

Приклади

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

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

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

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

Seemple.binders.textarea() binder

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

Повертає binder

Приклади

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

Клас Seemple.Object

Шлях до модуля CommonJS: 'seemple/object'

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

Уявіть собі, що ви створюєте клас, що включає властивості "a", "b" і "c". Припустимо "a" і "b" - це властивості які повинні бути відправлені на сервер, а властивість "c" лише відповідає за деякий стан програми (наприклад, містить суму "a" і "b"). Властивість "c" не повинна бути відправлена на сервер. Тому нам потрібно відокремити властивості, які відповідають за дані.

Для того, щоб відокремити такі властивості від інших, можна скористатися методом Seemple.Object#addDataKeys.

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

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

Якщо ви заздалегідь не знаєте, які властивості є даними, можна завжди використовувати метод Seemple.Object#setData, який не тільки оголошує властивості, що відповідають за дані, але і відразу встановлює значення.

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

this.c = 3;

Після того, як додаток отримав інформацію про те, що є даними, екземпляр Seemple.Object можна конвертувати в звичайний об'єкт методом Seemple.Object#toJSON і передати на сервер або зберегти в локальній БД (наприклад, в localStorage).

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

Події

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

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

Аргументи

Iм'я Тип Опис
data optional object Дані, що входять в новий екземпляр

Приклади

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

// те ж саме, що і new Seemple.Object().setData({ a: 1, b: 2 });
new Seemple.Object({ a: 1, b: 2 });

Спадкування

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

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

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

Перебір даних, використовуючи цикл for..of

const seempleObject = new Seemple.Object({ a: 1, b: 2 });
for(let item of seempleObject) {
	console.log(item); // 1 .. 2
}

Seemple.Object#addDataKeys(keys) seempleObject

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

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

Повертає seempleObject - self

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

Аргументи

Iм'я Тип Опис
keys string array

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

Приклади

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

Seemple.Object#each(callback, thisArg) seempleObject

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

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

Повертає seempleObject - self

Аргументи

Iм'я Тип Опис
callback function

Функція, яка викликається на кожній ітерації

thisArg optional *

Контекст функції

Приклади

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

Seemple.Object#entries() array

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

Повертає array - entries

Приклади

for(const [key, value] of this.entries()) {
    console.log(key, value);
}

Seemple.Object#isDataKey(key) boolean

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

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

Аргументи

Iм'я Тип
key string

Приклади

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

Seemple.Object#keyOf(value) string null

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

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

Аргументи

Iм'я Тип Опис
value *

значення будь-якого типу, яке слід знайти серед даних

Приклади

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

seempleObject.c = 3;

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

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

seempleObject.keyOf(3); // null

Seemple.Object#keys() array

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

Повертає array - keys

Приклади

const keys = this.keys();

Seemple.Object#removeDataKeys(keys) seempleObject

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

Повертає seempleObject - self

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

Аргументи

Iм'я Тип Опис
keys string array

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

Приклади

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

Seemple.Object#setData(key, value, eventOptions) seempleObject

Синонім: Seemple.Object#jset

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

Цей метод робить дві речі:

  1. Встановлює значення заданої властивості.

  2. Додає ключ властивості в список даних, що робить властивість доступною для використання в методах Seemple.Object#each, Seemple.Object#keys, Seemple.Object#toJSON) та інших.

Якщо передати прапор replaceData, встановлений як true, в об'єкт події, то інші властивості будуть вилучені зі списку властивостей, що відповідають за дані.

В іншому, метод працює так само, як і Seemple#set.

Повертає seempleObject - self

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

Аргументи

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

Ключ

value *

Значення

eventOptions optional eventOptions

Об'єкт події

Посилання

Приклади

this.setData('a', 1).setData('b', 2);

// Присвоювання властивості 'c' трійку,
// але не додаємо ключ 'c' в список ключів, що відповідають за дані
this.set('c', 3);

this.each((value, key) => {
	console.log(key, value);
});

// виводить 'a' 1 і 'b' 2

console.log(this.keys()); // виводить ['a', 'b']

console.log(this.toJSON()); // виводить { a: 1, b: 2 }

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

this.setData('a', 1).setData('b', 2);
this.set('a', 3);
this.b = 4;

Використання альтернативного імені методу: jset

this.jset('a', 1);

Seemple.Object#setData(keyValuePairs, evtOpts) seempleObject

Альтернативний синтаксис методу Seemple.Object#setData, який приймає об'єкт ключ-значення для встановлення декількох властивостей одночасно

Повертає seempleObject - self

Аргументи

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

Seemple.Object#toJSON(recursive=true) object

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

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

Повертає object

Аргументи

Iм'я За замовчуванням Тип
recursive optional true boolean

Приклади

const seempleObject = new Seemple.Object({
	a: 1,
	b: 2,
	c: new Seemple.Object({
		d: 3,
		e: 4
	})
});

// повертає {a: 1, b: 2, c: { d: 3, e: 4 }}
console.log(seempleObject.toJSON());

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

Seemple.Object#values() array

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

Повертає array - values

Приклади

const values = this.values();

Клас Seemple.Array

Шлях до модуля CommonJS: 'seemple/array'

Клас Seemple.Array служить колекцією в Seemple.js. Він успадковується від класу Seemple і включає всі його властивості та методи. Крім цього, Seemple.Array має всі методи, які є у звичайного масиву, тим самим спрощуючи вивчення його можливостей.

Всі методи, запозичені у вбудованого Array працюють аналогічно їх оригіналам

Програміст, знайомий з методами нативного Array відразу може зрозуміти, яким методом можна додати елемент (push, unshift, splice), яким видалити (pop, shift, splice), яким впорядкувати (sort, reverse) тощо.

У зв'язку з тим, що методи працюють так само, як і оригінальні (з невеликими винятками), вони не приведені в цій документації окремо, а виведені в розділ Seemple.Array#METHOD.

this.push(1, 2, 3);
this.pop();

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

Для цього використовується синтаксис метод_, де нижнє підкреслення в кінці імені методу означає, що останнім аргументом є об'єкт події. Такі методи не наведено в цій документації, так як потрібно запам'ятати тільки їх синтаксис. Див. Seemple.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

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

Автоматичний рендеринг

Seemple.Array вміє автоматично відмальовувати елементи на сторінці при будь-яких модифікаціях масиву. За подробицями зверніться до документації Seemple.Array#itemRenderer.

Посилання

Приклади

Створення екземпляра з нульовою довжиною

new Seemple.Array();

Створення екземпляра із зазначенням довжини

new Seemple.Array(42);

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

new Seemple.Array('Hi', { a: 'b' });

Спадкування

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

Спадкування, використовуючи функцію Seemple.Class

const MyClass = Seemple.Class({
	extends: Seemple.Array,
	constructor(items) {
		this.recreate(items).sayHello();
	},
	sayHello() {
		alert("Hello World!");
	}
});

Seemple.Array#METHOD()

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

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

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

  • Метод forEach повертає себе замість undefined
  • Методи, які в оригінальному вигляді повертають новий масив (splice, slice, filter, map ...), повертають новий екземпляр Seemple.Array.
  • Методи keys, values та entries повертають масив замість ітератора.

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

Посилання

Приклади

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

console.log(seempleArray.isSeempleArray); // true
this.reverse();

Seemple.Array#METHOD_()

Будь-який метод iз Array.prototype з можливістю передати об'єкт події

Ознайомившись з Seemple.Array#METHOD стає зрозуміло, що методи не підтримують передачу об'єкта події, так як в точності повторюють синтаксис і кількість аргументів методів вбудованого Array. Синтаксис МЕТОД_ дозволяє передати в обробник події якісь дані або встановити службові прапори, що відповідають за поведінку масиву після виклику методу.

Службові прапори:

Посилання

Приклади

this.push_(1, 2, 3, {
    silent: true
});

this.pop_({
    silent: true
});
this.on('modify', evt => {
	alert(evt.flag); // 42
});

this.push_(1, 2, 3, {
	flag: 42
});

<virtual>Seemple.Array#Model(data, seempleArray, index)

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

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

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

Аргументи

Iм'я Тип Опис
data object

Дані, передані в конструктор

seempleArray seempleArray

Масив, в який додали елемент

index number

Поточний індекс об'єкта в батьківському масиві

Посилання

Приклади

// визначаємо "модель"
class MyModel extends Seemple.Object {
	constructor(data, parentArray, index) {
		super(data);
		this.doSomething();
	}
	doSomething() { ... }
}

// визначаємо клас для колекції
class MyArray extends Seemple.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();

Seemple.Array#mediateItem(mediator)

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

Цей метод служить для того, щоб перехопити і трансформувати додані в масив елементи. Зверніть увагу, метод перевизначає властивість Seemple.Array#Model.

Аргументи

Iм'я Тип Опис
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(seempleArray.toJSON());
this.mediateItem(item => {
	if(item.something) {
		return new FirstModel(item);
	} else {
		return new SecondModel(item);
	}
});

<virtual>Seemple.Array#onItemRender(item, renderEvent)

Функція, яка запускається перед подією render.

Віртуальний метод onItemRender можна використовувати в якості заміни події render.

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

Аргументи

Iм'я Тип Опис
item object

Елемент колекції

renderEvent object

Об'єкт події render

Приклади

class MyModel extends Seemple.Object {
	constructor(data) {
		super(data);
	}
	onRender(renderEvt) {
		this.bindNode('isChecked', ':sandbox .my-checkbox');
		this.bindNode('text', ':sandbox .text', Seemple.binders.html());
	}
});

class MyArray extends Seemple.Array {
	get Model() {
		return MyModel;
	}
	itemRenderer() {
		return '<li>'
	}
	constructor() {
		this.bindNode('sandbox', '.my-form');
	}
	onItemRender(item, renderEvt) {
		// ...
	}
});

const app = new MyArray();

Seemple.Array#orderBy(keys, orders=asc) seempleArray

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

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

Повертає seempleArray - self

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

Аргументи

Iм'я За замовчуванням Тип Опис
keys string array

Ключ властивості або масив декількох ключів, за якими колекція буде відсортована

orders optional asc string array

Порядок або масив порядків, відповідних до масиву ключів

Приклади

this.recreate([
    { 'user': 'fred',   'age': 48 },
    { 'user': 'barney', 'age': 34 },
    { 'user': 'fred',   'age': 42 },
    { 'user': 'barney', 'age': 36 }
]);

// сортує за значенням властивості 'user' по зростанню і значенням властивості 'age' по спаданню
this.orderBy(['user', 'age'], ['asc', 'desc']);
// → [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":42}]

Seemple.Array#pull(indexOrValue, eventOptions) * null

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

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

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

Аргументи

Iм'я Тип Опис
indexOrValue object number

Індекс елемента, який потрібно видалити або видаляємий об'єкт

eventOptions optional eventOptions

Об'єкт події на випадок, якщо потрібно передати в обробник події якісь дані або встановити службові прапори (наприклад, silent)

Приклади

Передача індексу масиву

let removed;

this.recreate(['a', 'b', 'c']);

removed = this.pull(1);

console.log(removed); // 'b'

console.log(this.join(',')); // 'a,c'

Передача видаляємого об'єкту

const object1 = {};
const object2 = {};
const object3 = {};
let removed;

this.push(object1, object2, object3);

removed = this.pull(object2);

console.log(removed === object2); // true

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

Seemple.Array#recreate(array, eventOptions) seempleArray

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

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

Повертає seempleArray - self

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

Аргументи

Iм'я Тип Опис
array optional array

Масив або масивоподібний об'єкт

eventOptions optional eventOptions

Об'єкт події

Посилання

Приклади

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

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

Seemple.Array#rerender(eventOptions) seempleArray

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

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

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

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

Повертає seempleArray - self

Аргументи

Iм'я Тип Опис
eventOptions optional eventOptions

Об'єкт події

Приклади

this.rerender({
	forceRerender: true
});

Seemple.Array#restore(selector, eventOptions) seempleArray

Відтворює Seemple.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 Seemple.Object {
    constructor(data) {
        super(data);
        this.addDataKeys('value');
    }
    onRender() {
        this.bindNode('value', ':sandbox', Seemple.binders.html())
    }
});

class MyCollection extends Seemple.Array {
    get itemRenderer() {
        return ':sandbox .renderer';
    }
    constructor() {
        this
            .bindNode('sandbox', '.collection-node')
            .restore(':sandbox li');
    }
});

const myCollection = new MyCollection();
myCollection.push({
    value: 'Four'
});

console.log(myCollection.toJSON());
// [{value: 'One'}, {value: 'Two'}, {value: 'Three'}, {value: 'Four'}]

Якщо аргумент selector не заданий, то колекція буде відтворена з елементів, що входять в контейнер ("container" або "sandbox").

При відтворенні, на кожному елементі масиву генерується подія render і викликаються методи onRender і onItemRender (див документацію), як і при звичайному рендерингу.

Повертає seempleArray - self

Генерує події recreate modify add addone

Аргументи

Iм'я Тип Опис
selector optional selector

Селектор

eventOptions optional eventOptions

Об'єкт події

Seemple.Array#toJSON(recursive=true) array

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

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

Повертає array

Аргументи

Iм'я За замовчуванням Тип
recursive optional true boolean

Приклади

const seempleArray = new Seemple.Array([1, 2, new SeempleArray(3, 4)]);

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

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

<virtual>Seemple.Array#itemRenderer: string function

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

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

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

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

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

<ul class="my-list"></ul>
class MyArray extends Seemple.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 Seemple.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 Seemple.Array {
    get Model() { return MyModel; }
    itemRenderer = '<div class="my-div">foo</div>';
    constructor() { ... }
}

Селектор в якості значення властивості

На випадок, якщо ви виносите шаблони для елементів на HTML сторінку, itemRenderer підтримує селектор в якості значення. У цьому випадку, Seemple.Array буде шукати HTML елемент в DOM дереві і витягне innerHTML знайденого елемента. У разі, якщо елемент не знайдений, кидається виняток.

HTML текст від селектора відрізняється наявністю символу <.

<script type="text/html" id="my-template">
    <div class="my-div">foo</div>
</script>
class MyArray extends Seemple.Array {
    get Model() { return MyModel; }
    itemRenderer = '#my-template';
    constructor() { ... }
}

Функція як значення властивості

Використання функції в якості значення властивості itemRenderer може стати в нагоді, коли є потреба динамічно генерувати елемент для рендеринга. Функція може повертати:

HTML строку

class MyArray extends Seemple.Array {
    itemRenderer() {
        return '<div class="my-div">foo</div>';
    }
}

Селектор

class MyArray extends Seemple.Array {
    itemRenderer: function() {
        return '#my-template';
    }
}

DOM вузол

class MyArray extends Seemple.Array {
    itemRenderer() {
        return document.createElement('div');
    }
}

Перекриття батьківського рендерера властивістю render

Іноді зручно оголошувати рендерер в класі Seemple.Array#Model, а не на рівні колекції. Властивість renderer перекриває значення itemRenderer, якщо вона задана для елемента колекції.

class MyModel extends Seemple.Object {
    renderer = '<div class="my-div">foo</div>';
}

class MyArray extends Seemple.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 Seemple.Object {
    constructor(data) {
        super(data);

        // чекаємо на генерацію події
        this.on('render', () => {
            // оголошуємо біндінги
            this.bindNode('isChecked', ':sandbox .my-checkbox');
            this.bindNode('text', ':sandbox .text',
                Seemple.binders.html());
        });
    }
});

class MyArray extends Seemple.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.

Не забувайте, що в Seemple.js реалізована можливість вилову делегованих подій. Тобто сам масив може відловити подію рендеринга айтема, використовуючи ім'я події *@render (див. документацію до eventNames).

this.on('*@render', () => {
    alert('Child element is rendered');
});

HTML елемент стає пісочницею для вставленого об'єкту дозволяючи використовувати селектор :sandbox і інші можливості після рендеринга. Якщо об'єкт входить відразу в кілька колекцій, встановіть йому властивість bindRenderedAsSandbox: false, щоб скасувати цю поведінку.

class MyModel extends Seemple.Object {
    bindRenderedAsSandbox = false;
    // ...
});

onItemRender та onRender

Для поліпшення коду в одній з попередніх версій з'явився віртуальний метод Seemple.Array#onItemRender, який можна використовувати замість події render. В якості альтернативи, у "моделей" викликається метод onRender, що так само дозволяє зробити код більш "плоским" і позбутися вкладених функцій.

class MyModel extends Seemple.Object {
    constructor(data) {
        super(data);
    }
    onRender(evt) {
        this.bindNode('isChecked', ':sandbox .my-checkbox');
        this.bindNode('text', ':sandbox .text',
                Seemple.binders.html());
    }
}

class MyArray extends Seemple.Array {
    get Model() { return MyModel; }
    itemRenderer = '...';
    constructor() {
        //...
    },
    onItemRender(item, evt) {
        //...
    }
}

const app = new MyArray();

Шаблонізатор

Поглянувши на приклади використання Seemple.Array і Seemple.Array#itemRenderer можна звернути увагу на те, що вся логіка, що відповідає за двосторонню і односторонню прив'язку даних укладена в JavaScript коді. Але коли розробляєш дуже просту колекцію, яка не включає в себе складну логіку, масу прив'язок та ін. хотілося б мати більш короткий варіант оголошення прив'язок. Для цього, в itemRenderer може бути переданий шаблон, що включає прив'язки, укладені у фігурні дужки (див. Seemple#parseBindings).

class MyArray extends Seemple.Array {
    itemRenderer: `<label>
        <input type="checkbox" checked="{{isChecked}}">{{text}}
    </label>`
    // ...
}

const app = new MyArray();

Скасування рендеринга

Як видно вище, якщо у дочірнього елемента задано властивість render, Seemple.Array спробує його змалювати. Для того, щоб повністю скасувати рендеринг для масиву, надайте властивості масиву renderIfPossible значення false.

class MyArray extends Seemple.Array {
    renderIfPossible = false;
    // ...
}

Переміщення об'єкта з одного масиву в інший

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

Для рендеринга тільки тих об'єктів, які ще не були намальовані, скористайтеся методом Seemple#set з прапором forceRerender зі значенням false

this.set('itemRenderer', renderer, {
    forceRerender: false
});

Така необхідність може виникнути тоді, коли ви використовуєте серверний пререндерінг (див. Seemple.Array#restore), а шаблон завантажується динамічно.

class MyArray extends Seemple.Array {
    constructor() {
        super()
            .bindNode('sandbox', '.some-node')
            .restore();

        fetch('templates/template.html')
            .then(resp => resp.text())
            .then(data => {
                this.set('itemRenderer', data, {
                    forceRerender: false
                });
            });
    }
}

Рендерінг колекції, що складається зі звичайних об'єктів

Об'єкт, що входить в колекцію, не обов'язково повинен бути екземпляром Seemple, можна рендерити будь-який об'єкт. Байндінги для таких об'єктів можна оголосити використовуючи статичний метод Seemple.bindNode.

class MyArray extends Seemple.Array {
    // Model не визначена
    itemRenderer: ...
    onItemRender(item) {
        Seemple.bindNode(item, 'x', ':sandbox .some-node');
    }
})

Ще невеликий приклад: рендеринг простого списку.

class MyArray extends Seemple.Array {
    itemRenderer = '<li>{{value}}</li>';
    constructor() {
        super().bindNode('sandbox', '.my-list');
    }
});

const arr = new MyArray();
arr.push({ value: 'Item 1' }, { value: 'Item 2' });

Посилання

Seemple.Array#renderIfPossible: boolean

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

Посилання

Приклади

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

<virtual>Seemple.Array#trackBy: string

Властивість trackBy вказує на ім'я властивості ідентифікатора об'єктів, що входять в масив

У разі, якщо клієнт і сервер активно обмінюються даними (наприклад, списком користувачів), а об'єкти, що входять в масив мають унікальний ID (наприклад, ідентифікатор користувача), то перерисовка всієї колекції з нуля не має сенсу. Після того, як сервер повернув нову колекцію, набагато раціональніше перевірити, чи є в колекції об'єкт з таким само ID і, якщо об'єкт знайдений, оновити його. Таким чином, не створюється новий об'єкт (екземпляр Seemple.Array#Model) і не створюється новий DOM вузол.

trackBy працює тільки при використанні методу Seemple.Array#recreate, так як це єдиний метод який "перестворює" колекцію заново.

У прикладі нижче використовується _id як ключ ідентифікатора.

class MyArray extends Seemple.Array {
    get trackBy() {
        return '_id';
    }
    constructor() {
        //...
    }
});

const arr = new MyArray();

// додає два об'єкти в масив
arr.recreate([
    {_id: 0, name: 'Foo'},
    {_id: 1, name: 'Bar'},
    {_id: 2, name: 'Baz'}
]);

// Видалить об'єкт з ідентифікатором 0
// Додасть об'єкт з ідентифікатором 3
// Оновить об'єкт з ідентифікатором 1, перезаписавши name: Bar -> BarNew
// Оновить об'єкт з ідентифікатором 2, перезаписавши name: Baz -> BazNew
// Пересорує колекцію у відповідності з переданим даними
arr.recreate([
    {_id: 1, name: 'BarNew'},
    {_id: 3, name: 'Qux'},
    {_id: 2, name: 'BazNew'}
]);

Властивість може містити спеціальне значення "$index", яке дозволяє оновлювати об'єкт за індексом в колекції.

class MyArray extends Seemple.Array {
    get trackBy() {
        return '$index';
    }
    constructor() {
        //...
    }
});

const arr = new MyArray();

// додасть два об'єкти в масив
arr.recreate([
    {name: 'Foo'},
    {name: 'Bar'},
    {name: 'Baz'}
]);

// оновить всі три об'єкти новими даними
// і додасть новий об'єкт з ім'ям Qux
arr.recreate([
    {name: 'NewFoo'},
    {name: 'NewBar'},
    {name: 'NewBaz'},
    {name: 'Qux'}
]);

Посилання

Seemple.Array.from(arrayLike, mapFn, thisArg) seempleArray

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

Повертає seempleArray

Аргументи

Iм'я Тип Опис
arrayLike object

Массивоподібний або ітеруємий об'єкт

mapFn optional function

Відображаюча функція, що викликається для кожного елемента масиву

thisArg optional *

Об'єкт, який використовується в якості this при виклику mapFn

Посилання

Приклади

const seempleArray = Seemple.Array.from([1, 2, 3, 4]);
const seempleArray = Seemple.Array.from([1, 2, 3, 4], item => item * 2);

Спадкування методу

class MyClass extends Seemple.Array {
    // ...
}

const myArray = MyClass.from([1, 2, 3, 4]);
console.log(myArray instanceof MyClass); // true

Seemple.Array.of() seempleArray

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

Повертає seempleArray

Посилання

Приклади

const seempleArray = Seemple.Array.of(1, 2, 3, 4);

Спадкування методу

class MyClass extends Seemple.Array {
    // ...
}

const myArray = MyClass.of(1, 2, 3, 4);
console.log(myArray instanceof MyClass); // true

eventHandler: function

Функція-обробник події. Приймає будь-які аргументи, передані в Seemple#trigger

Аргументи

Iм'я Тип Опис
options * будь-які аргументи, передані в виклик Seemple#trigger після імені події

Приклади

const eventHandler = (...args) => {
	console.log(args);
};
this.on('fyeah', eventHandler);
// logs 'foo', 'bar', 'baz'
this.trigger('fyeah', 'foo', 'bar', 'baz');

seemple: object

Екземпляр класу Seemple

Приклади

const seemple = new Seemple();
obj.calc('a', 'b');

seempleObject: object

Екземпляр класу Seemple.Object

Приклади

const obj = new Seemple.Object({ foo: 'x' });
obj.setData({ bar: 'y' });

seempleArray: object

Екземпляр класу Seemple.Array

Приклади

const arr = new Seemple.Array(1, 2, 3);
arr.push(4);

eventNames: string

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

Довільні події
this.on('myevent', () => {...});
this.trigger('myevent');
change:KEY, що викликається, коли властивість змінюється
this.on('change:x', evt => {...});
this.x = 42;
beforechange:KEY, що викликається, перед зміною властивості
this.on('beforechange:x', evt => {...});
this.x = 42;
addevent:NAME і addevent, що викликаються, коли подія ініціалізується
// для всіх подій
this.on('addevent', evt => {...});
// для події "someevent"
this.on('addevent:someevent', evt => {...});
// генерує події "addevent" та "addevent:someevent"
this.on('someevent', evt => {...});
removeevent:NAME і removeevent, що викликаються, коли обробник події видаляється
// для всіх подій
this.on('removeevent', evt => {...});
// для події "someevent"
this.on('removeevent:someevent', evt => {...});
// генерує події "removeevent" та "removeevent:someevent"
this.off('someevent', evt => {...});
DOM_EVENT::KEY, де DOM_EVENT - це им'я DOM події, KEY - ключ. Генерується тоді, коли подія DOM_EVENT спрацьовує на елементі, який пов'язаний з KEY.
this.bindNode('x', '.my-div');
this.on('click::x', evt => {
    alert('clicked ".my-div"');
});
DOM_EVENT::KEY(SELECTOR), де DOM_EVENT - це им'я DOM події, KEY - ключ, SELECTOR - селектор. Генерується тоді, коли подія DOM_EVENT спрацьовує на елементі, який відповідає селектору SELECTOR, і знаходиться в елементі, який пов'язаний з властивістю KEY.
<div class="my-div">
    <button class="my-button"></button>
</div>
this.bindNode('x', '.my-div');
this.on('click::x(.my-button)', evt => {
    alert('clicked ".my-button"');
});
DOM_EVENT::(SELECTOR), де DOM_EVENT - це ім'я DOM події, SELECTOR - селектор. Генерується тоді, коли подія DOM_EVENT спрацьовує на елементі, який відповідає селектору SELECTOR, і знаходиться в пісочниці поточного об'єкта.
this.bindNode('sandbox', '.my-div');
this.on('click::(.my-button)', evt => {
    alert('clicked ".my-button"');
});

Те ж саме, що і:

this.bindNode('sandbox', '.my-div');
this.on('click::sandbox(.my-button)', evt => {
    alert('clicked ".my-button"');
});
Делеговані події PATH@EVENT, де PATH - це шлях до об'єкта, події якого ми бажаємо прослуховувати, EVENT - це ім'я події.
this.on('a@someevent', () => {...});
this.on('a.b.c@change:d', () => {...});

При виникненні необхідності слухати зміни в усіх елементах Seemple.Array або у всіх властивостях, що відповідають за дані Seemple.Object, замість імені властивості можна вказати зірочку "*".

this.on('*@someevent', () => {...});
this.on('*.b.*.d@change:e', () => {...});

Різні комбінації

Всі наведені вище варіанти синтаксису можна комбінувати довільним способом.

this.on('x.y.z@click::(.my-selector)', () => {...});

binder: object

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

Властивості

Iм'я Тип Опис
on optional string function

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

getValue optional function

Функція, яка відповідає за те, як витягти стан DOM елемента

setValue optional function

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

initialize optional function

Функція, яка запускається при ініціалізації прив'язки. Наприклад, може бути використана для ініціалізації jQuery плагіна

destroy optional function

Функція, яка викликається під час роботи unbindNode. Якщо Байндер досить складний, destroy може містити видалення логіки яка більше не потрібна та звільнення пам'яті

Приклади

const binder = {
	on: 'click',
	getValue(bindingOptions) {
		return this.value;
	},
	setValue(v, bindingOptions) {
		this.value = v;
	},
	initialize(bindingOptions) {
		alert('A binding is initialized');
	},
	destroy(bindingOptions) {
		alert('A binding is destroyed');
	}
};

this.bindNode('a', '.my-checkbox', binder);
const binder = {
	on(callback, bindingOptions) {
		this.onclick = callback;
	}
	// ...
};
// ...

eventOptions: object

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

Приклади

const eventOptions = { silent: true };

this.a = 1;

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

this.set('a', 2, eventOptions); // no alert
const eventOptions = { f: 'yeah' };

this.a = 1;

this.on('change:a', eventOptions => {
	alert(eventOptions.f);
});

this.set('a', 2, eventOptions); // alerts "yeah"

class: function

Клас створений за допомогою синтаксису ECMAScript 2015 або повернений функцією Seemple.Class

Приклади

class MyClass {
	method() { ... }
};
const MyClass = Seemple.Class({
	method() { ... }
});

node

DOM вузол

Приклади

const node = document.querySelector('.foo');

$nodes

Колекція DOM вузлів. Наприклад, jQuery або NodeList.

Приклади

let $nodes = $('.foo');
$nodes = document.querySelectorAll('.bar');

string

Строка

Приклади

const foo = 'bar';

boolean

Логічний тип

Приклади

const bool = true;

number

Число

Приклади

const num = 42;

object

Об'єкт

Приклади

const obj = {
	foo: 'x',
	['bar']: 'y'
};

array

Масив

Приклади

const arr = ['foo', undefined, null, () => {}];

function

Функція

Приклади

function comeOnBarbieLetsGoParty() {
	alert("I'm a Barbie girl, in a Barbie world");
}

null

null

Приклади

const x = null;

*

Будь-який тип

Приклади

let whatever = 'foo';
whatever = 42;

FAQ

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

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

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

function bindNode(object, key, node, binder) {
    const value = object[key];
    Object.defineProperty(object, key, {
        get() {
            return value;
        },
        set(v) {
            binder.setValue.call(node, v);
        }
    });

    node.addEventListener(binder.on, () => {
        value = binder.getValue.call(node);
    });
};

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

Як попередньо відрендерити додаток на сервері?

Можна використовувати Seemple.js на сервері Node.js (потрібна наявність jsdom, точніше, об'єкта window, доступного глобально) або скористатися абсолютно будь-яким шаблонізатором на будь-якій серверній платформі. Перший варіант підходить для статичної генерації HTML, другий - для сторінок, які генеруються при кожному зверненні користувача.

Завдання клієнтської сторони - відтворити додаток з HTML. Seemple#bindNode витягне стан елемента і привласнить його властивості, а Seemple.Array#restore відновить стан колекції.

Що таке debounce?

У документації часто зустрічається фраза "мікропаттерн debounce". Це поширений патерн, який перетворює кілька викликів функції протягом певного часу в один виклик. Детальніше тут.

Що з себе повинен представляти великий додаток?

Додаток на базі Seemple.js, як правило, представляє з себе один вкладений JavaScript об'єкт, кожна гілка якого - екземпляр Seemple. Нові гілки додатку створюються за допомогою Seemple#instantiate, що гарантує цілісність програми та можливість повернути попередній стан додатку або однієї його гілки звичайними привласненням.

Як відрендерити один об'єкт в контейнерах декількох колекцій?

Перше: потрібно встановити класу цього об'єкту властивість bindRenderedAsSandbox зі значенням false. Це відключає автоматичне створення пісочниці при рендеринзі об'єкта в масиві (так як заборонено одному об'єкту мати дві пісочниці).

Друге: за подією render перевірити, в якій масив був вставлений об'єкт і оголосити байндінги, відповідні до масиву. Батьківський масив і відмальований елемент можна отримати, звернувшись до властивостей parentArray і node об'єкта події.

Приклад. Є клас об'єкта User і дві колекції: UsersA і UsersB (їх Seemple.Array#itemRenderer може відрізнятися). Для обох колекцій User використовується в якості Seemple.Array#Model.

class User extends Seemple.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 і оголошувати інші прив'язки...

Знайшли помилку в тексті?
Виберіть її і натисніть
+
Помилка на сайті