前置知识

追踪鼠标位置

通过js去追踪鼠标经过按钮是的x轴和y轴的位置:

var card =document.querySelector('.card')
document.querySelector('.card').onmousemove = (e) => {
  const x = e.pageX; // 鼠标位置x轴
  const y = e.pageY; // 鼠标位置y轴
  card.style.setProperty(...); // 设置样式
}

获取当前元素距离视窗的距离

网上查一查,有很多都是通过offsetTop、offsetLeft来计算出来的。我按照网上的查到的资料用了一次,算出来了一堆错误答案。需要注意的是scrolltop 和 offsettop 是距离父元素的。下面我要分享的这个方法,兼容性很好(ie4都ok),而且很方便,不会算错。

Element.getBoundingClientRect()方法返回一个DOMRect 对象,是一组矩形集合,返回值主要包含lefttopbottomrightwidthheightxy等。

使用方法如下:

let elementToTop = element.getBoundingClientRect().top  // element的顶边到视口顶部的距离
let elementToLeft = element.getBoundingClientRect().left // element的左边到视口左边的距离
let elementToBottom = element.getBoundingClientRect().bottom // element的底边到视口「顶部」的距离
let elementToRight = element.getBoundingClientRect().right // element的右边到视口「左边」的距离

得到的值是相对于视口而言的,即如果页面的滚动位置发生变化,那么得到的top、left也会发生变化;如果需要计算到body边框的距离,需要再加上网页滚动条的长度。

旋转与透视属性

不了解这块儿的同学可以看一下这篇文章

几行CSS让你的页面立体起来

需要注意的是,perspective属性要设置在需要透视效果的元素的父元素上。

代码实现

来看一个Demo~

floatWithPoint.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./floatWithPoint.css">
</head>
</style>
<body>
    <br/><br/><br/><br/><br/>
    <div class="wrap">
        <div class="card">Card</div>
        <div class="card">Card</div>
        <div class="card">Card</div>
    </div>
</body>
<script type="text/javascript" src="./floatWithPoint.js"></script>
</html>

floatWithPoint.css如下:

*{
    margin: 0;
    padding: 0;
}
.wrap{
    perspective: 800px;
    perspective-origin: center;
    display: flex;
}
.card{
    background-color: blanchedalmond;
    width: 200px;
    height: 80px;
    border: 1px solid pink;
    text-align: center;
    color: coral;
    font-size: 24px;
    font-family: 'Helvetica Neue', Helvetica;
    line-height: 80px;
    transition: box-shadow 0.35s ease, transform 0.15s;
    box-shadow: 1px 1px 10px rgba(255, 157, 157, 10%);
}

.card:hover{
    transition: box-shadow 0.25s ease;
    box-shadow: 4px 4px 30px 2px rgba(255, 157, 157, 0.2);
}

.card:active{
    transition: box-shadow 0.25s ease;
    box-shadow: 1px 1px 10px rgba(255, 157, 157, 10%);
}

floatWithPoint.js如下:

let cards = document.querySelectorAll('.card');
    cards.forEach((card) => {
        var _x = card.getBoundingClientRect().left + card.offsetWidth / 2; // 目标元素的中心位置
        var _y = card.getBoundingClientRect().top + card.offsetHeight / 2; // 目标元素的中心位置
        card.onmousemove = (e) => {
            const x = e.pageX; // 鼠标位置x轴
            const y = e.pageY; // y轴
            card.style.setProperty('transform', `rotateX(${-(_y - y) / 4}deg) rotateY(${-(x - _x) / 8}deg)`);
            // console.log({_X: (_y-y)/4, Y: (x-_x)/8, xp: x, yp: y, _x, _y});
        }
        // 监听鼠标移出事件
        card.onmouseout = (e) => {
            card.style.setProperty('transform', `rotateX(${0}deg) rotateY(${0}deg)`);
        }
    })

let elementToTop = element.getBoundingClientRect().top  // element的顶边到视口顶部的距离

getBoundingClientRect()需要注意,其视口是你刷新页面时候的位置!

所以,当你滚动页面以后刷新页面,其值会发生改变!这一点不如offsetTop好使。


A Student on the way to full stack of Web3.