defi.js - reactive library based on Object.defineProperty

  • Tutorial
defi.js

defi.js is a library that includes a dozen 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 ).


<inputclass="first"><inputclass="last"><outputclass="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 firstor lastchanged, event handlers report this to the console, the property is greetingautomatically 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 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 innerHTMLan arbitrary HTML element (in the example we used the tag output), the function bindNodemust be passed to the so-called "binder", which is responsible for how to synchronize the state of the element and the properties of the object. By default, it bindNodedoes 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 htmlthe 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())

API methods


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 .


  • bindNode — Binds a property of an object and a DOM node for bidirectional bidding.

// обычное использование // (для стандартных 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'; // обновит элемент

  • calc - Creates the dependence of one property of an object on other properties (including from other objects).

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

  • mediate - Modifies the value of a property when it changes.

defi.mediate(obj, 'x', value => String(value));
obj.x = 1;
console.log(obj.x); // "1"console.log(typeof obj.x); // "string"

  • on - Adds an event handler. There is a short article on the documentation site that describes all possible events.

defi.on(obj, 'change:x', () => {
    alert(`obj.x now equals ${obj.x}`);
});
obj.x = 1;

  • off - Removes an event handler.

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)

  • unbindNode Disables the binding of an element and the DOM node.

defi.bindNode(obj, 'myKey', '.my-element');
defi.unbindNode(obj, 'myKey', '.my-element');

  • bound - Returns the DOM element associated with the given property.

defi.bindNode(obj, 'myKey', '.my-element');
const node = defi.bound(obj, 'myKey'); // вернет document.querySelector('.my-element')

  • chain - Used to chain the defi.j functions.

defi.chain(obj)
    .calc('a', 'b', b => b * 2)
    .set('b', 3)
    .bindNode('c', '.node');

  • defaultBinders - An array of functions that return the corresponding binder or undefined. Allows you bindNodeto link custom elements and properties without explicitly specifying the binder.

defi.defaultBinders.unshift(element => {
    // если у элемента есть класс "foo"if(element.classList.contains('foo')) {
        // значит, нужно использовать этот байндер return {
            on: ...,
            getValue: ...,
            setValue: ...
        };
    }
});
// ...
defi.bindNode(obj, 'myKey', '.foo.bar');

  • lookForBinder - Returns the binder corresponding to the element, if any, returned by one of the functions defaultBinders.

const element = document.createElement('input');
element.type = 'text';
console.log(defi.lookForBinder(element));

  • remove - Removes the property of an object and the corresponding event handlers.

defi.remove(obj, 'myKey');

  • set - Sets a property of an object, like a setter, but it gives the opportunity to pass some data to an event handler change:KEY. You can also make the setting of the property value "silent", i.e. not call change:KEYat all.

defi.set(obj, 'myKey', 3, { silent: true });



defi.js is a reworked 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 onceand onDebounceyou can use the method onby passing options once: trueor debounce: number.


Thank you for reading to the end. Have a nice day, everyone.


Also popular now: