移动左右滑动tab

580 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情

移动端需求

时间紧急,有个高优需求,移动端高端的特效,只给两天时间,直接无语。根本无法实现,紧急和大佬讨论一番,大佬直接开始砍需求,告知他的设计虽然巧夺天工,但是移动端上实现起来异常麻烦,而且效果也不会像想象的那么顺其自然。然后,直接将复杂的逻辑简化了,搞成左右滑动即可

然而

然而左右滑动我也没搞过,好兄弟建议我使用swiper,但是那么怎么能行,大家都知道我是cv大师了。不可强攻,只能智取

上代码

首先,先搭建ui,然,思想就是首先有个容器,然后容器宽度是屏幕宽度,内部有个子元素,子元素宽度为有几屏幕就有机屏幕的宽度。然后给个display flex, 里面的子元素flex 1 就能保证每个子元素自己一屏幕了。然后样式就这样。

有几个状态,pageIndex当前是第几页激活。也就是显示第几页,第二个是startX,记录手势开始的x坐标,然后在 touchmove里判断边界情况,就是在最左边就不能往左滑了,最右边就不能往右滑了。怎么区分往左往右呢?判断xd当前坐标,如果大于startX 就是往右滑了,反过来就是往左滑。然后根据左右 或者加减pageindex,根据左右位置,实时的更新元素移动的位移,当前要加上前面页占的距离。松手后,根据移动距离来决定是否翻页,力度自己控制,灵敏一点就少一点距离就翻页,否则就恢复到之前的位置 移动端实现左右移动,要利用手势事件 // touchStart // touchMove // touchEnd

过成中可以给对应的dom增加一个样式,然后突出一下。因为是移动端适配,所以要计算一下宽度

这三个事件打好配合



  <script>
    document.documentElement.style.fontSize = document.documentElement.clientWidth / 37.5 + 'px'
  </script>
  <style>
    body {
      margin: 0;
    }

    .slide-page {
      position: relative;
      width: 100%;
      height: 120px;
      padding: 30px 0px;
      overflow: hidden;
    }

    .scroll-wrapper {
      position: absolute;
      height: 100px;
      display: flex;
      width: calc(100% + (100% - 8rem) * 3);
      transition: transform .2s ease 0s;
    }

    .slide-item {
      width: calc(100% - 8rem);
      transform: scale(0.8);
    }

    .slide-item .inner {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 10rem;
    }

    .slide-item:nth-child(1) {
      background-color: #09f;
      margin-left: 4rem;
    }

    .slide-item:nth-child(2) {
      background-color: #990;
    }

    .slide-item:nth-child(3) {
      background-color: rgb(41, 149, 140);

    }

    .slide-item:nth-child(4) {
      background-color: rgb(126, 31, 31);
      margin-right: 4rem;
    }

    .active {
      transform: scale(1);
    }
  </style>
</head>


<body>
  <div class="app">

    <div class="slide-page">
      <div class="scroll-wrapper">
        <div class="slide-item active">
          <div class="inner">page1</div>
        </div>
        <div class="slide-item">
          <div class="inner">page2</div>
        </div>
        <div class="slide-item">
          <div class="inner">page3</div>
        </div>
        <div class="slide-item">
          <div class="inner">page4</div>
        </div>
      </div>
    </div>
  </div>

</body>
<script>

  // touchStart
  // touchMove
  // touchEnd
  const oSlidePage = document.querySelector('.slide-page'),
    oScrollWrapper = document.querySelector('.scroll-wrapper'),
    oSlideItemList = document.querySelectorAll('.slide-item'),
    pageWidth = document.documentElement.clientWidth - document.documentElement.clientWidth / 37.5 * 8
  let startX = 0
  let pageIndex = 0
  let distanceX = 0
  let isMove = false
  const init = () => {
    bindEvent()
  }
  function bindEvent () {
    oScrollWrapper.addEventListener('touchstart', handlerTouchStart)
    oScrollWrapper.addEventListener('touchmove', handlerTouchMove)
    oScrollWrapper.addEventListener('touchend', handlerTouchEnd)
  }
  function handlerTouchStart (e) {
    startX = e.touches[0].clientX
  }
  function handlerTouchMove (e) {
    const moveX = e.touches[0].clientX
    if ((moveX > startX && pageIndex === 0) || (moveX < startX && pageIndex === oSlideItemList.length - 1)) {
      return
    }
    // 实时的位移距离
    distanceX = moveX - startX
    // setTranslateX(-pageWidth * pageIndex + distanceX)
    isMove = true
  }
  function handlerTouchEnd () {
    if (isMove) {
      //切换
      if (Math.abs(distanceX) >= pageWidth / 4) {
        // 往右滑
        if (distanceX > 0) {
          pageIndex--
        } else {
          pageIndex++
        }
      }
      setTranslateX(-pageIndex * pageWidth)
      oSlideItemList.forEach(item => item.classList.remove('active'))
      oSlideItemList[pageIndex].classList.add('active')
      startX = 0
      distanceX = 0
      isMove = false
    }
  }


  function setTranslateX (transX) {
    oScrollWrapper.style.transform = `translateX(${transX}px)`
  }
  init()


</script>