Почти Ванильный Фронтэнд

от автора

Почти — потому что используется всего две функции из библиотеки:

  1. Создать элемент DOM

  2. Обновить элемент DOM

Эта библиотека упрощает использование нативных функций DOM, таких как createElement и replaceChild. Библиотека Fusor направлена на то, чтобы сделать эти функции проще и компактнее.

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

Оглавление

Установка

npm install @fusorjs/dom 

Или:

Создание и Обновление DOM

import {getElement, update} from '@fusorjs/dom'; import {section, div} from '@fusorjs/dom/html';  let count = 0;  const block = section(   {class: () => (count % 2 ? 'odd' : 'even')},    div('Seconds ', () => count, ' elapsed'),   div('Minutes ', () => Math.floor(count / 60), ' elapsed'), );  document.body.append(getElement(block));  setInterval(() => {   count++;   update(block); }, 1000); 

> запустить пример

Только крохотные части у block дерева DOM обновляются, если они отличаются от текущих значений.

Поддержка JSX

import {getElement, update} from '@fusorjs/dom';  let count = 0;  const block = (   <section class={() => (count % 2 ? 'odd' : 'even')}>     <div>Seconds {() => count} elapsed</div>     <div>Minutes {() => Math.floor(count / 60)} elapsed</div>   </section> );  document.body.append(getElement(block));  setInterval(() => {   count++;   update(block); }, 1000); 

> запустить пример

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

import {getElement, update} from '@fusorjs/dom'; import {section} from '@fusorjs/dom/html';  let count = 0;  const block = section(   {     id: 'set attribute or property automatically',     title_a: 'set attribute',     style_p: 'set property',      focus_e: () => 'set bubbling event handler',     blur_e_capture_once: () => 'set capturing event handler once',      // update dynamic values in this DOM node:     click_e_update: () => count++, // same as     click_e: () => {count++; update(block);}, // same as     click_e: (event, self) => {count++; update(self);},      class: count % 2 ? 'odd' : 'even', // static     class: () => (count % 2 ? 'odd' : 'even'), // dynamic   },    'Static child ', count, ' never changes.',   'Dynamic child ', () => count, ' is wrapped in a function.', );  document.body.append(getElement(block)); 

> запустить пример

Компонент с Состоянием

import {getElement} from '@fusorjs/dom'; import {button, div} from '@fusorjs/dom/html';  const ClickCounter = (count = 0) =>   button({click_e_update: () => count++}, 'Clicked ', () => count, ' times');  const App = () => div(ClickCounter(), ClickCounter(22), ClickCounter(333));  document.body.append(getElement(App())); 

> запустить пример

Версия JSX

import {getElement} from '@fusorjs/dom';  const ClickCounter = ({count = 0}) => (   <button click_e_update={() => count++}>Clicked {() => count} times</button> );  const App = () => (   <div>     <ClickCounter />     <ClickCounter count={22} />     <ClickCounter count={333} />   </div> );  document.body.append(getElement(<App />)); 

> запустить пример

Компоненты в обеих версиях совместимы.

Тот же Компонент Разными Способами

import {button} from '@fusorjs/dom/html';  const ClickCounter = (count = 0) => {   const self = button(     {click_e: () => {count++; update(self);}},     'Clicked ', () => count, ' times',   );    return self; };  const ClickCounter = (count = 0) =>   button(     {click_e: (event, self) => {count++; update(self);}},     'Clicked ', () => count, ' times',   );  const ClickCounter = (count = 0) =>   button(     {click_e_update: () => count++},     'Clicked ', () => count, ' times',   ); 

> запустить пример

Контролируемый Компонент Ввода

Или Controlled Input в терминах React.

import {getElement} from '@fusorjs/dom'; import {input, div} from '@fusorjs/dom/html';  const UppercaseInput = (value = '') =>   input({     value: () => value.toUpperCase(),     input_e_update: (event) => (value = event.target.value),   });  document.body.append(   getElement(     div(UppercaseInput(), UppercaseInput('two'), UppercaseInput('three')),   ), ); 

> запустить пример

Точное Обновление DOM

import {getElement, update} from '@fusorjs/dom'; import {section, div} from '@fusorjs/dom/html';  let count = 0;  const seconds = div('Seconds ', () => count, ' elapsed');  const block = section(   seconds,   div('Minutes ', () => Math.floor(count / 60), ' elapsed'), );  document.body.append(getElement(block));  setInterval(() => {   count++;   update(seconds); // not minutes }, 1000); 

> запустить пример

Это обновит только секунды, а не минуты.

Остановка Рекурсии Обновления

import {getElement, update} from '@fusorjs/dom'; import {section, div} from '@fusorjs/dom/html';  let count = 0;  const seconds = div('Seconds ', () => count, ' elapsed');  const block = section(   () => seconds, // wrapped in a function to escape   div('Minutes ', () => Math.floor(count / 60), ' elapsed'), );  document.body.append(getElement(block));  setInterval(() => {   count++;   update(block); }, 1000); 

> запустить пример

Это обновит только минуты, но не секунды.

Только компоненты (seconds, block) обновляются рекурсивно. () => seconds — это функция, а не компонент.

Каждая функция из @fusorjs/dom/html возвращает компонент, если он содержит динамические значения. То же самое относится и к определениям JSX.

Жизненный Цикл Компонента

  1. Создать компонент

  2. Подключить к DOM

  3. Обновить DOM

  4. Отключить от DOM

import {getElement, update} from '@fusorjs/dom'; import {div} from '@fusorjs/dom/html';  const IntervalCounter = (count = 0) => {   console.log('1. Create component');    return div(     {       mount: (self) => {         console.log('2. Connect to DOM');          const timerId = setInterval(() => {           count++;           update(self);           console.log('3. Update DOM');         }, 1000);          const unmount = () => {           clearInterval(timerId);           console.log('4. Disconnect from DOM');         };          return unmount;       },     },      'Since mounted ', () => count, ` seconds elapsed`,   ); };  const instance = IntervalCounter(); // 1. Create component const element = getElement(instance);  document.body.append(element); // 2. Connect to DOM setTimeout(() => element.remove(), 15000); // 4. Disconnect from DOM 

> запустить пример

> запустить SVG Analog Clock

Автоматическое/Реактивное Обновление

Автоматические/реактивные обновления в больших фреймворках — это не что иное, как реализация паттерна Observable. Это включает в себя State в React, Signals в Solid, Redux, MobX и многие другие. В Fusor вы можете использовать любую из этих библиотек.

Здесь мы обсуждаем универсальное решение:

Библиотека Роутинга

import {update} from '@fusorjs/dom'; import {Observable} from 'Any/Observable/Signal/Redux/Mobx...';  // Modern routing handling const observable = new Observable(); const read = () => location.hash.substring(1); // omit "#" let route = read(); window.addEventListener(   'popstate',   () => {     const next = read();     if (route === next) return;     route = next;     observable.notify();   },   false, );  // Fusor integration export const getRoute = () => route; export const mountRoute = (self) => {   const callback = () => update(self);   observable.subscribe(callback);   return () => observable.unsubscribe(callback); }; 

Реактивный Компонент

Переключение компонентов, когда выбран текущий маршрут.

import {span, a} from '@fusorjs/dom/html'; import {getRoute, mountRoute} from './router';  export const RouteLink = (title, route) =>   span({mount: mountRoute}, () =>     getRoute() === route       ? title // when selected       : a({href: `#${route}`}, title),   ); 

Динамическое Создание и Обновление DOM

import {getElement} from '@fusorjs/dom'; import {ul, li} from '@fusorjs/dom/html'; import {RouteLink} from './RouteLink';  const block = ul(   [...Array(10)].map((v, i) =>     li(RouteLink(`${i + 1}. Section`, `url-to-${i + 1}-section`)),   ), );  document.body.append(getElement(block)); 

> запустить пример

Кеширование и Мемоизация

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

import {div, br} from '@fusorjs/dom/html';  let isVisible = true; // can change  const block = div(   (     (cache = HeavyComponent()) =>     () =>       isVisible && cache   )(),    br(),    () => RecreatedEveryUpdate(), ); 

> запустить пример

Обработка Исключений

import {section, p} from '@fusorjs/dom/html';  const Value = (value) => {   if (value === undefined) throw new Error(`provide a value`);    return p(value); };  const block = section(   p('Before'),    (() => {     try {       return [         Value(1),         Value(), // will throw         Value(3),       ];     } catch (error) {       if (error instanceof Error) return p('Exception: ', error.message);        return p('Exception: unknown');     }   })(),    p('After'), ); 

> запустить пример

Заключение

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

Насколько мне известно, разработка с Fusor — это самый лаконичный, гибкий, легковесный и производительный способ создания фронтенд-приложений.


ссылка на оригинал статьи https://habr.com/ru/articles/897454/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *