[CSS, JavaScript, Интерфейсы, HTML] Динамическое меню c поддержкой touch move и mouse move на RevolveR
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Наверняка многие из вас хотели бы научиться создавать красивые и подвижные меню в духе Android Java и Kotlin приложений. Скорее всего даже многие из вас ради этого уходили в области программирования отдельных приложений и были вынуждены осваивать инородный стек.
В этой статье я расскажу как просто и непринужденно можно создавать линейные динамические меню поддерживающие не только события мыши, но и поинтеры для мобильных версий.
И так: Simple Dynamic Menu by RevolveR Labs.
Начинается все с верстки. Она должна быть семантической, легкой и современной.
<nav class="dynamic-menu">
<ul>
<li><a href="https://revolvercmf.ru">RevolveR Labs</a></li>
<li><a href="#">Ultra newest solutions</a></li>
<li><a href="#">The way of incredible</a></li>
<li><a href="#">In search of the best</a></li>
<li><a href="#">Progressive RevolveR frontends</a></li>
<li><a href="#">Developing of new era</a></li>
</ul>
</nav>
Мы используем стандартный маркированный список и HTML 5 в качестве элемента враппера, а чтобы сделать меню плавающим сразу пропишем CSS стили вытягивающие меню на за пределы экрана на всю ширину списка элементов и скроем все лишнее до области видимости:
.dynamic-menu {
display: inline-block;
text-align: center;
overflow: hidden;
margin: 0 auto;
height: 3vw;
width: 80%;
}
.dynamic-menu ul {
transition: all 2.5s ease-in-out;
position: relative;
list-style: none;
width: 900vw;
padding: 0;
margin: 0;
left: 0vw;
}
.dynamic-menu ul li {
box-shadow: 0 0 0.1vw #333;
border: .1vw dashed #fff;
background: #a2a2a2;
margin-bottom: 1vw;
display: inline-block;
border-radius: .2vw;
margin-right: .5vw;
padding: .2vw 1vw;
background: #888;
float: left;
}
.dynamic-menu ul li a {
text-shadow: 0 0 0.2vw #fff;
font: normal 2vw Helvetica;
text-decoration: none;
color: #006400;
}
.dynamic-menu ul li a:hover {
text-decoration: underline;
color: #674c2be0;
}
Наш CSS готов. Теперь меню будет расположено по центру и все элементы списка не отобразяться. Нам осталось написать хэндлеры меню, которые будут отвечать за плавное перемещение списка при нажатой левой кнопке мыши или событии touch.
Handler для desktop версии
Для работы хэндлера нам понадобится инициализировать RevolveR инстанс и использовать некоторое встроенное API работы с событиями:
let launch = RR.browser;
RR.menuMove = null;
if( !RR.isM ) {
RR.event('.dynamic-menu ul', 'mousedown', (e) => {
e.preventDefault();
if( !RR.menuMove ) {
RR.menuLeft = RR.curxy[0];
RR.MenuMoveObserver = RR.event('body', 'mousemove', (e) => {
e.preventDefault();
RR.styleApply('.dynamic-menu ul', ['transition: all 0s ease']);
RR.menuMove = true;
RR.menuPosition = ( RR.menuLeft - RR.curxy[0] ) *-1;
RR.styleApply('.dynamic-menu ul', ['left:'+ RR.menuPosition +'px']);
RR.event('body', 'mouseup', (e) => {
e.preventDefault();
if( e.target.tagName === 'A' && !RR.touchFreeze ) {
//R.loadURI(target.href, target.title);
console.log(e.target.href);
RR.touchFreeze = true;
RR.menuMove = null;
}
void setTimeout(() => {
RR.menuMove = null;
}, 50);
void setTimeout(() => {
if( !RR.menuMove ) {
RR.styleApply('.dynamic-menu ul', ['left: 0px', 'transition: all 2.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)']);
}
}, 2500);
});
});
}
});
}
Большинство необходимых event уже работают после запуска гетера RR.browser(). Это например отслеживание событий изменения размера окна и постоянно обновление положения указателя мыши RR.curxy.
Здесь мы используем метод блокировки флагами для того, чтобы добиться синхронности выполнения событий и задать блокирующие флаги, например, для реализации запрета события перехода по ссылке, если меню находится в движении.
RR.MenuMoveObserver является собой event стеком, который хранит MD5 hash события для того, чтобы можно было выключить часть хэндлера отвечающего за смену положения по оси X. Мы выключаем обсерверы каждый раз когда событие клик завершилось в пользу mouseup.
Готово. При нажатии на левую клавишу мыши, если держать кнопку утопленной будет происходить отслеживание положения курсора мыши по оси X, а обсервер обеспечит своевременное обновление положения left контейнера списка меню внутри враппера области видимости и лента меню начнет двигаться открывая не поместившиеся элементы списка.
Мобильный handler меню
Основной принцип работы остается примерно таким же, но я не стал схлопывать разные хэндлерры в один обработчик чтобы оставить понятность и читабельность кода.
Проверив, что инициализирован мобильный инстанс браузера мы подключим аналоги слушателей событий уже не для мыши, а для touch экрана.
if( RR.isM ) {
RR.event('.dynamic-menu ul', 'touchstart', (e) => {
e.preventDefault();
RR.menuMove = null;
RR.event('body', 'touchend', (e) => {
e.preventDefault();
if( !RR.menuMove ) {
RR.touchFreeze = null;
let target = e.changedTouches[0].target;
if( RR.isO(RR.MenuMoveObserver) ) {
for( i of RR.MenuMoveObserver ) {
RR.detachEvent( i[ 2 ] );
}
}
if( target.tagName === 'A' && !RR.touchFreeze ) {
//R.loadURI(target.href, target.title);
console.log(e.target.href);
RR.touchFreeze = true;
RR.menuMove = null;
}
void setTimeout(() => {
if( !RR.menuMove ) {
RR.styleApply('.dynamic-menu ul', ['left: 0px', 'transition: all 2.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)']);
//RR.animate('.dynamic-menu ul', ['left:0px:1000:wobble']);
}
}, 2500);
}
});
if( !RR.menuMove ) {
RR.menuLeft = e.changedTouches[0].screenX;
RR.MenuMoveObserver = RR.event('body', 'touchmove', (e) => {
e.preventDefault();
RR.styleApply('.dynamic-menu ul', ['transition: all 0s ease']);
RR.menuMove = true;
RR.menuPosition = ( RR.menuLeft - e.changedTouches[0].screenX ) *-1;
RR.styleApply('.dynamic-menu ul', ['left:'+ RR.menuPosition +'px']);
RR.event('body', 'touchend', (e) => {
RR.menuMove = null;
});
});
}
});
}
В коде вы увидите небольшую разницу. Во первых event.target теперь не работает и нужно следить за сериями touch. Я добавил анимацию возвращения меню с эффектом easing и теперь меню само плавно возвращается в начальное положение спустя некоторое время бездействия с меню:
void setTimeout(() => {
if( !RR.menuMove ) {
RR.styleApply('.dynamic-menu ul', ['left: 0px', 'transition: all 2.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)']);
}
}, 2500);
Demo
Чтобы посмотреть как работает Dynamic Menu на базе библиотеки RevolveR вы можете пройти по ссылке.
Итог
Многие из вас используют готовые плагины или встраивают блоки верстки с меню гамбургера, однако динамические линейные меню ни чуть не хуже и позволяют экономить место в интерфейсах. Многим из вас наверняка показалось бы сложным реализовать такие меню из-за разницы в слушателях событий и неумения использовать флаги. Этот пример был направлен показать, что средствами обычного JavaScript можно не обладая какой-то запредельной квалификацией реализовывать такие же вещи, как и в удобных Android приложениях, а мастерская работа с анимациями позволяет создавать потрясные эффекты переходов и разные хуки событий на какие-либо срабатывания.
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка веб-сайтов, JavaScript, ReactJS] Как эффективно применять React Context (перевод)
- [Интерфейсы, Usability, Управление продуктом] Зачем Авито «облачные» UX-исследователи и как с ними работать
- [PHP, Анализ и проектирование систем, Высокая производительность, Интерфейсы, Управление e-commerce] Как я за вечер написал быструю CMS для статических сайтов по правилам бизнес-логики в одном файлике
- [Разработка веб-сайтов, CSS, TypeScript] Продвинутый CSS-in-TS
- [JavaScript, ReactJS, Визуализация данных, Инфографика, Разработка веб-сайтов] Визуализация сложных данных с использованием D3 и React
- [JavaScript] Удобная платформа для подбора библиотек и фреймворков JavaScript — openbase (перевод)
- [CSS, Usability] Темный режим: Hello darkness, my old friend (перевод)
- [Разработка веб-сайтов, JavaScript, VueJS] Отдаем корректный код 404 в связке VUE SPA + SSR
- Доступен пакетный менеджер NPM 7.0
- [Разработка веб-сайтов, CSS, HTML] 10 современных раскладок в одну строку CSS-кода (перевод)
Теги для поиска: #_css, #_javascript, #_interfejsy (Интерфейсы), #_html, #_javascript, #_html_5, #_touch, #_mouse, #_menu, #_css, #_javascript, #_interfejsy (
Интерфейсы
), #_html
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 10:03
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Наверняка многие из вас хотели бы научиться создавать красивые и подвижные меню в духе Android Java и Kotlin приложений. Скорее всего даже многие из вас ради этого уходили в области программирования отдельных приложений и были вынуждены осваивать инородный стек. В этой статье я расскажу как просто и непринужденно можно создавать линейные динамические меню поддерживающие не только события мыши, но и поинтеры для мобильных версий. И так: Simple Dynamic Menu by RevolveR Labs. Начинается все с верстки. Она должна быть семантической, легкой и современной. <nav class="dynamic-menu">
<ul> <li><a href="https://revolvercmf.ru">RevolveR Labs</a></li> <li><a href="#">Ultra newest solutions</a></li> <li><a href="#">The way of incredible</a></li> <li><a href="#">In search of the best</a></li> <li><a href="#">Progressive RevolveR frontends</a></li> <li><a href="#">Developing of new era</a></li> </ul> </nav> Мы используем стандартный маркированный список и HTML 5 в качестве элемента враппера, а чтобы сделать меню плавающим сразу пропишем CSS стили вытягивающие меню на за пределы экрана на всю ширину списка элементов и скроем все лишнее до области видимости: .dynamic-menu {
display: inline-block; text-align: center; overflow: hidden; margin: 0 auto; height: 3vw; width: 80%; } .dynamic-menu ul { transition: all 2.5s ease-in-out; position: relative; list-style: none; width: 900vw; padding: 0; margin: 0; left: 0vw; } .dynamic-menu ul li { box-shadow: 0 0 0.1vw #333; border: .1vw dashed #fff; background: #a2a2a2; margin-bottom: 1vw; display: inline-block; border-radius: .2vw; margin-right: .5vw; padding: .2vw 1vw; background: #888; float: left; } .dynamic-menu ul li a { text-shadow: 0 0 0.2vw #fff; font: normal 2vw Helvetica; text-decoration: none; color: #006400; } .dynamic-menu ul li a:hover { text-decoration: underline; color: #674c2be0; } Наш CSS готов. Теперь меню будет расположено по центру и все элементы списка не отобразяться. Нам осталось написать хэндлеры меню, которые будут отвечать за плавное перемещение списка при нажатой левой кнопке мыши или событии touch. Handler для desktop версии Для работы хэндлера нам понадобится инициализировать RevolveR инстанс и использовать некоторое встроенное API работы с событиями: let launch = RR.browser;
RR.menuMove = null; if( !RR.isM ) { RR.event('.dynamic-menu ul', 'mousedown', (e) => { e.preventDefault(); if( !RR.menuMove ) { RR.menuLeft = RR.curxy[0]; RR.MenuMoveObserver = RR.event('body', 'mousemove', (e) => { e.preventDefault(); RR.styleApply('.dynamic-menu ul', ['transition: all 0s ease']); RR.menuMove = true; RR.menuPosition = ( RR.menuLeft - RR.curxy[0] ) *-1; RR.styleApply('.dynamic-menu ul', ['left:'+ RR.menuPosition +'px']); RR.event('body', 'mouseup', (e) => { e.preventDefault(); if( e.target.tagName === 'A' && !RR.touchFreeze ) { //R.loadURI(target.href, target.title); console.log(e.target.href); RR.touchFreeze = true; RR.menuMove = null; } void setTimeout(() => { RR.menuMove = null; }, 50); void setTimeout(() => { if( !RR.menuMove ) { RR.styleApply('.dynamic-menu ul', ['left: 0px', 'transition: all 2.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)']); } }, 2500); }); }); } }); } Большинство необходимых event уже работают после запуска гетера RR.browser(). Это например отслеживание событий изменения размера окна и постоянно обновление положения указателя мыши RR.curxy. Здесь мы используем метод блокировки флагами для того, чтобы добиться синхронности выполнения событий и задать блокирующие флаги, например, для реализации запрета события перехода по ссылке, если меню находится в движении. RR.MenuMoveObserver является собой event стеком, который хранит MD5 hash события для того, чтобы можно было выключить часть хэндлера отвечающего за смену положения по оси X. Мы выключаем обсерверы каждый раз когда событие клик завершилось в пользу mouseup. Готово. При нажатии на левую клавишу мыши, если держать кнопку утопленной будет происходить отслеживание положения курсора мыши по оси X, а обсервер обеспечит своевременное обновление положения left контейнера списка меню внутри враппера области видимости и лента меню начнет двигаться открывая не поместившиеся элементы списка. Мобильный handler меню Основной принцип работы остается примерно таким же, но я не стал схлопывать разные хэндлерры в один обработчик чтобы оставить понятность и читабельность кода. Проверив, что инициализирован мобильный инстанс браузера мы подключим аналоги слушателей событий уже не для мыши, а для touch экрана. if( RR.isM ) {
RR.event('.dynamic-menu ul', 'touchstart', (e) => { e.preventDefault(); RR.menuMove = null; RR.event('body', 'touchend', (e) => { e.preventDefault(); if( !RR.menuMove ) { RR.touchFreeze = null; let target = e.changedTouches[0].target; if( RR.isO(RR.MenuMoveObserver) ) { for( i of RR.MenuMoveObserver ) { RR.detachEvent( i[ 2 ] ); } } if( target.tagName === 'A' && !RR.touchFreeze ) { //R.loadURI(target.href, target.title); console.log(e.target.href); RR.touchFreeze = true; RR.menuMove = null; } void setTimeout(() => { if( !RR.menuMove ) { RR.styleApply('.dynamic-menu ul', ['left: 0px', 'transition: all 2.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)']); //RR.animate('.dynamic-menu ul', ['left:0px:1000:wobble']); } }, 2500); } }); if( !RR.menuMove ) { RR.menuLeft = e.changedTouches[0].screenX; RR.MenuMoveObserver = RR.event('body', 'touchmove', (e) => { e.preventDefault(); RR.styleApply('.dynamic-menu ul', ['transition: all 0s ease']); RR.menuMove = true; RR.menuPosition = ( RR.menuLeft - e.changedTouches[0].screenX ) *-1; RR.styleApply('.dynamic-menu ul', ['left:'+ RR.menuPosition +'px']); RR.event('body', 'touchend', (e) => { RR.menuMove = null; }); }); } }); } В коде вы увидите небольшую разницу. Во первых event.target теперь не работает и нужно следить за сериями touch. Я добавил анимацию возвращения меню с эффектом easing и теперь меню само плавно возвращается в начальное положение спустя некоторое время бездействия с меню: void setTimeout(() => {
if( !RR.menuMove ) { RR.styleApply('.dynamic-menu ul', ['left: 0px', 'transition: all 2.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)']); } }, 2500); Demo Чтобы посмотреть как работает Dynamic Menu на базе библиотеки RevolveR вы можете пройти по ссылке. Итог Многие из вас используют готовые плагины или встраивают блоки верстки с меню гамбургера, однако динамические линейные меню ни чуть не хуже и позволяют экономить место в интерфейсах. Многим из вас наверняка показалось бы сложным реализовать такие меню из-за разницы в слушателях событий и неумения использовать флаги. Этот пример был направлен показать, что средствами обычного JavaScript можно не обладая какой-то запредельной квалификацией реализовывать такие же вещи, как и в удобных Android приложениях, а мастерская работа с анимациями позволяет создавать потрясные эффекты переходов и разные хуки событий на какие-либо срабатывания. =========== Источник: habr.com =========== Похожие новости:
Интерфейсы ), #_html |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 10:03
Часовой пояс: UTC + 5