Skip to content

Commit 455b1b7

Browse files
committed
fix(scroll): 修复页面滚动时的闪烁问题
1 parent 544698c commit 455b1b7

3 files changed

Lines changed: 140 additions & 44 deletions

File tree

script-hook-website/src/App.css

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,38 @@
22
min-height: 100vh;
33
display: flex;
44
flex-direction: column;
5+
contain: layout style;
6+
will-change: contents;
7+
}
8+
9+
/* 防止滚动闪烁 */
10+
html {
11+
scroll-behavior: smooth;
12+
height: 100%;
13+
overflow-anchor: none;
14+
}
15+
16+
body {
17+
min-height: 100%;
18+
overflow-x: hidden;
19+
}
20+
21+
/* 确保图片和其他元素在加载前预留空间 */
22+
img, iframe, video {
23+
height: auto;
24+
max-width: 100%;
25+
}
26+
27+
/* 确保主要区域有最小高度,防止布局跳跃 */
28+
.container {
29+
min-height: 50vh;
30+
/* 减少布局计算 */
31+
contain: layout style;
32+
}
33+
34+
/* 优化滚动体验 */
35+
@media (prefers-reduced-motion: no-preference) {
36+
html {
37+
scroll-behavior: smooth;
38+
}
539
}

script-hook-website/src/App.tsx

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React from 'react';
2-
import { HashRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
1+
import React, { useEffect } from 'react';
2+
import { HashRouter as Router, Routes, Route, Navigate, useLocation } from 'react-router-dom';
33
import Header from './components/Header';
44
import Hero from './components/Hero';
55
import Features from './components/Features';
@@ -8,12 +8,25 @@ import FeatureTree from './components/FeatureTree';
88
import DetailedFeatures from './components/DetailedFeatures';
99
import Installation from './components/Installation';
1010
import Support from './components/Support';
11-
import StarHistory from './components/StarHistory';
1211
import CommunityGroup from './components/CommunityGroup';
1312
import Footer from './components/Footer';
1413
import GitHubStarButton from './components/GitHubStarButton';
1514
import './App.css';
1615

16+
// 滚动恢复组件,防止路由切换时的滚动问题
17+
const ScrollToTop: React.FC = () => {
18+
const { pathname, hash } = useLocation();
19+
20+
useEffect(() => {
21+
// 只有当没有hash值或hash值为空时,才滚动到顶部
22+
if (!hash) {
23+
window.scrollTo(0, 0);
24+
}
25+
}, [pathname, hash]);
26+
27+
return null;
28+
};
29+
1730
// 封装主页面内容为一个组件
1831
const HomePage: React.FC = () => {
1932
return (
@@ -34,9 +47,43 @@ const HomePage: React.FC = () => {
3447
};
3548

3649
const App: React.FC = () => {
50+
// 禁用滚动恢复
51+
useEffect(() => {
52+
// 如果存在 history.scrollRestoration 属性,则禁用自动滚动恢复
53+
if ('scrollRestoration' in history) {
54+
history.scrollRestoration = 'manual';
55+
}
56+
57+
// 防止滚动跳跃
58+
let isScrolling = false;
59+
let scrollTimeout: number | null = null;
60+
61+
const handleScroll = () => {
62+
isScrolling = true;
63+
64+
if (scrollTimeout !== null) {
65+
window.clearTimeout(scrollTimeout);
66+
}
67+
68+
scrollTimeout = window.setTimeout(() => {
69+
isScrolling = false;
70+
}, 150);
71+
};
72+
73+
window.addEventListener('scroll', handleScroll, { passive: true });
74+
75+
return () => {
76+
window.removeEventListener('scroll', handleScroll);
77+
if (scrollTimeout !== null) {
78+
window.clearTimeout(scrollTimeout);
79+
}
80+
};
81+
}, []);
82+
3783
return (
3884
<Router>
3985
<div className="app">
86+
<ScrollToTop />
4087
<Routes>
4188
<Route path="/" element={<HomePage />} />
4289
{/* 添加其他路由,如果未来需要子页面 */}
Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,63 @@
11
const path = require('path');
22
const HtmlWebpackPlugin = require('html-webpack-plugin');
33

4-
module.exports = {
5-
entry: './src/index.tsx',
6-
output: {
7-
path: path.resolve(__dirname, 'dist'),
8-
filename: 'bundle.js',
9-
publicPath: './',
10-
},
11-
resolve: {
12-
extensions: ['.ts', '.tsx', '.js', '.jsx'],
13-
},
14-
module: {
15-
rules: [
16-
{
17-
test: /\.tsx?$/,
18-
use: 'ts-loader',
19-
exclude: /node_modules/,
20-
},
21-
{
22-
test: /\.css$/,
23-
use: ['style-loader', 'css-loader'],
4+
module.exports = (env, argv) => {
5+
const isProduction = argv.mode === 'production';
6+
7+
return {
8+
entry: './src/index.tsx',
9+
output: {
10+
path: path.resolve(__dirname, 'dist'),
11+
filename: 'bundle.js',
12+
publicPath: isProduction ? './' : '/',
13+
},
14+
resolve: {
15+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
16+
},
17+
module: {
18+
rules: [
19+
{
20+
test: /\.tsx?$/,
21+
use: 'ts-loader',
22+
exclude: /node_modules/,
23+
},
24+
{
25+
test: /\.css$/,
26+
use: ['style-loader', 'css-loader'],
27+
},
28+
{
29+
test: /\.(png|jpe?g|gif|svg)$/i,
30+
type: 'asset/resource',
31+
},
32+
],
33+
},
34+
plugins: [
35+
new HtmlWebpackPlugin({
36+
template: './public/index.html',
37+
meta: {
38+
'Cache-Control': {'http-equiv': 'Cache-Control', 'content': 'no-cache, no-store, must-revalidate'},
39+
'Pragma': {'http-equiv': 'Pragma', 'content': 'no-cache'},
40+
'Expires': {'http-equiv': 'Expires', 'content': '0'}
41+
}
42+
}),
43+
],
44+
devServer: {
45+
static: {
46+
directory: path.join(__dirname, 'public'),
2447
},
25-
{
26-
test: /\.(png|jpe?g|gif|svg)$/i,
27-
type: 'asset/resource',
48+
compress: true,
49+
port: 'auto',
50+
hot: true,
51+
historyApiFallback: true,
52+
devMiddleware: {
53+
publicPath: '/'
54+
}
55+
},
56+
optimization: {
57+
runtimeChunk: 'single',
58+
splitChunks: {
59+
chunks: 'all',
2860
},
29-
],
30-
},
31-
plugins: [
32-
new HtmlWebpackPlugin({
33-
template: './public/index.html',
34-
}),
35-
],
36-
devServer: {
37-
static: {
38-
directory: path.join(__dirname, 'public'),
3961
},
40-
compress: true,
41-
port: 3000,
42-
hot: true,
43-
historyApiFallback: true,
44-
devMiddleware: {
45-
publicPath: '/'
46-
}
47-
},
62+
};
4863
};

0 commit comments

Comments
 (0)