mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-17 15:09:31 +00:00
proxio主题加入部分动画
This commit is contained in:
97
components/CursorDot.js
Normal file
97
components/CursorDot.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const CursorDot = () => {
|
||||
useEffect(() => {
|
||||
// 创建小白点元素
|
||||
const dot = document.createElement('div');
|
||||
dot.classList.add('cursor-dot');
|
||||
document.body.appendChild(dot);
|
||||
|
||||
// 鼠标坐标和缓动目标坐标
|
||||
let mouse = { x: -100, y: -100 }; // 初始位置在屏幕外
|
||||
let dotPos = { x: mouse.x, y: mouse.y };
|
||||
|
||||
// 监听鼠标移动
|
||||
const handleMouseMove = (e) => {
|
||||
mouse.x = e.clientX;
|
||||
mouse.y = e.clientY;
|
||||
};
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
|
||||
// 监听鼠标悬停在可点击对象上的事件
|
||||
const handleMouseEnter = () => {
|
||||
dot.classList.add('cursor-dot-hover'); // 添加放大样式
|
||||
};
|
||||
const handleMouseLeave = () => {
|
||||
dot.classList.remove('cursor-dot-hover'); // 移除放大样式
|
||||
};
|
||||
|
||||
|
||||
// 为所有可点击元素和包含 hover 或 group-hover 类名的元素添加事件监听
|
||||
const clickableElements = document.querySelectorAll(
|
||||
'a, button, [role="button"], [onclick], [cursor="pointer"], [class*="hover"], [class*="group-hover"]'
|
||||
);
|
||||
clickableElements.forEach((el) => {
|
||||
el.addEventListener('mouseenter', handleMouseEnter);
|
||||
el.addEventListener('mouseleave', handleMouseLeave);
|
||||
});
|
||||
|
||||
// 动画循环:延迟更新小白点位置
|
||||
const updateDotPosition = () => {
|
||||
const damping = 0.2; // 阻尼系数,值越小延迟越明显
|
||||
dotPos.x += (mouse.x - dotPos.x) * damping;
|
||||
dotPos.y += (mouse.y - dotPos.y) * damping;
|
||||
|
||||
// 更新DOM
|
||||
dot.style.left = `${dotPos.x}px`;
|
||||
dot.style.top = `${dotPos.y}px`;
|
||||
|
||||
requestAnimationFrame(updateDotPosition);
|
||||
};
|
||||
|
||||
// 启动动画
|
||||
updateDotPosition();
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
clickableElements.forEach((el) => {
|
||||
el.removeEventListener('mouseenter', handleMouseEnter);
|
||||
el.removeEventListener('mouseleave', handleMouseLeave);
|
||||
});
|
||||
document.body.removeChild(dot);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<style jsx global>{`
|
||||
.cursor-dot {
|
||||
position: fixed;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 9999;
|
||||
transition: transform 100ms ease-out, width 200ms ease, height 200ms ease; /* 添加尺寸平滑过渡 */
|
||||
mix-blend-mode: difference; /* 可选:增强对比度 */
|
||||
}
|
||||
|
||||
.cursor-dot-hover {
|
||||
border: 1px solid rgba(167, 167, 167, 0.14); /* 鼠标悬停时的深灰色边框,厚度为1px */
|
||||
width: 60px; /* 放大 */
|
||||
height: 60px; /* 放大 */
|
||||
background: hsla(0, 0%, 100%, 0.04); /* 半透明背景 */
|
||||
-webkit-backdrop-filter: blur(5px); /* 毛玻璃效果 */
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.dark .cursor-dot-hover {
|
||||
border: 1px solid rgba(66, 66, 66, 0.66); /* 鼠标悬停时的深灰色边框,厚度为1px */
|
||||
}
|
||||
`}</style>
|
||||
);
|
||||
};
|
||||
|
||||
export default CursorDot;
|
||||
@@ -1,52 +1,53 @@
|
||||
/**
|
||||
* 鼠标滚动阻尼感
|
||||
*/
|
||||
import { useEffect } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { loadExternalResource } from '@/lib/utils'
|
||||
|
||||
/**
|
||||
* 鼠标点击烟花特效
|
||||
* 滚动阻尼特效
|
||||
* 目前只用在proxio主题
|
||||
* @returns
|
||||
*/
|
||||
const Lenis = () => {
|
||||
const lenisRef = useRef(null) // 用于存储 Lenis 实例
|
||||
|
||||
useEffect(() => {
|
||||
// 异步加载
|
||||
async function loadLenis() {
|
||||
loadExternalResource(
|
||||
'/js/lenis.js',
|
||||
'js'
|
||||
).then(() => {
|
||||
console.log('Lenis',window.Lenis)
|
||||
if(!window.Lenis) {
|
||||
loadExternalResource('/js/lenis.js', 'js').then(() => {
|
||||
// console.log('Lenis', window.Lenis)
|
||||
if (!window.Lenis) {
|
||||
console.error('Lenis not loaded')
|
||||
return
|
||||
}
|
||||
const Lenis = window.Lenis
|
||||
// 创建 Lenis 实例
|
||||
|
||||
const lenis = new Lenis({
|
||||
duration: 1.2,
|
||||
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou
|
||||
direction: 'vertical', // vertical, horizontal
|
||||
gestureDirection: 'vertical', // vertical, horizontal, both
|
||||
smooth: true,
|
||||
mouseMultiplier: 1,
|
||||
smoothTouch: false,
|
||||
touchMultiplier: 2,
|
||||
infinite: false,
|
||||
})
|
||||
|
||||
//get scroll value
|
||||
lenis.on('scroll', ({ scroll, limit, velocity, direction, progress }) => { console.log({ scroll, limit, velocity, direction, progress })
|
||||
})
|
||||
|
||||
function raf(time) {
|
||||
lenis.raf(time)
|
||||
requestAnimationFrame(raf)
|
||||
}
|
||||
|
||||
requestAnimationFrame(raf)
|
||||
// 创建 Lenis 实例
|
||||
const lenis = new Lenis({
|
||||
duration: 1.2,
|
||||
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou
|
||||
direction: 'vertical', // vertical, horizontal
|
||||
gestureDirection: 'vertical', // vertical, horizontal, both
|
||||
smooth: true,
|
||||
mouseMultiplier: 1,
|
||||
smoothTouch: false,
|
||||
touchMultiplier: 2,
|
||||
infinite: false,
|
||||
})
|
||||
|
||||
// 存储实例到 ref
|
||||
lenisRef.current = lenis
|
||||
|
||||
// 监听滚动事件
|
||||
// lenis.on('scroll', ({ scroll, limit, velocity, direction, progress }) => {
|
||||
// // console.log({ scroll, limit, velocity, direction, progress })
|
||||
// })
|
||||
|
||||
// 动画帧循环
|
||||
function raf(time) {
|
||||
lenis.raf(time)
|
||||
requestAnimationFrame(raf)
|
||||
}
|
||||
|
||||
requestAnimationFrame(raf)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,6 +55,11 @@ const Lenis = () => {
|
||||
|
||||
return () => {
|
||||
// 在组件卸载时清理资源
|
||||
if (lenisRef.current) {
|
||||
lenisRef.current.destroy() // 销毁 Lenis 实例
|
||||
lenisRef.current = null
|
||||
// console.log('Lenis instance destroyed')
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user