jQuery:鼠标跟随元素滚动时不会粘住光标

时间:2018-03-17 00:33:51

标签: javascript jquery css cursor mouse

我遇到了一个小问题,我无法解决问题。

我开发了一个跟随光标的元素,它需要运行的方式是光标周围的边框需要坚持光标的位置。但我现在遇到的问题是它在向下滚动时不会坚持。

您可以在下面的演示中查看我的意思。

问题似乎是没有正确检查页面的高度,这就是为什么它没有正确定位。我是对的吗?

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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

final List<Integer> integers = new List(); // Do whatever operations you want with the list final List<Integer> integersInmutable = Collections.unmodifiableList(integers); integers = null; // Better safe than sorry… integersInmutable.add(1); // <- runtime exception integersInmutable = new List(); // <- compiler error 中,尝试替换:

onPointerMove

使用:

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

这是一篇很好的帖子,解释了这些价值观之间的差异: https://stackoverflow.com/a/9335517/965834

另外,改变:

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

成:

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

这会在计算按钮位置时考虑滚动。

<强>演示

&#13;
&#13;
target.x = window.scrollX + rect.left + (rect.width >> 1);
target.y = window.scrollY + rect.top + (rect.height >> 1);
&#13;
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();
&#13;
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)
  }
}
&#13;
&#13;
&#13;