和b站的吃豆人轮播图效果很像,然后我额外做了吃豆人可以平移的效果,效果图如下:
首先,基础页面搭建:
<div class="switchArticle">
<!-- 豆子列表 -->
<div class="dotList">
<div
:class="{ dot: true, hideDot: currentDot === index }"
v-for="(dot, index) in articleList"
:key="index"
@click="changeDot(index, true)"
></div>
</div>
<!-- 吃豆人div -->
<div
class="activeDot"
:style="{
left: currentDotPosition + 'px',
transform: dotDirection,
}"
>
<div
class="topRound"
:style="{ transform: topRoundAnimation }"
></div>
<div
class="bottomRound"
:style="{ transform: bottomRoundAnimation }"
></div>
</div>
</div>
因为考虑到吃豆人既需要平移,又需要张嘴吃豆子,都在css里面写animation动画的话不是很方便控制,所以我就把平移的动画用在.activeDot标签上,用transition实现,而吃豆人吃豆的动画用js写。
首先,在吃豆人div中添加上下两个半圆,然后使用js来控制行内元素的rotate样式实现上下半圆旋转吃豆子的效果
吃豆人div的样式详情:
.activeDot {
width: 20px;
height: 20px;
position: absolute;
top: 0;
transition: left 0.5s ease;
.topRound {
position: absolute;
top: 0;
width: 20px;
height: 10px;
border-radius: 10px 10px 0 0;
background-color: white;
transform-origin: bottom center;
transition: all 0.1s linear;
}
.bottomRound {
position: absolute;
bottom: 0;
width: 20px;
height: 10px;
border-radius: 0 0 10px 10px;
background-color: white;
transform-origin: top center;
transition: all 0.1s linear;
}
}
接下来是吃豆人吃豆动画效果的实现,当用户点击豆子切换时,会调用controlDotAnimation方法实现动画效果:
参数说明:
deg:转动的角度。count:吃豆人张嘴闭嘴的次数总和
controlDotAnimation(deg, count) {
// 提前设置好定时器,防止多个定时器同时开启
if (this.roundTimeout) {
clearTimeout(this.roundTimeout);
this.roundTimeout = null;
}
// 张闭嘴超过五次结束动画
if (count >= 5) {
return;
}
this.topRoundAnimation = `rotate(-${deg}deg)`;
this.bottomRoundAnimation = `rotate(${deg}deg)`;
this.roundTimeout = setTimeout(() => {
clearTimeout(this.roundTimeout);
this.roundTimeout = null;
// 递归
this.controlDotAnimation(Math.abs(deg - 25), count + 1);
}, 100);
},
接着,当用户点击的豆子在吃豆人后面时,吃豆人需要转身,可以使用transform:scale(-1)进行控制:
changeDot(index, interrupt) {
// 当用户点击时,需要清除自动轮播的定时器,重新开始计时
if (interrupt) {
clearInterval(this.changeDotInterval);
this.changeDotInterval = null;
this.autoChangeDot();
}
// 豆子转身
if (index < this.currentDot) {
this.dotDirection = "scale(-1)";
} else {
this.dotDirection = "scale(1)";
}
// 开启吃豆子动画
this.controlDotAnimation(25, 0);
this.currentDot = index;
// 吃豆人位置平移
this.currentDotPosition = index * 23;
},
以上。