js使用transition效果实现无缝滚动

目录
文章目录隐藏
  1. 前言
  2. 如果不用 vue 呢?
  3. 那么,动画怎么写呢?
  4. 轮播逻辑怎么写?

js 使用 transition 效果实现无缝滚动

前言

无缝轮播一直是面试的热门题目,而大部分答案都是复制第一张到最后。诚然,这种方法是非常标准,那么有没有另类一点的方法呢?

第一种方法是需要把所有图片一张张摆好,然后慢慢移动的,

但是我能不能直接不摆就硬移动呢?

如果你使用过 vue 的transition,我们是可以通过给每一张图片来添加入场动画和离场动画来模拟这个移动

  • 进场动画就是从最右侧到屏幕中央
  • 出场动画是从屏幕中央到左侧移出

这样看起来的效果就是图片从右边一直往左移动,但是这个不一样的地方是,我们每一个元素都有这个进场动画和离场动画,我们根本不用关心它是第几个元素,你只管轮播就是。

如果不用 vue 呢?

很简单,我们自己实现一个transtition的效果就好啦,主要做的是以下两点

  • 元素显示的时候,即 display 属性不为 none 的时候,添加xx-enter-active动画
  • 元素消失的时候,先添加动画xx-leave-active, 注意要让动画播完才消失
 function hide(el){
     el.className = el.className.replace(' slide-enter-active','')
     el.className += ' slide-leave-active'
     el.addEventListener('animationend',animationEvent)
 }
 function animationEvent(e){
     e.target.className = e.target.className.replace(' slide-leave-active','')
     e.target.style.display = 'none'
    e.target.removeEventListener('animationend',animationEvent)
 }
 function show(el){
     el.style.display = 'flex'
     el.className += ' slide-enter-active'
 }

这里我们使用了animationend来监听动画结束,注意这里每次从新添加类的时候需要重新添加监听器,不然会无法监听。如果不使用这个方法你可以使用定时器的方式来移除 leave-active 类。

 function hide(el){
     el.className = el.className.replace(' slide-enter-active','')
     el.className += ' slide-leave-active'
     setTimeout(()=>{
         //动画结束后清除 class
         el.className = el.className.replace(' slide-leave-active','')
         el.style.display = 'none'
     }, ANIMATION_TIME) //这个 ANIMATION_TIME 为你在 css 中动画执行的时间
 }

那么,动画怎么写呢?

 .slide-enter-active{
     position: absolute;
     animation: slideIn ease .5s forwards;
 }
 .slide-leave-active{
     position: absolute;
     animation: slideOut ease .5s forwards;
 }
  
 @keyframes slideIn {
     0%{
        transform: translateX(100%);
     }
     100%{
        transform: translateX(0);
     }
 }
 @keyframes slideOut {
     0%{
        transform: translateX(0);
     }
     100%{
        transform: translateX(-100%);
     }
 }

需要注意的是这里的 forwards属性,这个属性表示你的元素状态将保持动画后的状态,如果不设置的话,动画跑完一遍,你的元素本来执行了离开动画,执行完以后会回来中央位置杵着。这个时候你会问了,上面的代码不是写了,动画执行完就隐藏元素吗?

如果你使用上面的 setTimeout 来命令元素执行完动画后消失,那么可能会有一瞬间的闪烁,因为实际业务中,你的代码可能比较复杂,setTimeout 没法在那么精准的时间内执行。保险起见,就让元素保持动画离开的最后状态,即translateX(-100%)。此时元素已经在屏幕外了,不用关心它的表现了

轮播逻辑怎么写?

很简单,我们进一个新元素的时候同时移除旧元素即可,两者同时执行进场和离场动画即可。

 function autoPlay(){
     setTimeout(()=>{
         toggleShow(新元素, 旧元素)
         this.autoPlay()
     },DURATION) //DURATION 为动画间隔时间
 }
 function toggleShow(newE,oldE){
     //旧 ele 和新 ele 同时动画
     hide(oldE)
     show(newE)
 }

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>swiper</title>
  <style>
    .container{
      position: relative;
      overflow: hidden;
      height: 300px;
      overflow: hidden;
    }
    .item{
      width: 100%;
      font-size: 36px;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .item:nth-child(2n+1){
      background-color: gray;
    }
    .item:nth-child(2n){
      background-color: pink;
    }
    .slide-enter-active{
      position: absolute;
      animation: slideIn ease .5s forwards;
    }
    .slide-leave-active{
      position: absolute;
      animation: slideOut ease .5s forwards;
    }
    @keyframes slideIn {
      0%{
        transform: translateX(100%);
      }
      100%{
        transform: translateX(0);
      }
    }
    @keyframes slideOut {
      0%{
        transform: translateX(0);
      }
      100%{
        transform: translateX(-100%);
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="item" style="display:flex" >1</div>
    <div class="item" style="display:none" >2</div>
    <div class="item" style="display:none" >3</div>
    <div class="item" style="display:none" >4</div>
  </div>
</body>
<script>
  const DURATION = 3000
  let list = document.querySelectorAll('.item')
  let curIndex = 0
  autoPlay()
  function autoPlay(){
    setTimeout(()=>{
      toggleShow(list[(curIndex+1)%list.length], list[curIndex])
      curIndex = (curIndex+1)%list.length
      this.autoPlay()
    },DURATION)
  }
  function toggleShow(newE,oldE){
    //旧 ele 和新 ele 同时动画
    hide(oldE)
    show(newE)
  }
  //离场
  function hide(el){
    el.className = el.className.replace(' slide-enter-active','')  // 注意这里前面有个空格
    el.className += ' slide-leave-active'
    el.addEventListener('animationend',animationEvent)
  }
  function animationEvent(e){
    e.target.className = e.target.className.replace(' slide-leave-active','')
    e.target.style.display = 'none'
    e.target.removeEventListener('animationend',animationEvent)
  }
  //进场
  function show(el){
    el.style.display = 'flex'
    el.className += ' slide-enter-active'
  }
</script>
</html>

作者:李大雷 原文链接:点击这里

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » js使用transition效果实现无缝滚动

发表回复