<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>
Введение
Фичи
- Реактивный API, позволяющий эффективно решать сложные и запутанные задачи
- Меньше ошибок в коде
- Возможность рефакторинга легаси приложений, без переписывания с нуля
- Освоить фреймворк можно за пару часов благодаря отсутствию сложных концепций
- Одна из самых удобных документаций среди JavaScript библиотек
Для кого этот фреймворк?
Seemple.js заполняет пропасть между джуном и сеньором
- Для новичков в веб программировании, желающих освоить разработку одностраничных приложений
- Для full-stack разработчиков, для которых front-end разработка стоит на втором месте после back-end
- Для всех тех, кого не устраивает текущий порядок вещей во Вселенной веб разработки
Какую бизнес задачу решает фреймворк?
Не секрет, что порог вхождения в веб разработку становится всё выше, требований к современному разработчику всё больше, количество зависимостей в проектах может доходить до нескольких сотен. Несмотря на то, что изучать JavaScript стало модным, спрос на разработчиков, которые могут выполнить поставленную задачу всё сильнее превышает предложение.
Благодаря крайней простоте фреймворка, даже начинающие веб разработчики могут быстро начать делать сначала небольшие, потом средние, а затем и крупные веб приложения. Это значит, что веб студии получают возможность экономить деньги, нанимая младших специалистов, которые, в свою очередь, не могли найти работу раньше.
Только лишь для новичков?
Две вещи, которые выдают Seemple.js, как простой фреймворк - это прямое обращение к DOM при объявлении двустороннего связывания данных и отсутствие каких-либо ограничений по требованиям к архитектуре и шаблонам проектирования. В остальном Seemple.js - современный фреймворк общего назначения для неограниченных в размере одностраничных веб приложений, разработанный с использованием технологий сегодняшнего дня. А тот факт, что фреймворк использует, возможно, весь потенциал акцессоров в JavaScript, как минимум, может вызвать неподдельный интерес.
Как использовать документацию
Уровни важности
Документация разбита на три уровня "продвинутости".
Первый уровень - самое важное
Изучив самые важные свойства и методы, вы можете смело приступать к работе. С классами, методами и свойствами, помеченными значком необходимо разобраться в первую очередь.
Второй уровень - рекомендуется изучить
После того, как вы освоили необходимые для быстрого старта возможности, можете ознакомиться с другими, менее важными (но всё еще важными) свойствами и методами Seemple.js.
Третий уровень - остальные методы и свойства
Для того, чтоб не пугать новичков вещами, которые используются относительно редко, все неважные методы и свойства по умолчанию скрыты. Если вы хотите знать о фреймворке всё, без исключения, кликните на "Продвинутый режим" слева, в меню.
Внимание, если вы перейдете по ссылке к методу или свойству третьего уровня важности, то режим документации автоматически переключится в "продвинутый режим".
Опечатки и ошибки в документации
В конце каждой статьи документации есть ссылка на исходник статьи. Исправить опечатку или ошибку можно прямо в редакторе на 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 элементом
Seemple#bindNode - это единственный метод класса Seemple, отвечающий за изменения DOM. Он создаёт мост между значением свойства и состоянием HTML элемента на странице: от простого инпута до сложного виджета (сложность элементов не ограничена). После связывания свойства экземпляра и HTML элемента не нужно больше следить за синхронизацией данных и представления.
Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой целевой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.
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 });
}
});
// установит знaчeние слайдера 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
передать строку, содержащую точку, то такая строка будет интерпритирована как путь к свойству во вложенном объекте. фреймворк будет слушать изменения во всём дереве, разрывая связь для старых ветвей, и создавая её для новых.
this.a = { b: { c: 'foo' } };
this.bindNode('a.b.c', node);
this.a.b.c = 'bar'; // обновит элемент значением bar
const oldB = this.a.b;
this.a.b = { c: 'baz' }; // обновит элемент значением baz
// элемент не обновится, так как связь с этой ветвью разорвана
oldB.c = 'fuu';
В случае, если имя свойства должно быть использовано как есть, воспользуйтесь флагом exactKey
со значением true
.
this['a.b.c'] = 'foo';
this.bindNode('a.b.c', node, binder, {
exactKey: true
});
this['a.b.c'] = 'bar';
Флаг getValueOnBind
При наличии у байндера getValue
, состояние элемента будет извлечено и присвоено свойству сразу после вызова bindNode
при условии, если привязываемое свойство имеет значение undefined
. Для того, чтоб форсировать это поведение даже если свойство - не undefined
используйте флаг getValueOnBind
со значением true
. Для отмены этого поведения, используйте тот же флаг со значением false
.
Флаг setValueOnBind
При наличии у байндера setValue
, значение свойства будет установлено в качестве состояния элемента сразу после вызова bindNode
при условии, если привязываемое свойство имеет значение отличное от undefined
. Для того, чтоб форсировать это поведение даже если свойство - undefined
используйте флаг setValueOnBind
со значением true
. Для отмены этого поведения, используйте тот же флаг со значением false
.
Флаги debounceGetValue=true
и debounceSetValue=true
Важной особенностью метода bindNode
является то, что к изменению свойств и изменению состояния элемента применяется микропаттерн debounce. Это значит, что если привязанное свойство будет изменено многократно за короткий промежуток времени (например, в цикле), состояние элемента будет обновлено лишь один раз после задержки в несколько миллисекунд (благодаря debounceSetValue=true
). И наоборот: если состояние элемента меняется многократно за короткий промежуток времени (т. е. вызывается соответствующее DOM событие), свойство получит новое значение только один раз после короткой зарержки (благодаря debounceGetValue=true
).
const input = document.querySelector('.my-input');
this.bindNode('x', input);
this.x = 'foo';
console.log(input.value === 'foo'); // false
setTimeout(() => {
console.log(input.value === 'foo'); // true
});
Для отмены этого поведения, т. е. для отмены асинхронности действий, используйте флаги debounceSetValue
и/или debounceGetValue
со значением false
.
Флаги debounceSetValueOnBind=false
и debounceGetValueOnBind=false
Как говорилось выше, к изменению свойств и изменению состояния элемента применяется микропаттерн debounce. Это не касается самого момента связывания. При вызове bindNode
установка состояния элемента или его извлечение с изменением свойства происходит синхронно. debounceSetValueOnBind
и debounceGetValueOnBind
установленные как true
включают debounce и для этих процессов.
Флаги debounceSetValueDelay=0
и debounceGetValueDelay=0
Эти флаги позволяют указать задержку debounce. debounceSetValueDelay
задаётся при использовании debounceSetValue
и debounceSetValueOnBind
, debounceGetValueDelay
при использовании debounceGetValue
и debounceGetValueOnBind
.
Флаг useExactBinder=false
Даже если в метод bindNode
передать конкретный байндер, фреймворк попытается отыскать байндер из 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
Аргументы
Имя | Тип | Описание |
---|---|---|
key | string | Имя свойства |
node | string node $nodes | HTML элемент, который должен быть связан со свойством объекта |
binder optional | binder | Байндер, содержащий свойства |
eventOptions optional | eventOptions | Объект события, в который можно передать ключ |
Ссылки
Seemple#bindNode(bindings, binder, eventOptions)
→
object
Альтернативный синтаксис Seemple#bindNode: возможность передать объект с байндингами
В метод Seemple#bindNode можно передать объект чтобы избежать многократного вызова метода и сократить код. Ключи объекта - это имена привязываемых свойств, а значения могут быть следующими:
- HTML элемент
- Объект со свойствами
node
(HTML элемент) иbinder
- Массив объектов со свойствами
node
(HTML элемент) иbinder
Если binder
передан вторым аргументом, то он служит байндером для тех элементов, для которых байднер не указан явно.
Возвращает object - self
Аргументы
Имя | Тип | Описание |
---|---|---|
bindings | object | (см. пример) |
binder optional | binder | (см. выше) |
eventOptions optional | eventOptions | (см. выше) |
Примеры
this.bindNode({
foo: '.custom-checkbox',
'bar.length': 'textarea'
});
this.bindNode({
foo: {
node: ':sandbox .aaa',
binder: 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
Аргументы
Имя | Тип | Описание |
---|---|---|
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#bindOptionalNode()
Работает в точности так же, как и Seemple#bindNode но не бросает исключение, если аргумент node
- пустой массив, undefined
или не существует
У метода есть статичный аналог.
Ссылки
Примеры
this.bindOptionalNode('myKey', '.my-element');
Seemple#bindSandbox(node, eventOptions)
Привязывает песочницу
При этом, "отвязывает" предыдущую, если таковая существует.
У метода есть статичный аналог.
Генерирует события bind bind:sandbox
Аргументы
Имя | Тип | Описание |
---|---|---|
node | string node $nodes | Элемент, который должен стать песочницей |
eventOptions optional | eventOptions | Объект события |
Ссылки
Примеры
this.bindSandbox('.my-element');
Seemple#calc(target, source, handler=(v)=>v, eventOptions)
Создает зависимость значения одного свойства от значений других
Метод calc
создает зависимость значения свойства (аргумент target
) от значений других свойств (аргумент source
). При изменении source
, target
вычисляется автоматически.
Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.
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
});
Аргументы
Имя | По умолчанию | Тип | Описание |
---|---|---|---|
target |
| string | Имя свойства которое зависит от других свойств |
source |
| string array | От каких свойств зависит искомое свойство (см. описание выше) |
handler optional | (v)=>v
| function | Функция, возвращающая новое значение |
eventOptions optional |
| eventOptions | Объект, в который можно передать какие-нибудь данные для обработчика события, слушающего изменения |
Примеры
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
, массив объектов).
Аргументы
Имя | Тип | Описание |
---|---|---|
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.
Метод является надстройкой над 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
Аргументы
Имя | Тип | Описание |
---|---|---|
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 extends 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,
settings: 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
Аргументы
Имя | Тип | Описание |
---|---|---|
keyClassPairs | object | Объект со свойствами ключ-класс |
updateCallback optional | function | Функция, вызывающаяся при каждой попытке присвоить новые данные свойству. |
Примеры
this.instantiate({
x: Class1,
y: Class2,
z: Class3
}, (instance, data) => {
instance.doSomethingWith(data);
});
Seemple#mediate(key, mediator)
Трансформирует значение свойства при его изменении
Этот метод используется для преобразования значения свойства при его изменении. Например, вам нужно, чтоб значение свойства всегда было либо определенного типа, либо целым числом, либо быть не менее нуля и не более ста и т. д.
Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.
const mediate = require('seemple/mediate');
const object = {};
mediate(object, key, mediator);
// вместо this.mediate(key, mediator);
Аргументы
Имя | Тип | Описание |
---|---|---|
key | string array | Имя свойства или массив имен |
mediator | function | Функция-посредник (медиатор, mediator), возвращающая новое значение. В неё передаются следующие аргументы: новое значение, предыдущее значение, имя свойства, сам объект |
Примеры
this.mediate('x', value => String(value));
this.x = 1;
alert(typeof this.x); // "string"
Массив ключей
this.mediate(['x', 'y'], value => String(value));
Seemple#mediate(keyMediatorPairs)
Альтернативный синтаксис метода Seemple#mediate, принимающий в качестве аргумента объект "ключ-медиатор"
Аргументы
Имя | Тип | Описание |
---|---|---|
keyMediatorPairs | object | Объект со свойствами ключ-медиатор |
Примеры
this.mediate({
x: String,
y: Number,
z: Boolean
});
this.x = 1;
this.y = 2;
this.z = 3;
alert(typeof this.x); // "string"
alert(typeof this.y); // "number"
alert(typeof this.z); // "boolean"
Seemple#off(names, callback, context)
→
seemple
Удаляет обработчик события
Удаляет созданный ранее обработчик. Все три аргумента опциональны. Вы можете удалить как все события (не передавая ни одного аргумента), так и отдельные (передав только имя события, передав имя события и обработчик, передав и имя события, и обработчик, и контекст)
Возвращает seemple - self
Генерирует события removeevent removeevent:NAME
Аргументы
Имя | Тип | Описание |
---|---|---|
names optional | eventNames | Разделенный пробелами список имен событий (например, |
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.
Обратите внимание, что у метода есть статичный аналог, который работает в точности так же, но принимает любой объект в качестве первого аргумента, cдвигая остальные аргументы вправо.
const on = require('seemple/on');
const object = {};
on(object, names, callback, triggerOnInit, context);
// вместо this.on(names, callback, triggerOnInit, context);
Возвращает object - self
Генерирует события addevent addevent:NAME
Аргументы
Имя | Тип | Описание |
---|---|---|
names | eventNames | Имя события или несколько имен, разделенных пробелом (например, |
callback | eventHandler | Функция, которая вызывается по событию |
triggerOnInit optional | boolean | Если аргумент |
context optional | object | Контекст обработчика. Другими словами, |
Ссылки
Примеры
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
Аргументы
Имя | Тип | Описание |
---|---|---|
evtnameHandlerObject | object | Объект с событиями |
triggerOnInit optional | boolean | Если аргумент |
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
Аргументы
Имя | Тип | Описание |
---|---|---|
names | eventNames | Имя события или несколько имен, разделенных пробелом (например, |
callback | eventHandler | Функция, которая вызывается по событию |
debounceDelay optional | number | Задержка |
triggerOnInit optional | boolean | Если аргумент |
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
Аргументы
Имя | Тип | Описание |
---|---|---|
evtnameHandlerObject | object | Объект с обработчиками событий |
debounceDelay optional | number | Задержка |
triggerOnInit optional | boolean | Если аргумент |
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
Аргументы
Имя | Тип | Описание |
---|---|---|
names | eventNames | Имя события или несколько имен, разделенных пробелом (например, |
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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 события не затираются).
Поддерживаемый синтаксис.
- 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}}">
- Привязка атрибутов. ```html <!-- Значение атрибута href будет зависеть от значений свойств "category" и "someObject.page" (односторонняя привязка) JS: this.category = 'seemple'; this.someObject = { page: 42 };
--> A link
```
Если фигурные скобки не устраивают, поменяйте их на что-то другое, используя Seemple.parserBrackets
Зачем нужен такой метод?
В случае, если вы разрабатываете большую форму со стандартными HTML5 полями, метод поможет сохранить время на объявление многочисленных привязок. Кроме этого, parseBindings
полезен в случае создания очень простой коллекции, не требующей реализации сложной модели.
Возвращает $nodes - Коллекция DOM узлов, переданная в функцию в качестве аргумента
Аргументы
Имя | Тип | Описание |
---|---|---|
node | string node $nodes | HTML строка, селектор, DOM узел или коллекция DOM узлов |
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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 "ключ-значение"
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
key | string null | Ключ или список ключей, разделенных пробелами. Если вместо ключа передать null, удалятся все привязки для данного экземпляра |
node optional | string node $nodes | HTML элемент, с которым свойство больше не хочет иметь дела |
eventOptions optional | eventOptions | Объект события, в который можно передать какие-нибудь данные для обработчика или ключ |
Примеры
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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, позволяя присвоить байндинги переменной для быстрого удаления.
Аргументы
Имя | Тип | Описание |
---|---|---|
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 - class (точнее, конструктор класса)
Аргументы
Имя | Тип | Описание |
---|---|---|
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 - Экземпляр недоступного извне класса
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип |
---|---|
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 на странице). Необходимо, чтобы метод был запущен перед объявлением каких-либо байндингов.
Аргументы
Имя | Тип | Описание |
---|---|---|
$ | function | Любая библиотека (jQuery, Zepto, |
Примеры
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
Аргументы
Имя | Тип | Описание |
---|---|---|
attribute | string | Имя атрибута |
mappingFn optional | function | Отображающая функция |
Примеры
this.bindNode('image', 'img.my-image', Seemple.binders.attr('src'));
this.image = 'http://example.com/cats.jpg';
Использование отображающей функции
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
Аргументы
Имя | По умолчанию | Тип |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
property | string | Свойство dataset |
mappingFn optional | function | Отображающая функция |
Примеры
this.bindNode('myKey', '.my-element', Seemple.binders.dataset('myProp'));
this.myKey = 'foo';
Использование отображающей функции
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
Аргументы
Имя | По умолчанию | Тип | Описание |
---|---|---|---|
bool optional | true
| boolean | Если аргумент равен |
Примеры
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
Аргументы
Имя | По умолчанию | Тип | Описание |
---|---|---|---|
bool optional | true
| boolean | Если аргумент равен |
Примеры
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
Аргументы
Имя | Тип | Описание |
---|---|---|
mappingFn optional | function | Отображающая функция |
Примеры
this.bindNode('myKey', '.my-element', Seemple.binders.html());
// установит innerHTML элемента как "<div>foo</div>"
this.myKey = '<div>foo</div>';
Использование отображающей функции
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
property | string | Имя свойства |
mappingFn optional | function | Отображающая функция |
Примеры
this.bindNode('disabled', '.my-button',
Seemple.binders.prop('disabled'));
// устанавливает свойство disabled = true для элемента
this.disabled = true;
// устанавливает свойство disabled = false для элемента
this.disabled = false;
Использование отображающей функции
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
Аргументы
Имя | Тип | Описание |
---|---|---|
multiple optional | boolean | Является ли селект |
Примеры
this.bindNode('myKey', '.my-select', Seemple.binders.select(true));
Seemple.binders.style(property, mappingFn)
→
binder
Возвращает байндер, меняющий заданное свойство стиля DOM элемента в зависимости от значения свойства объекта.
Значение свойства можно преобразить с помощью переданной функции mappingFn
.
Возвращает binder
Аргументы
Имя | Тип | Описание |
---|---|---|
property | string | Свойство |
mappingFn optional | function | Отображающая функция |
Примеры
this.bindNode('myKey', '.my-element',
Seemple.binders.style('backgroundColor'));
this.myKey = 'red'; // цвет фона .my-element стал красным
Использование отображающей функции
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
Аргументы
Имя | Тип | Описание |
---|---|---|
mappingFn optional | function | Отображающая функция |
Примеры
this.bindNode('myKey', '.my-element', Seemple.binders.text());
this.myKey = 'foo'; // установит textContent элемента как "foo"
Использование отображающей функции
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');
});
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
keys | string array | Массив имен свойств либо список аргументов с именами свойств |
Примеры
this.addDataKeys(['a', 'b']);
this.addDataKeys('a', 'b');
Seemple.Object#each(callback, thisArg)
→
seempleObject
Перебирает свойства, отвечающие за данные
Метод очень похож на Array.prototype.forEach
и является альтернативой циклу for..of.
Возвращает seempleObject - self
Аргументы
Имя | Тип | Описание |
---|---|---|
callback | function | Функция, которая вызывается на каждой итерации |
thisArg optional | * | Контекст функции |
Примеры
this
.setData({ a: 1, b: 2 })
.addDataKeys('c')
.each((value, key) => {
console.log(key, value);
});
;
// >>> a 1, b 2, c undefined
Seemple.Object#entries() → array
Возвращает массив пар имен и значений свойств, отвечающих за данные
Возвращает array - entries
Примеры
for(const [key, value] of this.entries()) {
console.log(key, value);
}
Seemple.Object#isDataKey(key)
→
boolean
Проверяет, входит ли строка в список ключей, отвечающих за данные
Возвращает boolean - результат проверки
Аргументы
Имя | Тип |
---|---|
key | string |
Примеры
console.log(this.isDataKey('a'));
Seemple.Object#keyOf(value)
→
string
null
Ищет заданное значение свойства среди свойств, отвечающих за данные, и возвращает имя первого совпавшего свойства, если такое значение найдено
Возвращает string null - имя свойства
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
keys | string array | Массив имен свойств либо список аргументов с именами свойств |
Примеры
this.removeDataKeys(['a', 'b']);
this.removeDataKeys('a', 'b');
Seemple.Object#setData(key, value, eventOptions)
→
seempleObject
Синоним: Seemple.Object#jset
Устанавливает значение свойству и добавляет его имя в список имен, отвечающих за данные
Этот метод делает две вещи:
Устанавливает заданное значение заданному свойству.
Добавляет ключ свойства в список данных, что делает свойство доступным для использования в методах Seemple.Object#each, Seemple.Object#keys, Seemple.Object#toJSON).
Если передать флаг
replaceData
, установленный какtrue
объект события, то остальные свойства будут удалены из списка свойств, отвечающих за данные.
В остальном, метод работает так же, как и Seemple#set.
Возвращает seempleObject - self
Генерирует события change change:KEY modify set
Аргументы
Имя | Тип | Описание |
---|---|---|
key | string | Ключ |
value | * | Значение |
eventOptions optional | eventOptions | Объект события |
Ссылки
Примеры
this.setData('a', 1).setData('b', 2);
// присваиваем свойству 'c' тройку,
// но не добавляем ключ 'c' в список ключей, отвечающих за данные
this.set('c', 3);
this.each((value, key) => {
console.log(key, value);
});
// выводит 'a' 1 и 'b' 2
console.log(this.keys()); // выводит ['a', 'b']
console.log(this.toJSON()); // выводит { a: 1, b: 2 }
После использования метода setData
со свойством можно работать, как с обычным свойством
this.setData('a', 1).setData('b', 2);
this.set('a', 3);
this.b = 4;
Использование альтернативного имени метода: jset
this.jset('a', 1);
Seemple.Object#setData(keyValuePairs, evtOpts)
→
seempleObject
Альтернативный синтаксис метода Seemple.Object#setData, который принимает объект ключ-значение для установки нескольких свойств сразу
Возвращает seempleObject - self
Аргументы
Имя | Тип | Описание |
---|---|---|
keyValuePairs | object | Объект ключ-значение |
evtOpts | eventOptions | Объект события |
Примеры
this.setData({
a: 1,
b: 2
});
Если передать флаг replaceData
, установленный как true
в объект события, то свойства, которые не входят в переданный объект, будут удалены из списка свойств, отвечающих за данные
this
.addDataKeys(['a', 'b', 'c'])
.setData({
a: 1,
b: 2
}, {
replaceData: true
});
console.log(this.keys()); // ['a', 'b']
Seemple.Object#toJSON(recursive=true)
→
object
Конвертирует экземпляр Seemple.Object в обычный объект
Метод работает рекурсивно, вызывая toJSON
для всех свойств, у которых есть метод с таким именем. Для отмены рекурсии передайте false
первым аргументом.
Возвращает object
Аргументы
Имя | По умолчанию | Тип |
---|---|---|
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.Object#isSeempleObject: boolean
Свойство isSeempleObject
всегда равно true
для экземпляров Seemple.Object.
Примеры
console.log(object.isSeempleObject);
Класс 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()
Любой метод из Array.prototype
Seemple.Array включает в себя все методы, входящие в нативный JavaScript массив:
- join
- pop
- push
- reverse
- shift
- unshift
- slice
- splice
- sort
- filter
- forEach
- some
- every
- map
- indexOf
- lastIndexOf
- reduce
- reduceRight
- copyWithin
- find
- findIndex
- fill
- includes
- entries
- keys
- concat
При этом, они работают точно так же, как и методы 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_()
Любой метод из 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.
Аргументы
Имя | Тип | Описание |
---|---|---|
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.
Аргументы
Имя | Тип | Описание |
---|---|---|
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
с единственным аргументом - объектом события.
Аргументы
Имя | Тип | Описание |
---|---|---|
item | object | Отрисованный элемент коллекции |
renderEvent | object | Объект события |
Примеры
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
Аргументы
Имя | По умолчанию | Тип | Описание |
---|---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
indexOrValue | object number | Индекс элемента, который нужно удалить (число) либо удаляемый элемент (объект) |
eventOptions optional | eventOptions | Объект события на случай, если нужно передать в обработчик события какие-нибудь данные или установить служебные флаги (например, |
Примеры
Передача индекса массива
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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
Аргументы
Имя | Тип | Описание |
---|---|---|
selector optional | selector | Селектор |
eventOptions optional | eventOptions | Объект события |
Seemple.Array#toJSON(recursive=true)
→
array
Конвертирует экземпляр Seemple.Array в обычный массив
Метод работает рекурсивно, вызывая toJSON
для входящих объектов, у которых есть метод с таким именем. Для отмены рекурсии передайте false
первым аргументом.
Возвращает array
Аргументы
Имя | По умолчанию | Тип |
---|---|---|
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));
Seemple.Array#isSeempleArray: boolean
isSeempleArray
всегда равен true
для экземпляров Seemple.Array
Примеры
console.log(object.isSeempleArray);
<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>
И свяжет чекбоксы с соответствующими свойствaми 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;
// ...
}
Перемещение объекта из одного массива в другой
По умолчанию, при вставке объекта в массив фреймворк попытается его отрисовать, используя 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
Аргументы
Имя | Тип | Описание |
---|---|---|
arrayLike | object | Массивоподобный или итерируемый объект |
mapFn optional | function | Отображающая функция, вызываемая для каждого элемента массива |
thisArg optional | * | Объект, который используется в качестве |
Ссылки
Примеры
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
Аргументы
Имя | Тип | Описание |
---|---|---|
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 узел.
Свойства
Имя | Тип | Описание |
---|---|---|
on optional | string function | Имя DOM события (или список имен событий, разделенных пробелами), после срабатывания которого извлекается состояние DOM элемента и устанавливается свойство. Кроме этого, значением свойства может быть функция, которая устанавливает обработчик произвольным образом. |
getValue optional | function | Функция, которая отвечает за то, как извлечь состояние DOM элемента |
setValue optional | function | Функция, которая отвечает за то, как установить значение свойства DOM элементу |
initialize optional | function | Функция, которая запускается при инициализации привязки. Например, может быть использована для инициализации jQuery плагина. |
destroy optional | function | Функция, которая вызывается после вызова метода |
Примеры
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?
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
и объявлять остальные привязки...