📜 ⬆️ ⬇️

defi.js - reactive library based on Object.defineProperty

defi.js

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()) 

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 .



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


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


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


 defi.remove(obj, 'myKey'); 


 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/