Как улучшить свои навыки JavaScript, написав свою систему веб-разработки

kak uluchshit svoi navyki javascript napisav svoyu sistemu veb razrabotki

Вы когда-нибудь спрашивали себя, как работает фреймворк?

Когда я открыл AngularJS после изучения jQuery много лет назад, AngularJS показался мне темной магией.

Затем вышел Vue.js, и, проанализировав, как он работает под капотом, меня поощрили попытаться написать мою собственную двустороннюю систему связывания.

В этой статье я покажу вам, как написать современный фреймворк JavaScript с пользовательскими атрибутами HTML, реактивностью и двойным связыванием.

Как работает реактивность?

Было бы хорошо начать с понимания того, как работает реактивность. Хорошая новость состоит в том, что это просто. В самом деле, когда вы объявляете новый компонент в Vue.js, фреймворк будет проксифицировать каждое свойство (гетеры и сеттеры) с помощью шаблона проектирования прокси.

Таким образом, он сможет обнаружить изменения значения свойств как по коду, так и по введенным пользователями.

Как выглядит шаблон дизайна прокси

Идея шаблона прокси состоит в том, чтобы просто перегрузить доступ к объекту. Аналогией в реальной жизни может быть доступ к вашему банковскому счету.

Например, вы не можете напрямую получить доступ к балансу вашего банковского счета и изменить значение в соответствии с вашими потребностями. Вам необходимо спросить кого-нибудь, кто имеет это разрешение, в данном случае ваш банк.

var account = {
	balance: 5000
}

// A bank acts like a proxy between your bank account and you
var bank = new Proxy(account, {
    get: function (target, prop) {
    	return 9000000;
    }
});

console.log(account.balance); // 5,000 (your real balance)
console.log(bank.balance);    // 9,000,000 (the bank is lying)
console.log(bank.currency);   // 9,000,000 (the bank is doing anything)

В приведенном выше примере при использовании bank объект для доступа к account баланса, функция геттера перегружена, и она всегда возвращается 9,000,000 вместо значения свойства, даже если свойство не существует.

// Overload setter default function
var bank = new Proxy(account, {
    set: function (target, prop, value) {
        // Always set property value to 0
        return Reflect.set(target, prop, 0); 
    }
});

account.balance = 5800;
console.log(account.balance); // 5,800

bank.balance = 5400;
console.log(account.balance); // 0 (the bank is doing anything)

За счет перегрузки set функции, можно манипулировать ее поведением. Вы можете изменить значение, чтобы обновить другое свойство или даже ничего не делать.

Пример реактивности

Теперь, когда вы уверены в том, как работает шаблон дизайна прокси, давайте приступим к написанию нашего JavaScript-фреймворка.

Чтобы было просто, мы будем имитировать синтаксис AngularJS для этого. Объявить контроллер и привязать элементы шаблона к свойствам контроллера достаточно просто.

<div ng-controller="InputController">
    <!-- "Hello World!" -->
    <input ng-bind="message"/>   
    <input ng-bind="message"/>
</div>

<script type="javascript">
  function InputController () {
      this.message="Hello World!";
  }
  angular.controller('InputController', InputController);
</script>

Сначала определите контроллер со свойствами. Затем используйте этот контроллер в шаблоне. Наконец, воспользуйтесь ng-bind атрибут, чтобы включить двойное связывание со значением элемента.

Проанализируйте шаблон и создайте экземпляр контроллера

Чтобы обладать свойствами для привязки, нам нужно получить место (он же контроллер) для объявления этих свойств. Таким образом, необходимо определить контроллер и ввести его в наш фреймворк.

Во время объявления контроллера фреймворк будет искать элементы ng-controller атрибуты.

Если он соответствует одному из объявленных контроллеров, он создаст новый экземпляр этого контроллера. Этот экземпляр контроллера отвечает только за конкретный фрагмент шаблона.

var controllers = {};
var addController = function (name, constructor) {
    // Store controller constructor
    controllers[name] = {
        factory: constructor,
        instances: []
    };
    
    // Look for elements using the controller
    var element = document.querySelector('[ng-controller=" + name + "]');
    if (!element){
       return; // No element uses this controller
    }
    
    // Create a new instance and save it
    var ctrl = new controllers[name].factory;
    controllers[name].instances.push(ctrl);
    
    // Look for bindings.....
};

addController('InputController', InputController);

Вот что ручная работа controllers Объявление переменной выглядит следующим образом. The controllers объект содержит все контроллеры, объявленные в рамках вызова addController.

1*li6MNxPJEvE6BdgNwAQgwg
Определение контроллеров ручной работы

Для каждого контроллера factory функция сохраняется для создания экземпляра нового контроллера, когда это необходимо. Фреймворк также хранит каждый из новых экземпляров того же контроллера, который используется в шаблоне.

Ищу привязки

На этом этапе у нас есть экземпляр контроллера и фрагмент шаблона, который использует этот экземпляр.

Следующим шагом является поиск элементов с привязками, которые используют свойства контроллера.

var bindings = {};

// Note: element is the dom element using the controller
Array.prototype.slice.call(element.querySelectorAll('[ng-bind]'))
    .map(function (element) {
        var boundValue = element.getAttribute('ng-bind');

        if(!bindings[boundValue]) {
            bindings[boundValue] = {
                boundValue: boundValue,
                elements: []
            }
        }

        bindings[boundValue].elements.push(element);
    });

Достаточно просто, он сохраняет все привязки объекта (используется как хэш-карта). Эта переменная содержит все свойства, которые нужно связать с текущим значением, и все элементы DOM, связывающие это свойство.

1*4-mQb0bbJwzdZQZsgOqb-g
Декларация о привязках ручной работы

Свойства контроллера двойного связывания

После того, как предыдущая работа была выполнена фреймворком, теперь наступает интересная часть: двойная связка.

Он включает привязывание свойства контроллера к элементам DOM для обновления DOM каждый раз, когда код обновляет значение свойства.

Также не забудьте привязать элементы DOM к свойству контроллера. Таким образом, когда пользователь изменяет введенное значение, он обновляет свойство контроллера. Затем он также обновит все остальные элементы, связанные с этим свойством.

Обнаружение обновлений из кода с помощью прокси

Как объяснялось выше, Vue оборачивает компоненты в прокси-сервере, чтобы реагировать на изменения свойств. Давайте сделаем то же самое, прокси-серверируясь только для свойств, связанных с контроллером.

// Note: ctrl is the controller instance
var proxy = new Proxy(ctrl, {
    set: function (target, prop, value) {
        var bind = bindings[prop];
        if(bind) {
            // Update each DOM element bound to the property  
            bind.elements.forEach(function (element) {
                element.value = value;
                element.setAttribute('value', value);
            });
        }
        return Reflect.set(target, prop, value);
    }
});

Каждый раз, когда установлено связанное свойство, прокси-сервер проверит все элементы, связанные с этим свойством. Затем он обновит их новым значением.

В этом примере мы поддерживаем только введение элементы связывания, потому что только value атрибут установлен.

Реагировать на события элемента

Остальное, что нужно сделать, это реагировать на взаимодействие пользователя. Элементы DOM вызывают события, когда обнаруживают изменение значения.

Прослушайте эти события и обновите соответствующее свойство с помощью нового значения события. Все остальные элементы, связанные с таким же свойством, автоматически обновляются благодаря прокси.

Object.keys(bindings).forEach(function (boundValue) {
  var bind = bindings[boundValue];
  
  // Listen elements event and update proxy property   
  bind.elements.forEach(function (element) {
    element.addEventListener('input', function (event) {
      proxy[bind.boundValue] = event.target.value; // Also triggers the proxy setter
    });
  })  
});

После того, как вы собрали все вместе, вы получите входные данные ручной работы с двойным связыванием. Вот рабочая демонстрация, включающая весь код.

Спасибо, что читаете. Надеюсь, это помогло вам разобраться в том, как работают фреймворки JavaScript.

Поздравляю! Вы разработали такие популярные функции, как пользовательские атрибуты HTML-элементов, реактивность и двойное связывание!

Если вы нашли эту статью полезной, пожалуйста, нажмите на ? нажмите несколько раз, чтобы другие нашли статью и выразили свою поддержку! ?

Не забудьте подписаться на меня, чтобы получать уведомления о моих будущих статьях ?

https://www.freecodecamp.org/news/author/jbardon/

➥ Реакция для начинающих

➥ JavaScript

Добавить комментарий

Ваш адрес email не будет опубликован.