#javascript #jquery #html #css
#javascript #jquery #HTML #css
Вопрос:
Я настроил некоторый код для переключения между разными вкладками, и по большей части он работает довольно хорошо, за исключением некоторых крайних случаев на мобильных устройствах, которые доставляют мне проблемы.
Если я нажимаю одну из кнопок обычным образом (т. Е. позиции touchstart
и touchend
находятся на одной и той же кнопке), она ведет себя нормально; нажатая кнопка становится активной, и становится видимым соответствующий вид. Это также хорошо работает на рабочем столе. Я даже добавил некоторые события mouseenter
и mouseleave
, чтобы сделать вкладку (только одну вкладку) активной при наведении курсора мыши.
Однако проблемы возникают, когда позиции событий touchstart
и touchend
различаются. Если, например, при выбранной вкладке «Контакт» я нажимаю «Обновления», перемещаю палец к «Био» и отпускаю, «Био» и «Контакт» будут выбраны, как показано ниже.
Ожидаемым поведением в этой ситуации было бы, если бы «Bio» был активным с отображаемым представлением «Bio». Есть по крайней мере два других крайних случая, таких как включение или выключение кнопки, которые не работают должным образом с моей текущей конфигурацией. Приветствуется любая помощь, которая не нарушает работу с кейсами.
$(document).ready(function () {
// show appropriate view based on document hash
if (document.location.hash) {
setTimeout(function () {
window.scrollTo(0, 0);
}, 1);
}
if (document.location.hash === '' ||
document.location.hash === '#' ||
document.location.hash === '#bio') {
$('#bio').show();
$('#tabs-bio').addClass('active');
} else if (document.location.hash === '#updates') {
$('#updates').show();
$('#tabs-updates').addClass('active');
} else if (document.location.hash === '#contact') {
$('#contact').show();
$('#tabs-contact').addClass('active');
}
// define tabs behavior
var $activeTab = $('.active');
var $tabsChildren = $('.tabs > li');
$tabsChildren.on('click touchstart', function (event) {
event.preventDefault();
event.stopPropagation();
$tabsChildren.each(function () {
$($(this).data('href')).hide();
if (event.type === 'click') {
$(this).removeClass('active');
}
});
$activeTab = $(this);
$($(this).data('href')).show();
});
$('.tabs').mouseenter(function () {
$activeTab.removeClass('active');
});
$('.tabs').mouseleave(function () {
$activeTab.addClass('active');
});
$(window).on('touchstart', function () {
$activeTab.addClass('active');
});
});
ul {
padding-left: 0;
}
ul li {
list-style: none;
}
.center {
text-align: center;
}
.tabs {
display: grid;
grid-gap: 0.25rem;
color: black;
margin-bottom: 2rem;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.tabs-3 {
grid-template-columns: 33% 33% 33%;
grid-template-columns: calc((100% - 0.5rem)/3) calc((100% - 0.5rem)/3) calc((100% - 0.5rem)/3);
}
.tabs li {
border-radius: 4px;
background-color: #ced4da;
padding: 0.5rem;
}
.tabs li:hover {
background-color: #007bff;
color: white;
cursor: pointer;
}
.tabs .active {
background-color: #007bff;
color: white;
}
#page > div {
display: none;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<ul class="tabs tabs-3">
<li class="center" id="tabs-bio" data-href="#bio">Bio</li>
<li class="center" id="tabs-updates" data-href="#updates">Updates</li>
<li class="center" id="tabs-contact" data-href="#contact">Contact</li>
</ul>
<div id="page">
<div id="bio">
<h3>Bio</h3>
</div>
<div id="updates">
<h3>Updates</h3>
</div>
<div id="contact">
<h3>Contact</h3>
</div>
</div>
</div>
Ответ №1:
Я думаю, что понимаю взаимодействие, к которому вы стремитесь на рабочем столе, и, вероятно, пытаюсь имитировать это на мобильном устройстве.
На рабочем столе у вас есть активное состояние (т. Е. Биография), но при наведении курсора мыши на вкладки вы игнорируете активную вкладку и получаете эффект наведения курсора, если пользователь не выбирает опцию и наводит курсор, активная вкладка возобновляет свой активный стиль, но если пользователь выбирает новую вкладку, новая принимает активное состояние.
Вот какие изменения я бы предложил:
На touchstart
фактически не меняйте вкладку, поскольку пользователь может в конечном итоге не захотеть выбирать вкладку — либо отодвигается, либо они на самом деле просто пытались прокрутить, ваша функция переписана:
$tabsChildren.on('click touchstart', function (event) {
event.preventDefault();
event.stopPropagation();
$tabsChildren.removeClass('active');
if (event.type === 'click') {
$tabsChildren
.removeClass('active')
.each(function () {
$($(this).data('href')).hide();
});
$activeTab = $(this);
$($(this).data('href')).show();
} else {
$(this).addClass('active');
}
});
Обратите внимание, я все еще добавляю active
класс, просто чтобы показать стиль «наведения».
Теперь используйте touchend
, чтобы выяснить, действительно ли пользователь намеревался выбрать вкладку:
$tabsChildren.on('touchend', function (event) {
var changes = event.changedTouches[0];
var $endEl = $(document.elementFromPoint(changes.pageX, changes.pageY));
if ($endEl.parent('.tabs').length) {
$tabsChildren
.removeClass('active')
.each(function () {
$($(this).data('href')).hide();
});
$activeTab = $endEl;
$endEl.addClass('active');
$($endEl.data('href')).show();
event.stopPropagation();
}
});
То, что мы хотим сделать, это не использовать $(this)
(где пользователь начал касание), а выяснить, какой элемент находится в конце. Если пользователь действительно перешел на другую вкладку — выберите это. Если пользователь вообще не попал на вкладку, ничего не делайте и позвольте этому перехватить его:
$(window).on('touchend', function () {
$tabsChildren.removeClass('active');
$activeTab.addClass('active');
});
После чего мы возвращаем вкладку к исходной активной.
Вот код в действии https://codepen.io/anon/pen/pBzeEP?editors=0010 а также предварительный просмотр.