作者:李大雷
出自:SegmentFault 思否
原文:segmentfault.com/a/1190000023945464
前言
无缝轮播一直是面试的热门题目,而大部分答案都是复制第一张到最后。诚然,这种方法是非常标准,那么有没有另类一点的方法呢?
第一种方法是需要把所有图片一张张摆好,然后慢慢移动的,
但是我能不能直接不摆就硬移动呢?
如果你使用过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(()=>{//动画结束后清除classel.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)}