中心点靠近动画解析
背景
今天要解析的是一种常见动画效果,特点是:一排横行排列的卡片,被激活的卡片尽可能移动到中间位置。我给它命名为【中心点靠近动画】,先看下动画效果:
解析
要实现动画效果,个人总结有下面两个核心点:
运动动画基于什么实现? 每个卡片的运动到中心点的距离怎么计算?
1、运动动画基于什么实现?
针对第一个问题比较好解决,大致可以分为两种,一种是基于scrollLeft
来控制卡片位置,一种是基于css3动画属性transform
实现。两种方式各有优劣,具体如下:
scrollLeft
优点:在实现点击移动的效果下,能够利用div的滚动特性,快速实现横向滑动效果。
缺点:动画性能较低。
transform
优点:基于CSS3实现,动画性能高。
缺点:横向滚动效果需要单独实现。
这次是选用的transform实现的
html代码
<div class="container">
<div class="list"
ref="listRef"
style={{transform: `translateX(${translateX}px)` }}
>
<div class="cardItem">1</div>
<div class="cardItem">2</div>
<div class="cardItem">3</div>
<div class="cardItem">4</div>
<div class="cardItem">5</div>
<div class="cardItem">6</div>
<div class="cardItem active">7</div>
<div class="cardItem">8</div>
</div>
</div>
.container {
position: relative;
overflow: hidden;
.list {
display: flex;
transition: 0.3s ease-in-out;
}
}
2、每个卡片的运动到中心点的距离怎么计算
这个问题是今天讲的重点内容,画了一个简洁的示意图
每个卡片向中心点靠近时,list偏移的距离都是固定的。所以可以将list以中心点为分界线,分成两个部分。
active卡片中心点距离list左边距的距离为offsetLeft
如果 offsetLeft < w/2
,也就是中心点的左侧部分卡片,偏移距离translateX = 0;如果 offsetLeft > w/2
,也就是中心点右侧部分卡片,运动到中心点需要偏移dis=offsetLeft-w/2
,但是需要检查右边隐藏部分内容的宽度scrollRight
,偏移距离需要为两者之间的最小值Math.min(dis, scrollRight)
;
注意点:当L < w时,也就是列表长度小于容器长度时,偏移距离都是0;
代码如下:
// 其中cardW为卡片宽度
useEffect(() => {
const cardDomList = listRef.current?.children;
if (cardDomList) {
const leftDis = cardDomList[videoIndex].offsetLeft + cardW / 2;
const scrollRight = L > w ? L - w : 0;
if (leftDis < w / 2) {
setTranslateX(0);
} else {
const dis = leftDis - w / 2;
setTranslateX(-Math.min(dis, scrollRight));
}
}
}, [videoIndex]);
总结
解决方案整体是一个距离计算的算法,相对于之前计算方案,感觉这个计算方式更简洁,具有通用性。
评论