defi.js is a library that includes dozens of functions that add interesting features to any JavaScript objects using getters and setters.
Gifka to attract attention (3.5MB)
Repository
As Hello World, we will create a small widget consisting of a name field, a last name and a greeting ( demo ).
<input class="first"> <input class="last"> <output class="greeting"></output>
// данные по умолчанию const obj = { first: 'John', last: 'Doe' }; // слушаем изменения в свойствах first и last // если произошло изменение, сообщим об этом в консоли defi.on(obj, 'change:first', () => console.log('First name is changed')); defi.on(obj, 'change:last', () => console.log('Last name is changed')); // автоматически генерируем приветствие (свойство greeting) каждый раз, // когда first или last изменились defi.calc(obj, 'greeting', ['first', 'last'], (first, last) => `Hello, ${first} ${last}`); // объявляем двусторонний байндинг между свойствами // и соответствующими элементами на странице defi.bindNode(obj, { first: '.first', last: '.last', greeting: '.greeting' });
As a result, if first
or last
have changed, event handlers report this to the console, the greeting
property is automatically updated, and its element gets a new value (by default, "Hello, John Doe"). This happens every time the properties change, and it doesn't matter how. You can set the value using the code obj.first = 'Jane'
, or by changing the value of the field, and all other changes will occur automatically.
In case there is a need to synchronize the properties of the object and the innerHTML
an arbitrary HTML element (in the example we used the output
tag), the bindNode
function bindNode
be passed to the so-called binder, which is responsible for synchronizing the state of the element and the properties of the object. By default, bindNode
does not know how to work with nodes that are not form elements.
const htmlBinder = { setValue: (value, binding) => binding.node.innerHTML = value, }; // изменение свойства obj.greeting обновит innerHTML любого элемента defi.bindNode(obj, 'greeting', '.greeting', htmlBinder)
In addition, you can use html
from the common-binders library (this is a collection of general purpose binders ).
const { html } = require('common-binders'); // изменение свойства obj.greeting обновит innerHTML любого элемента defi.bindNode(obj, 'greeting', '.greeting', html())
Detailed documentation for all methods, available call variations, flags, etc. can be found at defi.js.org . It is worth mentioning that in addition to the methods below, defi.js has a library for routing: defi-router .
// обычное использование // (для стандартных HTML5 элементов форм, см. defaultBunders) defi.bindNode(obj, 'myKey', '.my-element'); // кастомный байндинг defi.bindNode(obj, 'myKey', '.my-element', { // событие, которое говорит об изменении элемента // (можно использовать функцию для не-DOM событий) on: 'click', // как извлечь текущее состояние элемента? getValue: ({ node }) => someLibraryGetValue(node), // как установить состояние элемента при изменении свойства? setValue: (v, { node }) => someLibrarySetValue(node, v), // как инициализировать элемент (библиотеку или виджет)? // это можно сделать любым способом // но 'initialize' добавляет немного синтаксического сахара initialize: ({ node }) => someLibraryInit(node), }); obj.myKey = 'some value'; // обновит элемент
defi.calc(obj, 'a', ['b', 'c'], (b, c) => b + c); obj.b = 1; obj.c = 2; console.log(obj.a); // 3
defi.mediate(obj, 'x', value => String(value)); obj.x = 1; console.log(obj.x); // "1" console.log(typeof obj.x); // "string"
defi.on(obj, 'change:x', () => { alert(`obj.x now equals ${obj.x}`); }); obj.x = 1;
defi.off(obj, 'change:x bind');
defi.on(obj, 'foo bar', (a, b, c) => { alert(a + b + c); }); defi.trigger(obj, 'foo', 1, 2, 3); // вызывает alert(6)
defi.bindNode(obj, 'myKey', '.my-element'); defi.unbindNode(obj, 'myKey', '.my-element');
defi.bindNode(obj, 'myKey', '.my-element'); const node = defi.bound(obj, 'myKey'); // вернет document.querySelector('.my-element')
defi.chain(obj) .calc('a', 'b', b => b * 2) .set('b', 3) .bindNode('c', '.node');
bindNode
to bind custom elements and properties without explicitly specifying a binder. defi.defaultBinders.unshift(element => { // если у элемента есть класс "foo" if(element.classList.contains('foo')) { // значит, нужно использовать этот байндер return { on: ..., getValue: ..., setValue: ... }; } }); // ... defi.bindNode(obj, 'myKey', '.foo.bar');
defaultBinders
functions. const element = document.createElement('input'); element.type = 'text'; console.log(defi.lookForBinder(element));
defi.remove(obj, 'myKey');
change:KEY
event handler. You can also make the setting of the property value "silent", that is, do not call change:KEY
at all. defi.set(obj, 'myKey', 3, { silent: true });
defi.js is a revised and simplified hard fork of the Matreshka.js framework, which included the rendering of arrays, several classes and more methods. Some methods that could potentially fall into defi.js have been replaced with options to other methods, for example, instead of once
and onDebounce
you can use the on
method, passing the options once: true
or debounce: number
.
Thank you for reading to the end. Have a nice day, everyone.
Source: https://habr.com/ru/post/436778/