文章目录
写了实现了一个具有3D旋转效果的卡片。下面是对其实现思路的详细解析:
效果预览
1. 组件结构
- 模板部分 (
<template>
):- 使用一个
<div>
元素包裹<slot>
,允许父组件传递内容到卡片内部。 :id="id"
绑定一个唯一的ID,用于在JavaScript中引用该元素。
- 使用一个
2. 脚本部分 (<script>
)
属性 (props
)
range
: 控制卡片旋转的角度范围,默认值为空字符串。padding
: 控制卡片的内边距,默认值为空字符串。
数据 (data
)
id
: 生成一个唯一的ID,确保每个卡片实例都有唯一的标识符。
方法 (methods
)
getRotate(range, value, max)
: 计算旋转角度。根据鼠标位置和卡片尺寸计算出旋转角度。
生命周期钩子 (mounted
)
- 在组件挂载后,设置卡片的初始样式。
- 根据
range
属性调整旋转角度范围。 - 设置
--padding
自定义属性,用于控制卡片的内边距。 - 添加鼠标移动事件监听器,根据鼠标位置动态计算并设置
--rx
和--ry
自定义属性,实现3D旋转效果。 - 添加鼠标离开事件监听器,当鼠标离开卡片时,重置旋转角度为0度。
3. 样式部分 (<style scoped>
)
-
.card-3d
:- 使用
--padding
自定义属性控制内边距。 - 设置
cursor: pointer
,使鼠标悬停时显示为指针形状。 - 设置
border-radius
和transition
,使卡片圆角过渡效果平滑。 - 使用
transform
属性结合perspective
和rotateX
、rotateY
实现3D旋转效果。 - 设置
border
,给卡片添加边框。
- 使用
-
.card-3d img
:- 设置
border-radius
继承父元素的圆角样式。
- 设置
-
.card-3d:hover
:- 设置
box-shadow
,当鼠标悬停时增加阴影效果,增强3D效果。
- 设置
实现思路总结
- 唯一标识: 通过生成唯一的ID,确保每个卡片实例都能被单独识别和操作。
- 属性配置: 通过
props
接收外部传入的参数,如旋转角度范围和内边距,提高组件的灵活性和复用性。 - 事件监听: 使用
onmousemove
和onmouseleave
事件监听器,动态计算并应用旋转角度,实现3D旋转效果。 - 样式控制: 使用CSS变量(自定义属性)动态控制样式,如内边距和旋转角度,使样式更加灵活和易于维护。
完整代码
<!-- 3D卡片效果 -->
<template>
<main class="page-main">
<div :id="id" class="card-3d">
<slot></slot>
</div>
</main>
</template>
<script lang="ts">
export default {
props: {
range: {type: String},
padding:{type:String}
},
components: {},
data() {
return {
id: new Date().getTime() + "_keller_card-img-3d_" + Math.random(),
}
},
methods: {
//计算偏转角度
getRotate(range, value, max) {
return value / max * (range[1] - range[0]) + range[0];
}
},
computed: {},
watch: {},
mounted() {
let xRange = [-10, 10];
let yRange = [-10, 10];
if (this.$props.range) {
const offset = this.$props.range;
xRange = [-1 * offset, offset];
yRange = [-1 * offset, offset];
}
const card = document.getElementById(this.id);
card.style.setProperty("--padding", this.$props.padding);
//监听鼠标事件
card.onmousemove = (e) => {
const {offsetX, offsetY} = e;
const {offsetWidth, offsetHeight} = card;
const ry = 0 - this.getRotate(yRange, offsetX, offsetWidth);
const rx = this.getRotate(xRange, offsetY, offsetHeight);
card.style.setProperty("--rx", rx + "deg");
card.style.setProperty("--ry", ry + "deg");
}
card.onmouseleave = (e) => {
card.style.setProperty("--rx", "0deg");
card.style.setProperty("--ry", "0deg");
}
}
}
</script>
<style scoped>
.card-3d {
padding: var(--padding,0px);
cursor: pointer;
border-radius: 8px;
transition: 0.1s;
transform: perspective(500px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
border: 1px solid #f0f0f0;
}
.card-3d img {
border-radius: inherit;
}
.card-3d:hover {
box-shadow: -3px -3px 10px #54a29e, 3px 3px 10px #a79d66;
}
</style>