javascript - 某些触摸事件后选择了多个选项卡

标签 javascript jquery html css

我已经设置了一些代码来在不同的选项卡之间切换,它在大多数情况下都运行良好,除了移动设备上的一些边缘情况一直给我带来麻烦。

如果我正常点击其中一个按钮(即 touchstarttouchend 都在同一个按钮上),它会正常运行;点击的按钮变为事件状态,相应的 View 变为可见。它在桌面上也能很好地工作。我什至添加了一些 mouseentermouseleave 事件来使一个选项卡(只有一个选项卡)在悬停时处于事件状态。

但是,当 touchstarttouchend 事件的位置不同时,就会出现问题。例如,如果在选择“联系人”选项卡的情况下,我点击“更新”,将手指移至“个人简介”,然后松开,“个人简介”和“联系人”似乎都已被选中,如下所示。

multiple tabs selected

在这种情况下,预期的行为是“Bio”在显示的“Bio” View 中处于事件状态。至少有两种其他极端情况,例如在按钮上滑动或滑动,在我当前的配置下无法按预期工作。感谢任何不破坏工作案例的帮助。

$(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>

最佳答案

我想我了解您希望在桌面设备上进行的交互,并且可能会尝试在移动设备上进行模仿。

On Desktop you have an active state (ie Bio) but on hover over the tabs you ignore the active tab and have hover effect, if the user selects no option and hovers out the active tab resumes its active style, but if the user selects a new tab the new one assumes the active state.

以下是我建议的更改:

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并预览。

enter image description here

关于javascript - 某些触摸事件后选择了多个选项卡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55422986/

相关文章:

html - 为什么在这个例子中 <ul> <li> 和 <a> 元素的高度不同?

javascript - Firebase 云消息传递 requireInteraction 不起作用

jquery - 单击选项卡时如何更改图标?

javascript - 如何防止 iFrame 在按下后退按钮时自动播放?

javascript - 如何使用 jQuery 解析表单字段的预定义子集?

javascript - 我应该如何定义一个重复出现的 HTML 元素并用 JavaScript 找到它们?

javascript - 带转到页面的 Angular ng-table

javascript - 谷歌地图 API JavaScript : nearbysearch callback function not calling

javascript - xml 自动收报机在谷歌浏览器中不起作用

javascript - 如何将 <label> 和普通文本与 Kendo UI 对齐?