<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>磁性鼠标悬停互动</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
background: #121212;
cursor: none;
}
.cursor {
width: var(--size);
height: var(--size);
border-radius: 50%;
position: absolute;
left: 0;
top: 0;
transform: translate(-50%, -50%);
pointer-events: none;
z-index: 100;
}
.cursor--large {
--size: 40px;
border: 1px solid #ff3c3c;
}
.cursor--small {
--size: 10px;
background: #ff3c3c;
}
main {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
main button {
--size: 60px;
border: none;
min-width: var(--size);
min-height: var(--size);
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
background: rgba(255, 255, 255, 0.08);
color: #fff;
transition: background 200ms ease, color 200ms ease;
cursor: none;
}
main:hover button {
background: rgba(255, 255, 255, 0.04);
color: rgba(255, 255, 255, 0.04);
}
main:hover button:hover {
color: #fff;
}</style>
</head>
<body>
<script src="js/gsap.min.js"></script>
<!--图标库-->
<script src="https://unpkg.com/ionicons@5.0.0/dist/ionicons.js"></script>
<main>
<button>
<ion-icon name="logo-facebook"></ion-icon>
</button>
<button>
<ion-icon name="logo-twitter"></ion-icon>
</button>
<button>
<ion-icon name="logo-instagram"></ion-icon>
</button>
<button>
<ion-icon name="logo-youtube"></ion-icon>
</button>
<button>
<ion-icon name="logo-dribbble"></ion-icon>
</button>
</main>
<div class="cursor cursor--large"></div>
<div class="cursor cursor--small"></div>
<script>
console.clear();
const { gsap } = window;
const cursorOuter = document.querySelector(".cursor--large");
const cursorInner = document.querySelector(".cursor--small");
let isStuck = false;
let mouse = {
x: -100,
y: -100,
};
let cursorOuterOriginalState = {
width: cursorOuter.getBoundingClientRect().width,
height: cursorOuter.getBoundingClientRect().height,
};
const buttons = document.querySelectorAll("main button");
buttons.forEach((button) => {
button.addEventListener("pointerenter", handleMouseEnter);
button.addEventListener("pointerleave", handleMouseLeave);
});
document.body.addEventListener("pointermove", updateCursorPosition);
document.body.addEventListener("pointerdown", () => {
gsap.to(cursorInner, 0.15, {
scale: 2,
});
});
document.body.addEventListener("pointerup", () => {
gsap.to(cursorInner, 0.15, {
scale: 1,
});
});
function updateCursorPosition(e) {
mouse.x = e.pageX;
mouse.y = e.pageY;
}
function updateCursor() {
gsap.set(cursorInner, {
x: mouse.x,
y: mouse.y,
});
if (!isStuck) {
gsap.to(cursorOuter, {
duration: 0.15,
x: mouse.x,
y: mouse.y,
});
}
requestAnimationFrame(updateCursor);
}
updateCursor();
function handleMouseEnter(e) {
isStuck = true;
const targetBox = e.currentTarget.getBoundingClientRect();
gsap.to(cursorOuter, 0.2, {
x: targetBox.left + targetBox.width / 2,
y: targetBox.top + targetBox.height / 2,
width: targetBox.width,
height: targetBox.width,
borderRadius: 0,
backgroundColor: "rgba(255, 255, 255, 0.1)",
});
}
function handleMouseLeave(e) {
isStuck = false;
gsap.to(cursorOuter, 0.2, {
width: cursorOuterOriginalState.width,
height: cursorOuterOriginalState.width,
borderRadius: "50%",
backgroundColor: "transparent",
});
}
</script>
</body>
</html>