Skip to content

Commit d230d80

Browse files
committed
refactor(Header): 将Header组件重构为ScrollHeader组件
将Header组件中的滚动逻辑提取到ScrollHeader组件中,以提高代码的可维护性和复用性。同时优化了滚动事件的处理,添加了防抖和初始状态设置。
1 parent 2f458d8 commit d230d80

2 files changed

Lines changed: 51 additions & 94 deletions

File tree

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
---
2-
// Header component with smart scroll behavior
2+
import ScrollHeader from "../components/solid/ScrollHeader";
33
---
44

5-
<header
6-
class="fixed top-0 w-full z-50 transition-all duration-300 transform"
7-
id="smart-header"
8-
>
5+
<ScrollHeader client:load>
96
<div class="navbar container mx-auto px-4 h-16">
107
<div class="navbar-start">
118
<div class="dropdown">
@@ -73,75 +70,4 @@
7370
<button class="btn btn-primary ml-2">登录</button>
7471
</div>
7572
</div>
76-
</header>
77-
78-
<script>
79-
// Get the header element
80-
const header = document.getElementById('smart-header');
81-
let lastScrollY = 0;
82-
let isAtTop = true;
83-
84-
// Handle scroll events
85-
function handleScroll() {
86-
// Safety check in case header element doesn't exist
87-
if (!header) return;
88-
89-
const currentScrollY = window.scrollY;
90-
const scrollDelta = currentScrollY - lastScrollY;
91-
92-
// Check if at top of page
93-
if (currentScrollY < 10) {
94-
isAtTop = true;
95-
header.classList.remove('-translate-y-full');
96-
header.classList.add('translate-y-0');
97-
header.classList.remove('bg-base-100/95', 'backdrop-blur-sm', 'shadow-md');
98-
header.classList.add('bg-base-100');
99-
} else {
100-
if (isAtTop) {
101-
isAtTop = false;
102-
header.classList.remove('bg-base-100');
103-
header.classList.add('bg-base-100/95', 'backdrop-blur-sm', 'shadow-md');
104-
}
105-
106-
// Ignore small scroll movements to prevent jitter
107-
if (Math.abs(scrollDelta) < 5) {
108-
lastScrollY = currentScrollY;
109-
return;
110-
}
111-
112-
// Show/hide based on scroll direction
113-
if (scrollDelta < 0) {
114-
// Scrolling up - show header
115-
header.classList.remove('-translate-y-full');
116-
header.classList.add('translate-y-0');
117-
} else if (currentScrollY > 100) {
118-
// Only hide when we've scrolled down a bit
119-
header.classList.remove('translate-y-0');
120-
header.classList.add('-translate-y-full');
121-
}
122-
}
123-
124-
lastScrollY = currentScrollY;
125-
}
126-
127-
// Add scroll event listener with throttling for better performance
128-
let ticking = false;
129-
130-
// Only add event listener if header exists
131-
if (header) {
132-
window.addEventListener('scroll', function() {
133-
if (!ticking) {
134-
window.requestAnimationFrame(function() {
135-
handleScroll();
136-
ticking = false;
137-
});
138-
ticking = true;
139-
}
140-
});
141-
142-
// Initialize header state
143-
handleScroll();
144-
} else {
145-
console.warn('Header element with ID "smart-header" not found');
146-
}
147-
</script>
73+
</ScrollHeader>
Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { createSignal, createEffect, onCleanup } from 'solid-js';
1+
import { createSignal, createEffect, onCleanup, onMount } from "solid-js";
22

33
export default function ScrollHeader(props) {
44
const [isVisible, setIsVisible] = createSignal(true);
55
const [lastScrollY, setLastScrollY] = createSignal(0);
66
const [isAtTop, setIsAtTop] = createSignal(true);
7-
7+
8+
// Handle scroll events with debounce
89
const handleScroll = () => {
910
const currentScrollY = window.scrollY;
1011

@@ -13,38 +14,68 @@ export default function ScrollHeader(props) {
1314
setIsAtTop(true);
1415
setIsVisible(true);
1516
} else {
16-
setIsAtTop(false);
17+
// Update at-top state if needed
18+
if (isAtTop()) {
19+
setIsAtTop(false);
20+
}
1721

18-
// Show/hide based on scroll direction
19-
if (currentScrollY < lastScrollY()) {
22+
// Check scroll direction
23+
const isScrollingUp = currentScrollY < lastScrollY();
24+
25+
if (isScrollingUp) {
2026
// Scrolling up - show header
2127
setIsVisible(true);
22-
} else if (currentScrollY > 50 && currentScrollY > lastScrollY()) {
23-
// Scrolling down and not at the very top - hide header
24-
setIsVisible(false);
28+
} else {
29+
// Scrolling down - hide header after scrolling past threshold
30+
if (currentScrollY > 100) {
31+
setIsVisible(false);
32+
}
2533
}
2634
}
2735

36+
// Update last scroll position
2837
setLastScrollY(currentScrollY);
2938
};
30-
39+
40+
// Throttle scroll events using requestAnimationFrame
41+
let isThrottled = false;
42+
43+
const onScroll = () => {
44+
if (!isThrottled) {
45+
requestAnimationFrame(() => {
46+
handleScroll();
47+
isThrottled = false;
48+
});
49+
isThrottled = true;
50+
}
51+
};
52+
53+
onMount(() => {
54+
// Set initial scroll position
55+
setLastScrollY(window.scrollY);
56+
// Initialize header state
57+
handleScroll();
58+
});
59+
3160
createEffect(() => {
32-
window.addEventListener('scroll', handleScroll);
61+
// Add scroll event listener
62+
window.addEventListener("scroll", onScroll, { passive: true });
3363

3464
onCleanup(() => {
35-
window.removeEventListener('scroll', handleScroll);
65+
// Remove scroll event listener
66+
window.removeEventListener("scroll", onScroll);
3667
});
3768
});
38-
69+
3970
return (
40-
<header
41-
class={`fixed top-0 w-full z-50 transition-all duration-300 ${
42-
isVisible() ? 'translate-y-0' : '-translate-y-full'
71+
<header
72+
class={`fixed top-0 w-full z-50 transition-all duration-300 transform ${
73+
isVisible() ? "translate-y-0" : "-translate-y-full"
4374
} ${
44-
!isAtTop() ? 'bg-base-100/95 backdrop-blur-sm shadow-md' : 'bg-base-100'
75+
!isAtTop() ? "bg-base-100/95 backdrop-blur-sm shadow-md" : "bg-base-100"
4576
}`}
4677
>
4778
{props.children}
4879
</header>
4980
);
50-
}
81+
}

0 commit comments

Comments
 (0)