|||
Общее
Введение
BOToD — Библиотека для двустороннего реактивного связывания JavaScript данных с DOM элементами. Для отслеживания Object он лениво-рекурсивно оборачивается в Proxy. Это значит, что вложенные Object'ы и массивы будут заменены на свои Proxy только при необходимости. Вся реализация происходит в коде, нет никаких биндингов в HTML.Быстрый старт
Подключаем библиотекуСейчас, и наверное далее, будет использоваться только CDN для подключения библиотеки
<script src="https://cdn.jsdelivr.net/gh/Graff46/BOToD@latest/src/BOToD.js"></script>
Создаем экземпляр приложения:
const myApp = App();
Создаем прокси объекта с данными:
const obj = {
key: {
k1: {
l1: {m1: 1, m11: 2,}
},
},
one: {
k2: {
l2: {m2: 22,}
}
},
two: 5,
};
const myApp = App();
const appData = myApp.buildData(obj);
Создадим привязку поля объекта с текстовым элементом.Аргументы:
- Селектор или сам DOM элемент
- Функция возвращающая значение из JS объекта к которому привязываемся
myApp.bind('.txt-input', x => appData.key.k1.l1.m1);
Создадим input элементы по количеству элементов в массиве (объекте) и каждому новому элементу будет установлен атрибут valueАргументы:
- Селектор или сам DOM элемент
- Функция возвращающая итерируемый объект по которому будем повторять выше указанный DOM элемент
- Функция возвращающая значение из JS объекта к которому привязываемся, в данном случае эта функция имеет первый аргумент - ключ объекта который будет использован на этапах создания копии DOM элемента
myApp.repeat('div.input-block > input', x => appData.k1.l1, k => appData.k1.l1[k]);
Основы
Создание экземпляра приложения
После того, как библиотека будет подключена в глобальной области видимости появится функция App, которая возвращает экземпляр приложения.Следите за тем, чтобы не переназначить идентификатор App в глобальной области видимости
const myApp = App();
const myApp = App(App.eventTypeInput | App.textContent);
const myApp2 = App(App.eventTypeInput + App.textContent);
При создании экземпляра приложения можно задать настройки определяющие правила работы данного экземпляра приложения. Указание настроек осуществляется путём указания флагов в аргументах функции App указанной выше. Идентификаторы флагов доступны как статические свойства объекта функции App. На данный момент доступны следующие флаги:
- eventTypeInput — устанавливает тип обработчиков событий на связанных элементах в input. Иначе будет установлено change
- textContentBinding — устанавливает привязку к textContent DOM элемента. Иначе установлено в value
Создание отслеживаемого объекта
Для обеспечения реактивности библиотека использует Proxy. Поэтому, чтобы отслеживать изменения в объекте, необходимо его обернуть в Proxy. Для этого используется метод экземпляра приложения: buildDataconst data = {key: {k1: {l1: {m1: 1, m11: 2}}}};
const myApp = App();
const appData = myApp.buildData(data);
Связывания
bind
Простое двустороннее связывание. Отслеживает изменение поля объекта (массива) и меняет свойство value или textContent DOM элемента. Если поменять значение в DOM элементе - то изменится связанное поле объекта соответственно.Аргументы:
- Селектор или сам DOM элемент
- Функция возвращающая значение из JS объекта к которому привязываемся
const myApp = App();
const appData = myApp.buildData({key: {k1: {l1: {m1: 1, m11: 2}}}});
myApp.bind('.txt-input', () => appData.key.k1.l1.m1);
Возможен такой вариант:
const myApp = App();
const appData = myApp.buildData({key: {l1: {m1: 1, m11: 2}}});
const obj = appData.key.l1;
const elm = document.querySelector('.txt-area');
myApp.bind(elm, () => obj.m1);
xrBind
Расширенное двустороннее связывание. Принцип действия аналогичен bind.Аргументы:
- Селектор или сам DOM элемент
- Функция возвращающая значение из JS объекта к которому привязываемся
- Функция-коллбэк которая выполняется при изменении значения JS объекта, также данная функция выполнится сразу. Аргументы:
- DOM элемент из 1-го аргумента данного метода
- Функция-коллбэк которая выполняется при изменении значения DOM объекта. Допускается пропустить данный аргумент, в этом случае обработка событий DOM объекта отсутствует, что можно использовать для "облегчения" кода. Аргументы:
- DOM элемент из 1-го аргумента данного метода
- Значение поля JS объекта которое было ранее привязано
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});
myApp.xrBind('.txt-area', () => appData.m1, el => el.value = appData.m1, (el, val) => el.value = val);
repeat
Метод копирования DOM объекта по количеству элементов итерируемого объекта, также устанавливает привязки.Аргументы для реализации с тремя аргументами:
- Селектор или сам DOM элемент
- Функция возвращающая JS итерируемый объект
- Коллбэк аналогичен 3-му аргументу bind (вызывается на каждой итерации). Аргументы:
- Ключ объекта (массива) который используется в итерации
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});
myApp.repeat('.list-input', x => appData.key, k => appData.key[k]);
Аргументы для реализации с четырьмя аргументами (аналогично xrBind):
- Селектор или сам DOM элемент
- Функция возвращающая JS итерируемый объект
- Коллбэк аналогичен 3-му аргументу xrBind (вызывается на каждой итерации). Аргументы:
- DOM элемент созданный на данной итерации
- Ключ объекта (массива) который используется в итерации
- Коллбэк аналогичен 4-му аргументу xrBind (вызывается на каждой итерации). Аргументы:
- DOM элемент созданный на данной итерации
- Значение поля JS объекта которое было ранее привязано
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});
myApp.repeat('.i2', x => appData.m1, (el, k) => el.value = appData.key[k], (el, k) => appData.key[k] = el.value);
Есть варианты использовать данный метод для создания элементов без привязок и реактивности:
- Для того чтобы отсутствовала привязка между созданными DOM объектами и полем итерируемого JS объекта для этого нужно 4-м аргументом передать false
- Для того чтобы отсутствовала привязка по итерируемому JS объекту (количество полей объекта меняется соответственно меняется количество создаваемых DOM элементов) для этого нужно 4-м аргументом передать null или использовать неотслеживаемый JS объект в 1-м аргументе (см. Важные заметки). Стоит учесть, что данный функционал также ведёт к отсутствию реактивности в пункте выше
Развязывания
unbind
Удаление и перезапись полей объекта не приводит к удалению связываний с этими полями! Данный метод используется для снятия связываний с JS объекта или DOM элемента.Аргументы:
- JS объект или DOM элемент c которого убираем прявязки
- Булевый флаг. При true удаляются привязки кроме привязок repeat
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});
myApp.repeat('.i2', x => appData.key, (el, k) => el.value = appData.key[k], (el, k) => appData.key[k] = el.value);
myApp.bind('input#cd', () => appData.key.m11);
myApp.unbind('input#cd'); // unbind from an DOM element
myApp.unbind(appData.key); // unbind from an JS Object
Важные заметки
Не используйте аргументы в методах и функциях всверх тех, что указаны в данном руководстве!
В методах xrBind и repeat с 4 аргументами: в аргументе-функции в которой указываем привязку DOM элемента к JS данным (3-й аргумент) нужно в коде читать поле JS объекта, чтобы сработал перехват Proxy и связал нужное поле JS объекта. Этого можно не делать, тогда будет отсутствовать привязка JS данных с DOM объектом.
Можно использовать все методы для заполнения данными DOM элементов без каких либо привязок и реактивности, достаточно использовать в качестве источника данных неотслеживаемый JS объект (не использовать App.buildData)
Если удалить дочерний JS объект оператором delete, то отвязки биндингов не будет.
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});
myApp.bind('input#cd', () => appData.key.m11);
setTimeout(() => delete appData.key.m11, 2000);
setTimeout(() => appData.key = {m11: 55}, 2000)
В вышепоказанном коде через 2 секунды значение DOM элемента будет сброшено, а еще через 2 секунды значение DOM элемента будет 55.