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

Просто чтобы убедиться, что вы имеете в виду ту же картину:

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

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

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

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

Содержание

  1. Вступление
  2. Что такое neo.mjs?
  3. Как добавить анимацию на панели инструментов на основе Flexbox?
  4. Как работает логика перетаскивания: перемещение?
  5. Как работает пересортировка вкладок?
  6. Использует ли панель инструментов.SortZone необязательно?
  7. Онлайн-демонстрация примера видео
  8. Как пользоваться функционалом
  9. Какие следующие пункты в дорожной карте neo.mjs?
  10. Последние мысли

1. Введение

Чтобы получить быстрый обзор, вот короткое видео, показывающее повторную сортировку вкладок на основе перетаскивания, включая вертикальные панели HeaderToolbars, динамическое изменение макетов и темы:

Я реализовал логику внутри инфраструктуры пользовательского интерфейса neo.mjs с открытым исходным кодом, но вы также можете заставить ее работать для разных сценариев.

2. Что такое neo.mjs?

neo.mjs - это очень разрушительная среда пользовательского интерфейса нового поколения на основе Javascript.
Она позволяет создавать невероятно быстрые многопоточные интерфейсы.

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



Если вы хотите присоединиться к прекрасному проекту с открытым исходным кодом: neo.mjs ищет новых участников. Спрос на пользовательские интерфейсы на основе neo.mjs быстро растет, поэтому ускорение может иметь смысл, если вы все равно ищете новые клиентские проекты.

3. Как добавить анимацию на панели инструментов на основе Flexbox?

TabHeader - это просто расширение класса container.Toolbar.
Очевидно, что он придерживается CSS3 и использует display:flex, поэтому вкладки (кнопки) могут иметь гибкий стиль для указания их ширины или, альтернативно, использовать фиксированную ширину.

Если задуматься:
невозможно перемещать элементы внутри макета flexbox с помощью анимации.

Итак, как это работает?

Основной поток использует либо Mouse-, либо TouchSensor и пересылает пользовательские события drag:start, drag:move и drag:end в App Worker.

При желании вы можете использовать надстройку основного потока DragDrop. Это гарантирует отсутствие накладных расходов на размер файла, если вам не нужен DD для ваших приложений. Подробное описание аддона уйдет слишком далеко от этой темы, поэтому я просто публикую ссылку на его исходный код (на случай, если вам интересно):

Https://github.com/neomjs/neo/blob/dev/src/main/addon/DragDrop.mjs

Мы собираемся подробно рассказать о newdraggable.toolbar.SortZone.

Этот класс является расширением draggable.toolbar.DragZone, который будет подписываться на упомянутые события, связанные с перетаскиванием.

Https://github.com/neomjs/neo/blob/dev/src/draggable/toolbar/DragZone.mjs#L35

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

Element.getBoundingClientRect() здесь помогает:



Поскольку наш код выполняется внутри области App Worker, прямого доступа к DOM нет. Однако это не имеет большого значения, поскольку мы можем использовать удаленный API, чтобы легко извлекать данные из основного потока:

Мы можем передать массив идентификаторов и асинхронно получить связанные данные.

Neo.main.DomAccess также не существует внутри области App Worker, но удаленный API сделает открытые методы доступными для использования через Promises. Этот вызов отправит postMessage от работника приложения в основной поток, получит данные, отправит postMessage обратно работнику приложения, и обещание будет выполнено.

Вот полная логика:

Важной частью здесь является строка 20item.style=.
Хотя это может выглядеть как присвоение, Component.style - это конфигурация класса на основе neo.mjs. Изменение значения style запустит сеттер, сравнив новый объект стиля с текущим и отправив соответствующие дельта-обновления в основной поток.

Если вы следили за другими сообщениями блога, связанными с neo.mjs, вы знаете, что динамическое изменение DOM во время выполнения - одна из сильных сторон этой структуры.

Мы трансформируем все элементы панели инструментов, включая тот, который мы перетаскиваем. Этот элемент получит стиль visibility: 'hidden', чтобы логика позиционирования и движения была согласованной.

4. Как работает логика перетаскивания?

В этот момент вы, вероятно, задаетесь вопросом, как мы можем перетащить элемент, который скрыт. Мы этого не делаем. Ответ находится внутри draggable.DragZone:

Мы получаем DomRect элемента, который хотим перетащить, и вызываем метод createDragProxy().

Это клонирование дерева DOM компонента, который мы хотим перетащить, и создание нового DragProxyComponent.

В нашем случае moveInMainThread равно true, поэтому нам не нужно вручную заботиться о перемещении внутри App worker.

Мы также можем передать boundaryContainerId аддону DragDrop основного потока, который ограничивает перемещения соответствующим DomRect.

5. Как работает пересортировка вкладок?

Наш App Worker подписан на событие drag:move, поэтому мы можем легко добавить дополнительную логику, которая должна произойти.

Логика draggable.toolbar.SortZone выглядит так:

Мне потребовалось несколько попыток, чтобы привести код в такую ​​форму.

Он охватывает 4 варианта использования:

  1. flex-direction: row
  2. flex-direction: row, sort-direction: row-reverse
  3. flex-direction: column
  4. flex-direction: column, sort-direction: column-reverse

Имейте в виду, что когда мы меняем значение sort-direction, индексы начинаются с другой стороны контейнера, но нам все равно нужно правильно сравнивать значения left или top.

Логика switchItems() довольно проста:

Нам нужна indexMap, поскольку одна операция перетаскивания может вызвать несколько switchItems() вызовов, и мы настраиваем только реальные элементы, когда срабатывает drag:end.

Это также позволяет нам остановить операцию перетаскивания в любой момент времени.
Например, мы могли бы добавить событие drag:cancel, когда пользователь нажимает клавишу ESC, и просто удалить абсолютное позиционирование.

Если кто-то захочет добавить эту функцию, добро пожаловать :)

Логика updateItem() тривиальна:

Мы просто снова используем установщик конфигурации стиля.

Изменение левого и верхнего значений автоматически запускает анимацию на основе CSS3:

Очевидно, onDragEnd() удалит абсолютное позиционирование, восстановит фиксированные размеры элементов (если они существуют) и запустит соответствующую логику Container.moveTo().

Вы можете ознакомиться с полным SortZone исходным кодом здесь:

Https://github.com/neomjs/neo/blob/dev/src/draggable/toolbar/SortZone.mjs

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

6. Используется ли toolbar.SortZone по желанию?

Да, это определенно так. tab.header.Toolbar имеет sortable конфигурацию,
которая автоматически запускает:

Эта логика действительно прекрасна.

Как вы, надеюсь, знаете, режим разработчика neo.mjs запускается непосредственно в браузере, без каких-либо сборок или транспиляции кода.

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

Этот код также очень хорошо работает со связанными сборками на основе webpack для среды dist/production.

Как упоминалось в моем сообщении в блоге о разделении блоков Cross Apps:



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

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

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

Https://neomjs.github.io/pages/node_modules/neo.mjs/dist/production/examples/tab/container/index.html

Вы можете использовать Chrome Dev Tools, чтобы переключиться в режим планшета:

Совет: не забудьте перезагрузить страницу после переключения на мобильную симуляцию.

Фреймворк использует либо MouseSensor, либо TouchSensor, но не оба одновременно.

Я также добавил вкладку для повторной сортировки приложения neo.mjs Docs.
Да, она работает и для динамически добавляемых вкладок:

Https://neomjs.github.io/pages/node_modules/neo.mjs/dist/production/docs/index.html

Эта функция также была добавлена ​​в Covid Dashboard, а также в приложение Multi Browser Window, управляемое SharedWorkers.

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

Https://neomjs.github.io/pages/node_modules/neo.mjs/dist/production/apps/website/index.html#mainview=examples

8. Как пользоваться функционалом

Использовать функцию повторной сортировки перетаскиванием для панелей инструментов или контейнеров вкладок настолько просто, насколько это возможно. Все, что вам нужно сделать, это добавить sortable:trueconfig.

9. Каковы следующие пункты в дорожной карте neo.mjs?

Прямо сейчас я работаю над клиентским проектом по созданию построителя пользовательского интерфейса на основе neo.mjs. Немного похож на WebFlow, но он будет создавать деревья компонентов на основе neo.mjs.

Это похоже на вечный двигатель:

Пользовательский интерфейс на основе neo.mjs, который позволяет пользователям его приложений создавать пользовательские интерфейсы на основе neo.mjs с помощью перетаскивания.

Для самого фреймворка это означает, что в следующий раз я сосредоточусь на DragZones и SortZones for Trees. Определенно эпический предмет.

Поскольку поддержка браузером полей общедоступных классов на этом этапе очень хороша:



Я хотел бы вскоре добавить это в структуру neo.mjs. Мы можем убрать все «примитивные» конфигурации из static getConfig() логики.

Это первое действительно серьезное изменение с тех пор, как фреймворк стал публичным, поэтому это будет neo.mjs v2.

Единственное, что меня сдерживает, это то, что webpack еще не поддерживает поля общедоступных классов. Точнее: они используют синтаксический анализатор желудей без соответствующего предложения Stage3.

Пока мне не удалось переопределить зависимость npm:



Если у кого-то есть хорошая идея, помощь в этом приветствуется!

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

Благодаря повторной сортировке вкладок на основе перетаскивания вы можете легко добавить эту функцию в свои приложения.

Вы можете создать на его основе собственную логику.

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

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

Удачного кодирования и будьте в безопасности во время пандемии!

С уважением,
Тобиас