简体   繁体   English

jQuery:滚动时鼠标跟随元素不会与光标粘在一起

[英]jQuery: mouse following element wont stick with cursor when scrolling

I have a small problem and I can't get it to fix. 我有一个小问题,无法解决。

I developed a element that is following the cursor and way it needs to function is that the border around the cursor needs to stick with the position of the cursor. 我开发了一个跟随光标的元素,它需要起作用的方式是,光标周围的边框必须与光标的位置保持一致。 But the problem I've got right now is that it won't stick when scrolling down. 但是我现在遇到的问题是,向下滚动时它不会粘住。

You can check at the demo below what I mean. 您可以在下面的演示中查看我的意思。

The problem seems that it is not correctly checking the height of the page, thats why its not correctly positioning. 问题似乎是它没有正确检查页面的高度,这就是为什么它无法正确定位的原因。 Am I right? 我对吗?

const windowW = window.innerWidth;
const windowH = window.innerHeight;
const maxLength = Math.max(windowW, windowH);

const cursorWidth = 100;
const cursorR = cursorWidth >> 1;
const cursorDelay = 10;

const buttons = Array.from(document.querySelectorAll('.border-button'));

const cursor = {
    el: document.querySelector('.border-cursor'),
    x: windowW >> 1,
    y: windowH >> 1,
    scaleX: 1,
    scaleY: 1,
};

const target = {
    x: windowW >> 1,
    y: windowH >> 1,
    width: cursorWidth,
    followMouse: true,
};

const norm = (val, max, min) => (val - min) / (max - min);
const toDegrees = r => r * (180 / Math.PI);
const distanceBetween = (v1, v2) => Math.sqrt((v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y +- v2.y));

const loop = () => {
    const destX = target.x - cursorR;
    const destY = target.y - cursorR;

    const newX = cursor.x + ((destX - cursor.x) / cursorDelay);
    const newY = cursor.y + ((destY - cursor.y) / cursorDelay);
    const angle = angleBetween(cursor.x, cursor.y, newX, newY);

    if (target.followMouse) {
        const distance = Math.abs(distanceBetween(target, cursor));
        const scale = norm(distance, maxLength, cursorR);
        cursor.scaleX = 1 + scale;
        cursor.scaleY = 1 - scale;
    } else {
        const targetScale = target.width / cursorWidth;

        cursor.scaleX += (targetScale - cursor.scaleX) / (cursorDelay / 2);
        cursor.scaleY = cursor.scaleX;
    }

    cursor.x = newX;
    cursor.y = newY;

    cursor.el.style.transform = `translate(${cursor.x}px, ${cursor.y}px) rotate(${toDegrees(angle)}deg) scale(${cursor.scaleX}, ${cursor.scaleY})`;

    requestAnimationFrame(loop);
};

const angleBetween = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1);

const onPointerMove = (e) => {
    if (!target.followMouse) {
        return;
    }

    const pointer = (e.touches && e.touches.length) ? e.touches[0] : e;
    const { clientX: x, clientY: y } = pointer;

    target.x = x;
    target.y = y;
};

const onPointerOver = (e) => {
    const btn = e.target;
    const rect = btn.getBoundingClientRect();

    target.followMouse = false;
    target.x = rect.left + (rect.width >> 1);
    target.y = rect.top + (rect.height >> 1);

    target.width = Math.max(rect.width, rect.height) + 50;
};

const onPointerOut = () => {
    target.followMouse = true;
    target.width = cursorWidth;
};

document.body.addEventListener('mousemove', onPointerMove);
document.body.addEventListener('touchmove', onPointerMove);

buttons.forEach((btn) => {
    btn.addEventListener('touchstart', onPointerOver);
    btn.addEventListener('mouseover', onPointerOver);

    btn.addEventListener('touchend', onPointerOut);
    btn.addEventListener('mouseout', onPointerOut);
});

loop();

 const windowW = window.innerWidth; const windowH = window.innerHeight; const maxLength = Math.max(windowW, windowH); const cursorWidth = 100; const cursorR = cursorWidth >> 1; const cursorDelay = 10; const buttons = Array.from(document.querySelectorAll('.border-button')); const cursor = { el: document.querySelector('.border-cursor'), x: windowW >> 1, y: windowH >> 1, scaleX: 1, scaleY: 1, }; const target = { x: windowW >> 1, y: windowH >> 1, width: cursorWidth, followMouse: true, }; const norm = (val, max, min) => (val - min) / (max - min); const toDegrees = r => r * (180 / Math.PI); const distanceBetween = (v1, v2) => Math.sqrt((v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y +- v2.y)); const loop = () => { const destX = target.x - cursorR; const destY = target.y - cursorR; const newX = cursor.x + ((destX - cursor.x) / cursorDelay); const newY = cursor.y + ((destY - cursor.y) / cursorDelay); const angle = angleBetween(cursor.x, cursor.y, newX, newY); if (target.followMouse) { const distance = Math.abs(distanceBetween(target, cursor)); const scale = norm(distance, maxLength, cursorR); cursor.scaleX = 1 + scale; cursor.scaleY = 1 - scale; } else { const targetScale = target.width / cursorWidth; cursor.scaleX += (targetScale - cursor.scaleX) / (cursorDelay / 2); cursor.scaleY = cursor.scaleX; } cursor.x = newX; cursor.y = newY; cursor.el.style.transform = `translate(${cursor.x}px, ${cursor.y}px) rotate(${toDegrees(angle)}deg) scale(${cursor.scaleX}, ${cursor.scaleY})`; requestAnimationFrame(loop); }; const angleBetween = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1); const onPointerMove = (e) => { if (!target.followMouse) { return; } const pointer = (e.touches && e.touches.length) ? e.touches[0] : e; const { clientX: x, clientY: y } = pointer; target.x = x; target.y = y; }; const onPointerOver = (e) => { const btn = e.target; const rect = btn.getBoundingClientRect(); target.followMouse = false; target.x = rect.left + (rect.width >> 1); target.y = rect.top + (rect.height >> 1); target.width = Math.max(rect.width, rect.height) + 50; }; const onPointerOut = () => { target.followMouse = true; target.width = cursorWidth; }; document.body.addEventListener('mousemove', onPointerMove); document.body.addEventListener('touchmove', onPointerMove); buttons.forEach((btn) => { btn.addEventListener('touchstart', onPointerOver); btn.addEventListener('mouseover', onPointerOver); btn.addEventListener('touchend', onPointerOut); btn.addEventListener('mouseout', onPointerOut); }); loop(); 
 html, body { margin: 0; padding: 0; } .wrapper { width: 100vw; min-height: 1500px; display: flex; flex-direction: row; align-items: center; } .container { width: 100%; display: flex; padding: 0 1rem; } .cursor { position: absolute; z-index: 10; width: 100px; height: 100px; border: 2px solid #23bfa0; border-radius: 50%; pointer-events: none; } .button { padding: 1rem; background-color: #23bfa0; border: none; box-shadow: 0 0 7px 0px rgba(0, 0, 0, 0.2); color: white; font-size: 1.2rem; cursor: pointer; transition: box-shadow 0.1s ease-in, transform 0.1s ease-in; &--small { padding: 0.75rem; font-size: 0.75rem; } &:hover { transform: translate(0%, -2px); box-shadow: 0px 4px 9px 2px rgba(0, 0, 0, 0.2) } } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> <div class="cursor border-cursor"></div> <div class="wrapper"> <div class="container"> <button class="button button--small border-button">small</button> <button class="button border-button">hover me</button> <button class="button border-button">hover me more</button> </div> </div> </body> 

In onPointerMove , try replacing: onPointerMove ,尝试替换:

const { clientX: x, clientY: y } = pointer;

with: 与:

const { pageX: x, pageY: y } = pointer;

Here's a good post explaining the differences between these values: https://stackoverflow.com/a/9335517/965834 这是一篇很好的文章,解释了这些值之间的区别: https : //stackoverflow.com/a/9335517/965834

Also, change: 另外,更改:

target.x = rect.left + (rect.width >> 1);
target.y = rect.top + (rect.height >> 1);

into: 变成:

target.x = window.scrollX + rect.left + (rect.width >> 1);
target.y = window.scrollY + rect.top + (rect.height >> 1);

This takes into account scrolling when calculating the position of your buttons. 这在计算按钮位置时考虑了滚动。

Demo : 演示

 const windowW = window.innerWidth; const windowH = window.innerHeight; const maxLength = Math.max(windowW, windowH); const cursorWidth = 100; const cursorR = cursorWidth >> 1; const cursorDelay = 10; const buttons = Array.from(document.querySelectorAll('.border-button')); const cursor = { el: document.querySelector('.border-cursor'), x: windowW >> 1, y: windowH >> 1, scaleX: 1, scaleY: 1, }; const target = { x: windowW >> 1, y: windowH >> 1, width: cursorWidth, followMouse: true, }; const norm = (val, max, min) => (val - min) / (max - min); const toDegrees = r => r * (180 / Math.PI); const distanceBetween = (v1, v2) => Math.sqrt((v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y +- v2.y)); const loop = () => { const destX = target.x - cursorR; const destY = target.y - cursorR; const newX = cursor.x + ((destX - cursor.x) / cursorDelay); const newY = cursor.y + ((destY - cursor.y) / cursorDelay); const angle = angleBetween(cursor.x, cursor.y, newX, newY); if (target.followMouse) { const distance = Math.abs(distanceBetween(target, cursor)); const scale = norm(distance, maxLength, cursorR); cursor.scaleX = 1 + scale; cursor.scaleY = 1 - scale; } else { const targetScale = target.width / cursorWidth; cursor.scaleX += (targetScale - cursor.scaleX) / (cursorDelay / 2); cursor.scaleY = cursor.scaleX; } cursor.x = newX; cursor.y = newY; cursor.el.style.transform = `translate(${cursor.x}px, ${cursor.y}px) rotate(${toDegrees(angle)}deg) scale(${cursor.scaleX}, ${cursor.scaleY})`; requestAnimationFrame(loop); }; const angleBetween = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1); const onPointerMove = (e) => { if (!target.followMouse) { return; } const pointer = (e.touches && e.touches.length) ? e.touches[0] : e; const { pageX: x, pageY: y } = pointer; target.x = x; target.y = y; }; const onPointerOver = (e) => { const btn = e.target; const rect = btn.getBoundingClientRect(); target.followMouse = false; target.x = window.scrollX + rect.left + (rect.width >> 1); target.y = window.scrollY + rect.top + (rect.height >> 1); target.width = Math.max(rect.width, rect.height) + 50; }; const onPointerOut = () => { target.followMouse = true; target.width = cursorWidth; }; document.body.addEventListener('mousemove', onPointerMove); document.body.addEventListener('touchmove', onPointerMove); buttons.forEach((btn) => { btn.addEventListener('touchstart', onPointerOver); btn.addEventListener('mouseover', onPointerOver); btn.addEventListener('touchend', onPointerOut); btn.addEventListener('mouseout', onPointerOut); }); loop(); 
 html, body { margin: 0; padding: 0; } .wrapper { width: 100vw; min-height: 1500px; display: flex; flex-direction: row; align-items: center; } .container { width: 100%; display: flex; padding: 0 1rem; } .cursor { position: absolute; z-index: 10; width: 100px; height: 100px; border: 2px solid #23bfa0; border-radius: 50%; pointer-events: none; } .button { padding: 1rem; background-color: #23bfa0; border: none; box-shadow: 0 0 7px 0px rgba(0, 0, 0, 0.2); color: white; font-size: 1.2rem; cursor: pointer; transition: box-shadow 0.1s ease-in, transform 0.1s ease-in; &--small { padding: 0.75rem; font-size: 0.75rem; } &:hover { transform: translate(0%, -2px); box-shadow: 0px 4px 9px 2px rgba(0, 0, 0, 0.2) } } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> <div class="cursor border-cursor"></div> <div class="wrapper"> <div class="container"> <button class="button button--small border-button">small</button> <button class="button border-button">hover me</button> <button class="button border-button">hover me more</button> </div> </div> </body> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM