Как стать автором
Обновить

Связывание DOM-элементов и объектов JS в 42 строки

Уровень сложностиПростой

Недавно я начал заниматься разработкой собственного JS фреймворка подобного Angular'у, тут конечно я описывать не буду как он работает и как на нем писать SPA, но хотелось бы поделиться примером, как я реализовал управление состоянием и связывание DOM и JS.

Начнем с HTML странички:

<h1 bind="name">name</h1>
<input type="text" placeholder="Your name..." bind="name" />
<h1 bind="age">age</h1>
<input type="text" placeholder="Your age..." bind="age" />

Из компонента мы имеем состояние по умолчанию (initial state) в виде константы componentState.


const componentState = {
  name: 'no name', 
  age: 0
}
const target = {};
const handler = {
  get: function(target, prop) {
    return target[prop];
  },
  set: function(target, prop, value) {
    updateElements(prop, value)
    return target[prop] = value
  }
};
const state = new Proxy(target, handler);
function updateElements(prop, value) {
  var els = document.querySelectorAll(`[bind='${prop}']`)
  els.forEach(el => {
    if(el.nodeName === 'INPUT' || el.nodeName === 'TEXTAREA') el.value = value
    else el.textContent = value
  })
}
function initBinds(prop, value){
  var elems = document.querySelectorAll(`[bind='${prop}']`)
  elems.forEach(el => {
    if(el.nodeName === 'INPUT' || el.nodeName === 'TEXTAREA') {
      el.value = value
      el.addEventListener('input', (e) => {
        state[prop] = e.target.value
      })
    }
    else el.textContent = value
  })
}
function reactivity(){
  var keys = Object.keys(componentState)
  keys.forEach(key => {
    initBinds(key, componentState[key])  
  })
}
reactivity()

Из приведенного выше кода мы видим, что в константе handler, объявлены сеттер и геттер, которые через класс Proxy реагируют на чтение и запись данных, а далее объявлена константа state, которая как раз и будет творить чудеса. Как мы видим, что геттер просто возвращает содержимое, а вот сеттер как раз выполняет обновление данных как в объекте JS, так и в DOM с помощью функции updateElements, соответственно чтобы все заработало, нам необходимо связать объект state и объект состояния из компонента, что и делает функция initBinds. Ну а функция reactivity просто переберает первичные состояния из компонента и кормит их функции initBinds.

Тем самым у нас выходит, что когда например мы вводим в поле ввода

<input type="text" placeholder="Your name..." bind="name" />

у нас изменяется state, ну и само собой и заголовок.

<h1 bind="name">name</h1>

Вот и вся магия JS и кастомных атрибутов HTML.

P.S. Говорю сразу, что опыта в написании статей у меня нет и стаж в программировании у меня небольшой, т.ч. камнями не бросайте. У кого есть желание, то предлагайте решения по оптимизации или улучшению кода.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.