开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
前言
继上一篇,用纯css展示元素内鼠标移入移出效果,在相同原理下,今天要结合js展示3D的动态效果。
效果图如下:
1. 了解3D方向轴
使用3D动态效果,首先要先熟悉三维坐标轴系统。我们可以用手掌记忆法记住x,y,z轴正轴方向,左手掌心向下,大拇指向自己表示z轴正轴,食指垂直大拇指指向右手表示x轴正轴,中指垂直食指向下表示y轴正轴。
2. 3D盒子布局
当鼠标移入上下左右的某一个方向位置内时,隐藏的文字面要放置在对应面。
2.1 文字面在左侧
将文字面绕Y轴逆时针旋转90度,使文字正面朝外,由于旋转中心在(0,0)位置,需要将文字面向Z轴平移-w个单位。
--w: 180px;
--h: 180px;
.left-in .mask,
.left-out .mask {
transform-origin: 0% 0%;
transform: translate3d(0, 0, calc(0px - var(--w))) rotate3d(0, 1, 0, -90deg);
}
2.2 文字面在右侧
将文字面绕Y轴顺时针旋转90度,使文字正面朝外,由于旋转中心在(0,0)位置,需要将文字面沿X轴平移w个单位。
.right-in .mask,
.right-out .mask {
transform: translate3d(100%, 0, 0) rotate3d(0, 1, 0, 90deg);
}
2.3 文字面在顶部
将文字面绕X轴顺时针旋转90度,使文字正面朝外,由于旋转中心在(0,0)位置,需要将文字面沿Z轴平移-w个单位。
.top-in .mask,
.top-out .mask {
transform: translate3d(0, 0, calc(0px - var(--w))) rotate3d(1, 0, 0, 90deg);
}
2.4 文字面在底部
将文字面绕X轴逆时针旋转90度,使文字正面朝外,由于旋转中心在(0,0)位置,需要将文字面沿Y轴平移w个单位。
.bottom-in .mask,
.bottom-out .mask {
transform: translate3d(0, 100%, 0) rotate3d(1, 0, 0, -90deg);
}
3. 鼠标移入移出事件
3.1 鼠标移入事件
当鼠标移入元素内时如何判断元素是从上下左右哪个位置进入元素?上一篇中,我将元素内划分为四个三角形,分别表示上下左右四个方位。
用js怎么判断鼠标所在位置属于哪一个方位呢?可以看出,两条斜线分别表示y=x及y=-x+180,所以当offsetX大于等于90,并且在offsetY小于等于offsetX,offsetY大于等于-offsetX + 180表示右侧,其他方位同样可得。
const eles = document.getElementsByClassName('item-wrapper')
const itemWrapper = document.getElementsByClassName('item-wrapper');
const width = itemWrapper[0].clientWidth;
new Array(...eles).forEach(ele => {
let isEnter = false;
ele.addEventListener('mouseenter', e => {
if (!isEnter) {
isEnter = true;
const { offsetX, offsetY } = e;
const child = e.currentTarget.children[0];
if (offsetX > width / 2 && offsetY > -offsetX + width && offsetY < offsetX) {
child.className = 'item-block right-in';
} else if (offsetX < width / 2 && offsetY > offsetX && offsetY < -offsetX + width) {
child.className = 'item-block left-in';
} else if (offsetY < width / 2 && offsetY < offsetX && offsetY < -offsetX + width) {
child.className = 'item-block top-in';
} else if (offsetY > width / 2 && offsetY > offsetX && offsetY > -offsetX + width) {
child.className = 'item-block bottom-in';
}
}
})
})
3.2 鼠标移出事件
鼠标移出时,移出位置同样根据两条斜线y=x及y=-x+180划分,顶部y<0,底部y>w,左侧x<0,右侧x>w。
let isLeave = false;
ele.addEventListener('mouseleave', e => {
if (!isLeave) {
isLeave = true;
const { offsetX, offsetY } = e;
const child = e.currentTarget.children[0];
if (offsetX >= width && offsetY >= -offsetX + width && offsetY <= offsetX) {
child.className = 'item-block right-out';
} else if (offsetX <= 0 && offsetY >= offsetX && offsetY <= -offsetX + width) {
child.className = 'item-block left-out';
} else if (offsetY <= 0 && offsetY <= offsetX && offsetY <= -offsetX + width) {
child.className = 'item-block top-out';
} else if (offsetY >= width && offsetY >= offsetX && offsetY >= -offsetX + width) {
child.className = 'item-block bottom-out';
}
isEnter = false;
isLeave = false;
ele.removeEventListener('mouseleave', e => {})
}
})
4. 3D透视
没有透视下的动画效果,远近边的长度都相同,旋转的效果感觉就像是一个面平移过去。
用perspective属性给元素块添加透视效果后:
源代码: