作者:chokcoco
来源:SegmentFault 思否社区
今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现:
简单分析一下,这个交互效果主要有两个核心:
借助了 CSS 3D 的能力
元素的旋转需要和鼠标的移动相结合
{
transform: rotate(90deg);
}
<div class="reverseRotate">
<div class="rotate">
<div class="content">正负旋转相消3D动画</div>
</div>
</div>
.rotate {
animation: rotate 5s linear infinite;
}
.reverseRotate {
animation: reverseRotate 5s linear infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes reverseRotate {
100% {
transform: rotate(-360deg);
}
}
div {
transform-style: preserve-3d;
perspective: 100px;
}
@keyframes rotate {
0% {
transform: rotateX(0deg) rotateZ(0deg);
}
50% {
transform: rotateX(40deg) rotateZ(180deg);
}
100% {
transform: rotateX(0deg) rotateZ(360deg);
}
}
鼠标活动区域
旋转物体本身
<body>
<div id="element"></div>
</body>
body {
width: 100vw;
height: 100vh;
transform-style: preserve-3d;
perspective: 500px;
}
div {
width: 200px;
height: 200px;
background: #000;
transform-style: preserve-3d;
}
div {
transform: rotateX(15deg) rotateY(30deg);
}
当鼠标在中心右侧连续移动,元素绕 Y 轴移动,并且值从 0 开始,越来越大,范围为(0, +∞)deg
反之,当鼠标在中心左侧连续移动,元素绕 Y 轴移动,并且值从 0 开始,越来越小,范围为(-∞, 0)deg
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");
mouseOverContainer.onmousemove = function(e) {
let box = element.getBoundingClientRect();
let calcY = e.clientX - box.x - (box.width / 2);
element.style.transform = "rotateY(" + calcY + "deg) ";
}
const multiple = 20;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");
mouseOverContainer.onmousemove = function(e) {
let box = element.getBoundingClientRect();
let calcY = (e.clientX - box.x - (box.width / 2)) / multiple;
element.style.transform = "rotateY(" + calcY + "deg) ";
}
const multiple = 20;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");
mouseOverContainer.onmousemove = function(e) {
let box = element.getBoundingClientRect();
let calcX = (e.clientY - box.y - (box.height / 2)) / multiple;
element.style.transform = "rotateX(" + calcX + "deg) ";
};
结合 X、Y 方向的移动let calcX = (e.clientY - box.y - (box.height / 2)) / multiple * -1;
const multiple = 20;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");
function transformElement(x, y) {
let box = element.getBoundingClientRect();
let calcX = -(y - box.y - (box.height / 2)) / multiple;
let calcY = (x - box.x - (box.width / 2)) / multiple;
element.style.transform = "rotateX("+ calcX +"deg) "
+ "rotateY("+ calcY +"deg)";
}
mouseOverContainer.addEventListener('mousemove', (e) => {
window.requestAnimationFrame(function(){
transformElement(e.clientX, e.clientY);
});
});
div {
// 与上述保持一致...
transition: all .1s;
}
mouseOverContainer.addEventListener('mouseleave', (e) => {
window.requestAnimationFrame(function(){
element.style.transform = "rotateX(0) rotateY(0)";
});
});