效果图
设计思想
1.有左中右三个内容块,左右opacity:0
2. 选择向左,则中间块从左移动到中间,右边快从中间移动到右边
3.反向同理
<template>
<div class="container">
<div id="left" ref="left">
<span class="content"> {{ list[showItem.left] }} </span>
</div>
<div id="mid" ref="mid">
<span class="content"> {{ list[showItem.mid] }} </span>
</div>
<div id="right" ref="right">
<span class="content"> {{ list[showItem.right] }} </span>
</div>
</div>
</template>
<script setup>
import {getCurrentInstance, onBeforeUnmount, onMounted, reactive} from "vue";
let currentInstance
let CLEAR_CLASS_TIMEOUT
let CLEAR_CLASS_INTERVAL
onMounted(() => {
currentInstance = getCurrentInstance()
CLEAR_CLASS_INTERVAL = setInterval(() => {
let steps = [-1, 1]
let step = steps[Math.round(Math.random())]
move(step)
}, 1000)
})
onBeforeUnmount(() => {
clearTimeout(CLEAR_CLASS_TIMEOUT)
clearInterval(CLEAR_CLASS_INTERVAL)
})
const list = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
const showItem = reactive({left: 0, mid: 1, right: 2})
const move = (step) => {
let keys = Object.keys(showItem)
keys.forEach(item => showItem[item] += step)
if (showItem.left < 0 || showItem.mid < 0 || showItem.right < 0)
keys.forEach(item => showItem[item] += list.length)
if (showItem.left >= list.length || showItem.mid >= list.length || showItem.right >= list.length)
keys.forEach(item => showItem[item] %= list.length)
setClass(step)
}
const setClass = (step) => {
let leftClass, midClass, rightClass
if (step > 0) {
leftClass = 'midToLeft'
midClass = 'rightToMid'
rightClass = ''
} else {
leftClass = ''
midClass = 'leftToMid'
rightClass = 'midToRight'
}
currentInstance.refs.left.className = leftClass
currentInstance.refs.mid.className = midClass
currentInstance.refs.right.className = rightClass
CLEAR_CLASS_TIMEOUT = setTimeout(() => {
currentInstance.refs.left.className = ''
currentInstance.refs.mid.className = ''
currentInstance.refs.right.className = ''
}, 500)
}
</script>
<style scoped lang="scss">
.container {
width: fit-content;
margin: auto auto 20px;
display: flex;
padding-top: 60px;
div {
width: 400px;
height: 300px;
background: #747bff;
border-radius: 10px;
position: relative;
.content {
position: absolute;
font-size: 22px;
top: calc(50% - 21px);
left: calc(50% - 22px);
}
}
#left, #right {
opacity: 0;
width: 350px;
}
#left {
transform: translate(-20px, -30px) skewY(10deg);
}
#right {
transform: translate(20px, -30px) skewY(-10deg);
}
}
$duration: .5s;
.rightToMid {
animation: rightToMid ease-in-out $duration;
}
.midToLeft {
animation: midToLeft ease-in-out $duration;
}
.leftToMid {
animation: leftToMid ease-in-out $duration;
}
.midToRight {
animation: midToRight ease-in-out $duration;
}
@keyframes rightToMid {
0% {
transform: translate(370px, -30px) skewY(-10deg);
width: 350px;
opacity: 0;
}
}
@keyframes midToLeft {
0% {
transform: translate(350px, 0) skewY(0);
width: 400px;
opacity: 1;
}
}
@keyframes leftToMid {
0% {
transform: translate(-370px, -30px) skewY(10deg);
width: 350px;
opacity: 0;
}
}
@keyframes midToRight {
0% {
transform: translate(-350px, 0px) skewY(0deg);
width: 400px;
opacity: 1;
}
}
</style>