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

  1. Как создавать свои собственные компоненты
  2. Как создавать приложения (плюс руководства по архитектуре)

Я думаю, что это руководство - хорошее сочетание: оно не слишком продвинутое (мы говорим о 240 строках кода) и не тривиальное (даже профессионалы Javascript, скорее всего, могут узнать что-то новое).

Следуя концепции «работник приложения - главный действующий субъект», экземпляры Fieldset будут находиться внутри области действия веб-воркера приложения.

Содержание

  1. Требования
  2. Демо-видео
  3. Выбор правильного базового класса
  4. Создание примера приложения
  5. Создание класса компонента Legend
  6. Добавление легенды в наш Fieldset
  7. Регулировка свернутого состояния
  8. Тематика
  9. Онлайн-демонстрация
  10. Последние мысли

1. Требования

  • Набор полей может содержать любое количество дочерних компонентов любого типа.
  • При желании он может быть сворачиваемым (в том числе для изменения этого параметра во время выполнения).
  • Мы можем его динамически расширять и сворачивать.
  • Свернутые элементы удаляются из DOM.
  • Свернутые элементы при желании можно отключить.
  • Мы не хотим уничтожать экземпляры элементов при сворачивании (чтобы избежать утечки памяти).
  • Мы хотим иметь возможность изменять состояние дочерних элементов, даже когда Fieldset свернут.
  • Мы хотим использовать разные темы (стили).

2. Демо-видео

Я создал видео 44 с, чтобы было более понятно, о чем мы будем говорить:

3. Выбор правильного базового класса

Одним из прекрасных аспектов ООП является то, что мы можем выбрать базовый класс, который имеет наибольший смысл. Он не обязательно должен быть компонентным, самый низкий уровень - core.Base (например, если вы хотите создать маршрутизатор или модель выбора).

Для нашего Fieldset выбор прост: мы хотим содержать дочерние элементы и иметь возможность использовать разные макеты, поэтому мы выбираем container.Base.

Наша первая версия выглядит так: (src / form / Fieldset.mjs)

Интересный факт: эта версия уже функционирует, но, конечно, еще не покрывает все требования.

Сначала мы собираемся импортировать наш базовый класс.

neo.mjs использует три разных окружения:

  1. разработка (запускается непосредственно в вашем браузере)
  2. dist / development (сборка на основе webpack. это то, что вы называете режимом разработки в Angular или React)
  3. dist / production (сборка на основе веб-пакетов, минимизированная, без исходных карт)

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

Мы помещаем наши конфигурации в метод static getConfig(), который реализует преимущества системы конфигурации классов. Перед экспортом нашего класса нам нужно вызвать Neo.applyClassConfig(), чтобы наши конфигурации были разумно назначены прототипу класса.

Использование className обязательно. Значение этой конфигурации будет присвоено пространству имен, поэтому вы можете использовать Neo.form.Fieldset для доступа к классу.

Конфигурация ntype не является обязательной. По умолчанию он будет использоваться для создания идентификаторов экземпляров. Например. neo-fieldset-1. Этот идентификатор является идентификатором экземпляра JS, а также идентификатором DOM нашего виртуального корневого узла.

Мы добавляем конфигурацию cls, так как хотим использовать механизм тем для применения стилей.

Для контейнера конфигурация виртуального dom:

_vdom: {tag: 'div', cn: []}

Мы изменили его, чтобы вместо него использовать тег fieldset.

4. Создание примера приложения.

Уже на этом этапе я настоятельно рекомендую создать следующий пример приложения.

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

Если вы работаете в репозитории neo.mjs, вы можете скопировать существующую папку примеров или использовать сценарий create-app внутри package.json.

Примеры кода MainContainer.mjs:

Это (последняя) демонстрация, которая показана внутри видео. В нем уже есть элементы управления функциями, которые мы собираемся добавить дальше.

5. Создание класса компонента легенды.

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

Мы можем многому научиться из этого крошечного файла.

Он имеет три конфигурации с завершающим символом подчеркивания: iconCls_, text_ и useIcon_. Использование подчеркивания дополнительно позволяет нам использовать следующие методы (примеры для iconCls):

  1. beforeGetIconCls(value) // модифицируем геттер
  2. beforeSetIconCls(value) // предварительная обработка
  3. afterSetIconCls(value, oldValue) // постобработка

Мы используем методы afterSet () для отображения изменений конфигурации в нашем виртуальном домене. Глядя на это, вы, скорее всего, спросите: что такое vtype: 'text'?

Мы могли бы обернуть текст легенды в собственный тег (например, диапазон). В случае, если мы не хотим использовать тег, но все же можем динамически изменять контент, псевдотег имеет смысл.

Посмотрев на afterSetUseIcon(), вы заметите, что мы используем свойство removeDom для элемента vdom. Это один из моих любимых и самых мощных флагов, которые может предложить виртуальный дом neo.mjs. Мы можем изменить его значение во время выполнения, и в результате отмеченные узлы удаляются из реальной DOM, но древовидная структура vdom остается синхронизированной.

Установка useIcon на false приводит к:

6. Добавление легенды в наш набор полей

Добавляем в наш класс еще конфиги и методы:

Метод afterSetCollapsible() добавит прослушиватель щелчков легенды один раз, если значение истинно.

Изменения других новых конфигураций вызовут updateLegend(), чтобы уменьшить код плиты котла. Этот метод заслуживает более внимательного изучения.

В случае, если наш Fieldset не использует ни iconCls, ни text конфигурации, мы не хотим иметь тег легенды внутри DOM. Если экземпляр Legend уже существует, мы снова будем использовать флаг removeDom.

В случае, если мы действительно используем конфигурацию iconCls и / или text, мы проверяем, создали ли мы уже экземпляр Javascript легенды. Мы хотим создать его только один раз и повторно использовать для динамических изменений.

Если у нас еще нет экземпляра, мы создаем его с помощью метода базового класса контейнера insert(). legendConfig позволяет нам настраивать класс для конкретных случаев использования. Вы даже можете расширить класс легенды и таким образом переопределить конфигурацию module.

Если имеется экземпляр легенды, мы используем setSilent() для одновременного обновления нескольких конфигураций классов, при этом не запуская механизм виртуального dom. Это происходит внутри последней строки: me.vdom = vdom;, которая не является присваиванием, а запускает сеттер.

Если вы хотите настроить сразу несколько конфигураций классов, вы также можете использовать set(), который запустит движок vdom один раз после того, как все изменения конфигурации будут отображены в конфигурации vdom.

7. Регулировка свернутого состояния

Последним оставшимся элементом является добавление конфигурации collapsed и логики постобработки:

Сначала мы добавляем или удаляем neo-collapsed правило CSS, которое важно для стиля.

Следующий шаг - перебрать все дочерние элементы Fieldset верхнего уровня и снова использовать флаг removeDom vdom. Это невероятно эффективно при динамическом изменении конфигурации collapsed во время выполнения.

Установка его в false удалит элементы из реальной DOM, сохраняя ее как можно более минимальной. Мы все еще можем редактировать состояние дочерних элементов, поскольку экземпляры элементов JS сохраняются.

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

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

Однако нам также необходимо учитывать элементы, которые уже отключены при расширении Fieldset. Мы не хотим удалять их отключенное состояние при повторном расширении Fieldset.

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

Вы можете найти финальную версию реализации Fieldset здесь:
dev / src / form / Fieldset.mjs.

8. Тематика

Как вы видели в видео, мы поддерживаем разные стили для темной и светлой тем.

Сделать это довольно просто.

ресурсы / scss / src / form / Fieldset.scss:

ресурсы / scss / theme-dark / form / Fieldset.scss:

ресурсы / scss / тема-свет / форма / Fieldset.scss:

При желании мы можем создавать наши темы, используя переменные CSS или нет.

9. Онлайн-демонстрация

Демоверсии оптимизированы для настольных ПК.

Neo.mjs / dist / production / examples / form / fieldset / index.html

Neo.mjs / dist / development / examples / form / fieldset / index.html

Только Chromium и Safari Tech Preview:

Neo.mjs / examples / form / fieldset / index.html

Проверить консоль → источники:

Как и было обещано, Fieldset и демонстрационное приложение (я) живут внутри App worker.

10. Заключительные мысли

Если вы пропустили, проект neo.mjs был номинирован:



neo.mjs номинирован на« Самое захватывающее использование технологии
В рамках программы награждения JavaScript с открытым исходным кодом 2021 года. itnext.io»



Вы можете найти репозиторий здесь:



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

Мы будем благодарны за обратную связь, особенно в отношении уровня сложности. Это руководство слишком простое, подходящее или слишком сложное для вас?

Меня пригласили в (немецкий) Рабочий проект подкаста в понедельник (31 мая 2021 г.). Говоря о концепциях neo и архитектуре воркеров, Питер и Родни придумали, как мы можем улучшить взаимодействие работников приложений и данных без необходимости передавать сообщения postMessages через основные потоки.

Я уже реализовал это в выпуске v2.2.6.

Если это интересная тема, я могу написать короткое сообщение в блоге о том, как это работает:



10+ комментариев, и я сделаю это, звучит справедливо?

Если вам нужна помощь в ускорении, присоединение к Slack Channel приветствуется:



В общем, было бы очень полезно, если бы больше участников могли помогать в написании руководств для «новичков» или работе над новыми компонентами.

Это может дать мне время сосредоточиться на «сложных» частях, таких как ядро ​​фреймворка.

В выпуске v2.3 я планирую сконцентрироваться на доработке компонента Календарь.

С уважением и удачного кодирования,
Тобиас

Изображение для предварительного просмотра: