Comments 30
Кажется, вы изобрели Solid.js, только со слотами
Как мы пытались сделать фреймворк для фронтенда которого можно выучить за 5 минут и что из этого вышло
Что-то с падежом напутали
Русский не мой родной язык, так что может быть ошибки, я пока что не понимаю какой падеж напутал.
Кстати, если вам сложно, используйте профридеры - приложения, которые подсвечивают ошибки в тексте и исправляют по нажатию кнопки. В основном они умеют объяснять причины исправлений. Я вот, например, английские тексты так правлю. А то знаний мало и пишу как селянин, меня очень выручает.
Очередной Фреймворк, который ничего нового не делает. Можно было взять существующий и не тратить зря деньги бизнеса.
Оставлю тут пример компонента счетчика нажатий на своей библиотеке. Если ваш фреймворк имеющий стейт-менеджер и шаблонизатор для циклов и условий и который учится за 5 минут, то моя библиотека не имеющая ничего этого должна учиться за 2 минуты, ЛОЛ.
const ClickCounter = ({count = 0}) => (
<button click_e_update={() => count++}>Clicked {() => count} times</button>
);
По этому коду тут вопросов очень много:
{count = 0}почему состояние это поле объекта в параметре функций?click_e_updateчто означаетe_update? Как добавить обработчик дляtouchstartнапример?Clicked {() => count} times- для чего тут функция если это шаблон и по идею встроим значение?
Тот же пример у нас:
const ClickCounter = component(() => {
let $count = 0;
<button onclick={() => $count++}>Clicked {$count} times</button>;
});
{count = 0}- это деструктурирование параметров функции, где мы получаем переменнуюcountсо значение по умолчанию0click_e- означает установка обработчика событий, для события можно добавлять модификаторы, например:touchstart_e_capture_once_update. Помимо событий есть еще модификаторы для атрибутов и пропсов. Все это сделано чтобы в полной мере отражать спецификацию W3C стандарта.Clicked {() => count} times- функция тут нужна чтобы подставлять в DOM динамически значения при вызове фукцииupdateкоторая декларируется в нашем модификаторе. Также можно явно ее вызывать как описано тут. Статическое значение можно было вставить не оборачивая в функцию.
Также существует альтернативный (не JSX) синтаксис:
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()));
Вот стандарт: https://dom.spec.whatwg.org/#eventtarget в нём чётка указано что обработчик события устанавливается тремя параметрами: тип события, обработчик и опции. Вот часть стандарта https://html.spec.whatwg.org/multipage/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects которая описыввает какие атрибуты у элемента под какие типы события, соответственно нам остаётся указать 1 или 2 параметра. примеры:
<button onclick={() => $count++}>Clicked {$count} times</button>
<button onclick={[() => $count++, true]}>Clicked {$count} times</button>
<button onclick={[() => $count++, {capture: true, once: true}]}>Clicked {$count} times</button>
И вот такое как раз и соответствует стандартам, а вот эти хитроумные свойства надо выучить. Понимаешь разницу в подходе?
Модификатором проще это делать, в вашем способе также надо разобраться, хотя ваш способ тоже интересный, возвращение тюпла, во Фьюзоре примерно также можно сделать:
click_e={{
handle: (event, self) => 'Clicked!',
capture: true,
once: true,
passive: true,
signal: AbortSignal,
update: true, // update target component after event handler completes
}}
Другое дело что во Фьзоре помимо эвентов поддерживаются еще и другие типы модификаторов
a-attributean-attributenamespacedp-propertyps-propertystatice-event handler
Но мы тут уходим в детали синтаксиса, который легко подправить. Главное отличие Фьюзора - то что это библиотека, она не имеет встроенного стейт-менеджера, и позволяет все делать ЯВНО.
Я не говорил что так хуже, а то что это всё надо выучить, особенно пугает ручное обновление компонента. Ещё мне непонятно будет ли Typescript это проверять, IDE предлагать авто-дополнение этих названий и сколько всего вариантов там в списке будут.
Автроматическое обновление подключается на пропсу mount. Причем можно использовать лучший алгоритм для каждого компонента, а не один "средний" для всех. Поддержка Typescript есть на сколько хватило моих в нем компетенции - уверен что можно допилить ее на много лучше, также как и автодополнения IDE.
FYI @artptr86
Это довольно интересный подход.
В реальном приложении тогда будут тысячи рукописных маунтов для всех реактивных переменных. Этот код писать нудно и неудобно. Кроме того, реактивные фреймворки позволяют изменять текстовые ноды, а в Фузоре можно обновить только ноду тега со всеми дочерними. Но самое главное: в показанном примере есть утечка памяти: маунт подписывается на обновление переменной, но никогда не отписывается. В памяти также останется сохранённый в замыкании self.
Достаточно будет написать одну функцию "маунтер" для каждой библиотеки стейт менеджера, и проблема решена, тем более это очень простая функция - одна строка в примере.
Добавить обновление только для текстовых нод без элемента, есть такая идея, но пока в реальных кейсах не пригождалось, нужно собрать больше данных в каких сценариях это может быть полезно.
Если вы приглядитесь к примеру, то обнаружите функцию usubscribe, которая передается в mount, которая в свою очередь и вызовет ее на событии unmount. Так что нет утечки.
Для чего вообще кому-то может быть нужна библиотека для создания счётчиков нажатий?
Это такой тренд, почти на всех сайтах фреймворках находится этот пример, он простой и даёт первичное впечатление о том как строится компоненты. А сам счётчик можешь найти на маркетплейсах когда нажимаешь кнопку "Добавить в корзину".
Прикол в том что эта библиотека всего лишь абстракция над document.createElement без стейт менеджмента. Но тем не менее она может делать все то же самое, что делают "большие" фреймворки, потребляя в разы меньшие ресурсы. Там есть также два полноценных приложения.
Объясните пожалуйста, зачем нужны псевдокомпоненты If, Else, ElseIf и For?
Ведь у нас внутри компонента уже есть JavaScript (или TypeScript), которые имеют if, else, for и весь арсенал для проверок/ветвлений и обхода циклов?
Я не веб-разработчик, так, для десктопа пишу, мне действительно не очевидно
С большим удовольствием отвечаю, я сам разработчик C++ Qt (middle) по этому отлично понимаю ваше недоразумение.
Больше всего писал на QML, это всё по сути заменяет такие компоненты в нём как Loader и Repeater.
Когда используешь более классический способ у тебя есть доступ к указателя на каждый Layout и в нём можно что-то добавить и удалить без проблем, это работает на основе архитектуры MVC. Да и там всё равно есть различные ListView, TableView и подобные.
В моём фреймворке используется архитектура MVVM, по этому любые изменения на экраны идут через так называемые биндинги, т.е. меняешь данные и интерфейс сам обновляется, в таком случае программист не имеет необходимость в прямой доступ к составляющих интерфейса (а сам доступ он есть).
Собственно потому, что функция компонента исполняется всего один раз для его конструирования, а все зависимости от данных внутри него перевычисляются реактивно. Поэтому, например, псевдокомпонент If декларативно задаёт, что показывать его детей нужно по изменению соответствующей переменной, а For — что дочерний компонент нужно итерировать (причём по возможности переиспользуя существующие элементы) согласно переданному массиву.
А вот в React, в котором функция компонента вызывается каждый раз при изменении данных, действительно используются встроенные в JS возможности для циклов и условий.
Проект с открытым исходным кодом, но не знаю, будет ли публикация его названия считаться рекламой.
Спасибо за статью, хотелось бы ещё увидеть ссылку на гитхаб например чтобы поиграться (обычно на хабре делятся такой ссылкой)
Сейчас идёт ребрэндинг, изначально проект не имел по сути название, пару дней назад только что наконец-то придумал. Но код и документацию можно посмотреть тут: https://github.com/vasille-js/vasille-js
Как мы пытались сделать фреймворк для фронтенда которого можно выучить за 5 минут и что из этого вышло