1.这里使用js的方法实现了旋转卡片来展示内容的效果,鼠标移入悬停,移出开始旋转
2.支持自定义卡片数量,均匀分布圆周,支持近大远小的效果,支持自定义运动速率
3.代码:html
<div>
<div id="container" ref="container">
<div v-for="(card, index) in cards" :key="index" class="card" :style="cardStyle(card)"
@mouseover="handlemouseover" @mouseout="handlemouseout"></div>
</div>
</div>
4.自定义变量来控制圆周大小与卡片尺寸,运动速度
data() {
return {
numCards: 10, // 渲染的卡片数量
maxCardSize: 50, // 卡片在椭圆底部时的最大尺寸(实现近大远小)
minCardSize: 40, // 卡片在椭圆顶部时的最小尺寸(实现近大远小)
ellipseWidth: 400, // 椭圆宽度示例(调整椭圆的宽度和高度)
ellipseHeight: 150, // 椭圆高度示例
centerX: 0,
centerY: 0,
speed: 0.005, // 根据需要调整速度
cards: [], // 存储卡片信息的数组
animationId: null // 存储 requestAnimationFrame ID 的变量
};
},
5.循环创建卡片,开启动画(具体注释在代码里面)
/**
* 创建卡片并设置初始角度
*
* 此函数用于创建指定数量的卡片,并为每张卡片设置一个初始角度
* 角度的设置是根据卡片在数组中的位置来决定的,这样可以确保卡片均匀分布在一个圆周上
*/
createCards() {
// angle初始角度值
for (let i = 0; i < this.numCards; i++) {
this.cards.push({
angle: (i / this.numCards) * Math.PI * 2
});
}
},
/**
* 动画函数,用于动态调整卡片的位置和大小,使卡片在椭圆形路径上移动
* 此函数通过遍历每张卡片,根据其当前角度计算在椭圆上的位置,并更新卡片的大小
* 卡片的角度会随时间递增,以实现持续的动画效果
*/
animateCards() {
// 遍历每张卡片,调整其位置和大小
this.cards.forEach((card, index) => {
// 获取卡片当前的角度
const angle = card.angle;
// 根据角度计算卡片在x轴上的位置,使其沿椭圆路径移动
const x = this.centerX + this.ellipseWidth * Math.cos(angle);
// 根据角度计算卡片在y轴上的位置,使其沿椭圆路径移动
const y = this.centerY + this.ellipseHeight * Math.sin(angle);
// 打印卡片的位置,用于调试
// console.log('(x,y)', x, y);
// 根据卡片在y轴上的位置动态调整卡片的大小,使卡片大小随位置变化
let size = this.minCardSize + (this.maxCardSize - this.minCardSize) * ((y - this.centerY + this.ellipseHeight) / (2 * this.ellipseHeight));
// 更新卡片的角度,以在下一次动画帧中改变位置
card.angle += this.speed;
// 如果角度超过一圈(2π),则重置角度,实现循环动画效果
if (card.angle > Math.PI * 2) {
card.angle -= Math.PI * 2;
}
// 更新卡片的信息,包括位置和大小
// 使用Vue的$set方法来确保数据绑定的响应式
this.$set(this.cards, index, {
...card,
x,
y,
size
});
});
// 请求下一帧动画,实现连续动画效果
// 将animateCards函数自身作为参数传递,形成递归调用
this.animationId = requestAnimationFrame(this.animateCards);
},
/**
* 根据卡片的属性动态生成卡片的样式对象
*
* 该函数用于根据卡片的当前位置(x, y坐标)、最大卡片尺寸(maxCardSize)以及卡片尺寸(size)来计算卡片的样式属性
* 包括卡片的左上角位置(left, top)、宽度(width)和高度(height)
*
* @param {Object} card - 当前卡片对象,包含卡片的x和y坐标、size属性以及maxCardSize属性
* @returns {Object} 包含样式属性left、top、width和height的对象,用于设置卡片的样式
*/
cardStyle(card) {
return {
left: card.x - this.maxCardSize / 2 + 'px', // 计算卡片左边界距离视图左边界的距离
top: card.y - this.maxCardSize / 2 - 20 + 'px', // 计算卡片顶边距离视图顶边的距离,额外减去20px以调整位置
width: card.size + 'px', // 设置卡片宽度
height: card.size * 1.4 + 'px' // 根据宽度计算并设置卡片高度,比例为1.4
};
},
6.鼠标事件(开启与停止动画)
stopAnimation() {
cancelAnimationFrame(this.animationId);
},
startAnimation() {
this.animateCards();
},
// 鼠标移入事件
handlemouseover(val) {
console.log('进入', val);
this.stopAnimation()
},
// 鼠标移出事件
handlemouseout(val) {
console.log('移除', val);
this.startAnimation()
}
7.页面初始化
mounted() {
// 计算中心点位
this.centerX = this.$refs.container.offsetWidth / 2;
this.centerY = this.$refs.container.offsetHeight / 2;
console.log('中心点的位置', this.centerX, this.centerY);
// 创建10个卡片
this.createCards();
this.animateCards();
},
8.记得离开页面清除动画
// 离开页面清理动画帧
beforeDestroy() {
cancelAnimationFrame(this.animationId);
}
9.卡片的css样式(我这里随便写的)
<style>
#container {
width: 800px;
height: 300px;
position: relative;
margin: 100px auto;
border: 1px solid #ccc;
border-radius: 50%;
/* overflow: hidden; */
}
.card {
position: absolute;
width: 100px;
height: 140px;
background-color: #f00;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
transform-origin: center bottom;
}
</style>
标签:动画,vue,angle,卡片,位置,角度,大屏,card
From: https://blog.csdn.net/weixin_72915006/article/details/142451114