refactor(layout): 优化 hero 区域滚动效果和样式

移除 hero 区域的顶部 margin 控制,改为使用 transform 实现平滑滚动
简化滚动逻辑,调整 hero 区域在不同页面的显示效果
更新 CSS 变量定义,移除无用样式
This commit is contained in:
qingfeng1121
2025-12-18 15:19:46 +08:00
parent 183d98a699
commit 0dc24cfa85
2 changed files with 32 additions and 62 deletions

View File

@@ -49,7 +49,7 @@
<!-- Hero 区域 --> <!-- Hero 区域 -->
<div class="hero" :class="{ 'small-hero': classsmallhero }" v-if="windowwidth" <div class="hero" :class="{ 'small-hero': classsmallhero }" v-if="windowwidth"
:style="{ marginTop: heroMarginTop, marginBottom: heroMarginBottom, transform: heroTransform, transition: 'all 0.3s ease' }"> :style="{ marginBottom: heroMarginBottom, transform: heroTransform }">
<h1 class="typewriter">{{ heroText }}</h1> <h1 class="typewriter">{{ heroText }}</h1>
</div> </div>
@@ -104,14 +104,14 @@ const classnonsenset = ref(false);
const classsmallhero = ref(false); const classsmallhero = ref(false);
const elrowtop = ref('transparent'); const elrowtop = ref('transparent');
// hero区域的margin值用于实现滚动时动态变化 // hero区域的margin值用于实现滚动时动态变化
const heroMarginTop = ref('45%');
const heroMarginBottom = ref('45%'); const heroMarginBottom = ref('45%');
// hero区域的初始margin值从CSS变量获取 // hero区域的初始margin值从CSS变量获取
const initialHeroMargin = 45; const initialHeroMarginBottom = 45;
// hero是否开始向上移动 // hero是否开始向上移动
const heroIsMoving = ref(false); const heroIsMoving = ref(false);
// hero的transform值用于实现向上移动和吸附效果 // hero的transform值用于实现向上移动和吸附效果
const heroTransform = ref('translateY(0)'); const heroTransform = ref('translateY(450px)');
const heroTransformValue = 450;
// hero的位置状态static(静态)、moving(移动中)、sticky(吸附顶部) // hero的位置状态static(静态)、moving(移动中)、sticky(吸附顶部)
const heroPosition = ref('static'); const heroPosition = ref('static');
@@ -231,7 +231,6 @@ const updateArticleTitle = () => {
if (rpsliturl[2] === 'aericletype') { if (rpsliturl[2] === 'aericletype') {
// 按属性类型获取 // 按属性类型获取
articledata = globalStore.getValue('attribute')?.name; articledata = globalStore.getValue('attribute')?.name;
console.log('attributeId参数:', articledata);
} }
else if (rpsliturl[2] === 'aericletitle') { else if (rpsliturl[2] === 'aericletitle') {
// 按标题搜索获取 // 按标题搜索获取
@@ -354,48 +353,26 @@ const handleScroll = () => {
if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) { if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) {
const scrollY = window.scrollY; const scrollY = window.scrollY;
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
// 计算滚动距离与窗口高度的比例,用于内容渐显 // 计算滚动距离与窗口高度的比例,用于内容渐显
const contentScrollRatio = Math.min(scrollY / windowHeight, 1); const contentScrollRatio = Math.min(scrollY / windowHeight, 1);
// 计算新的底部margin值从初始值45%逐渐减少到25% // 计算新的底部margin值从初始值45%逐渐减少到25%
const newMarginBottom = Math.max(initialHeroMargin - (initialHeroMargin * contentScrollRatio), 0); const newMarginBottom = Math.max(initialHeroMarginBottom - (initialHeroMarginBottom * contentScrollRatio), 0);
// 更新hero的底部margin值 // 更新hero的底部margin值
heroMarginBottom.value = `${newMarginBottom}%`; heroMarginBottom.value = `${newMarginBottom}%`;
// 顶部margin保持不变 // 计算新的translateY值从初始值450px逐渐减少到150px
heroMarginTop.value = `${initialHeroMargin}%`; const translateYValue = Math.max(heroTransformValue - (heroTransformValue * contentScrollRatio * 5), 90);
heroTransform.value = `translateY(${translateYValue}px)`;
// 内容区域随滚动逐渐显现 // 当滚动超过100px时开始显示滚动到一屏高度时完全显示
// 当滚动超过50px时开始显示滚动到一屏高度时完全显示 iscontentvisible.value = scrollY > 100;
iscontentvisible.value = scrollY > 50; // 当滚动超过287px时logo被顶出屏幕
if (scrollY > 287) {
// 计算hero的移动阶段
if (scrollY >= 555) {
// 滚动超过555px标题开始向上移动
heroIsMoving.value = true;
heroPosition.value = 'moving'; heroPosition.value = 'moving';
const translateYValue = Math.min(heroTransformValue - (heroTransformValue * contentScrollRatio * 5), 0);
// 计算移动距离从0到初始marginTop值(45%) heroTransform.value = `translateY(${translateYValue / 2}px)`;
// 使用滚动距离减去起始位置(555px),除以移动范围(500px),得到移动比例
const moveScrollRatio = Math.min((scrollY - 555) / 500, 1);
const moveDistance = initialHeroMargin * moveScrollRatio;
heroTransform.value = `translateY(-${moveDistance*10}%)`;
// 当移动距离达到初始marginTop值时吸附到顶部
if (moveScrollRatio >= 1) {
heroPosition.value = 'sticky';
heroTransform.value = `translateY(-${initialHeroMargin*10}%)`;
}
} else {
// 滚动未超过555px标题保持静态
heroIsMoving.value = false;
heroPosition.value = 'static';
heroTransform.value = 'translateY(0)';
} }
// 控制左侧模块的滚动状态 // 控制左侧模块的滚动状态
isScrollingleftmodlue.value = scrollY > 600; isScrollingleftmodlue.value = scrollY > 600;
} }
}; };
/** /**
@@ -420,37 +397,32 @@ const updateNavbarStyle = (scrollY: number) => {
const handleRouteChange = () => { const handleRouteChange = () => {
// 重新解析路由路径 // 重新解析路由路径
rpsliturl = route.path.split('/'); rpsliturl = route.path.split('/');
console.log(rpsliturl);
// 更新页面相关状态 // 更新页面相关状态
updatePageState(); updatePageState();
setActiveIndex(rpsliturl[1]); setActiveIndex(rpsliturl[1]);
updateArticleTitle(); updateArticleTitle();
// 页面跳转后回到顶部 // 页面跳转后回到顶部
window.scrollTo({ top: 0, behavior: 'smooth' }); window.scrollTo({ top: 0, behavior: 'smooth' });
// 根据是否为首页决定是否启动打字机效果 // 根据是否为首页决定是否启动打字机效果
if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) { if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) {
// 首页启动打字机效果 // 首页启动打字机效果
startTypewriter(fullHeroText); startTypewriter(fullHeroText);
// 重置hero的margin值为初始值 // 重置hero的margin值为初始值
heroMarginBottom.value = `${initialHeroMargin}%`; heroMarginBottom.value = `${initialHeroMarginBottom}%`;
heroMarginTop.value = `${initialHeroMargin}%`;
// 重置hero的移动状态 // 重置hero的移动状态
heroTransform.value = `translateY(${heroTransformValue}px)`;
heroIsMoving.value = false; heroIsMoving.value = false;
heroPosition.value = 'static'; heroPosition.value = 'static';
heroTransform.value = 'translateY(0)';
// 移动端首页默认显示内容区,桌面端初始隐藏 // 移动端首页默认显示内容区,桌面端初始隐藏
iscontentvisible.value = window.innerWidth <= 768; iscontentvisible.value = window.innerWidth <= 768;
} else { } else {
// 非首页直接显示完整文本
iscontentvisible.value = true; iscontentvisible.value = true;
stopTypewriter(); startTypewriter(fullHeroText);
} heroMarginBottom.value = `${5}%`;
// 不在首页时hero的margin为0 heroTransform.value = ``;
if (rpsliturl[1] !== localhome) {
heroMarginBottom.value = '0%';
heroMarginTop.value = '0%';
} }
}; };
@@ -465,18 +437,17 @@ const initializePage = () => {
// 首页启动打字机效果 // 首页启动打字机效果
startTypewriter(fullHeroText); startTypewriter(fullHeroText);
// 重置hero的margin值为初始值 // 重置hero的margin值为初始值
heroMarginBottom.value = `${initialHeroMargin}%`; heroMarginBottom.value = `${initialHeroMarginBottom}%`;
heroMarginTop.value = `${initialHeroMargin}%`;
// 重置hero的移动状态 // 重置hero的移动状态
heroIsMoving.value = false; heroIsMoving.value = false;
heroPosition.value = 'static'; heroPosition.value = 'static';
heroTransform.value = 'translateY(0)';
// 移动端首页默认显示内容区,桌面端初始隐藏 // 移动端首页默认显示内容区,桌面端初始隐藏
iscontentvisible.value = window.innerWidth <= 768; iscontentvisible.value = window.innerWidth <= 768;
} else { } else {
// 非首页清空hero内容 startTypewriter(fullHeroText);
heroText.value = ''; heroMarginBottom.value = `${2.5}%`;
} }
}; };
// ========== 生命周期钩子 ========== // ========== 生命周期钩子 ==========
@@ -518,8 +489,7 @@ onUnmounted(() => {
*/ */
watch( watch(
() => route.path, () => route.path,
handleRouteChange, handleRouteChange
{ immediate: true } // 立即执行一次,确保初始状态正确
); );
</script> </script>

View File

@@ -21,11 +21,8 @@
/* hero 默认高度 */ /* hero 默认高度 */
--hero-height-small: 100px; --hero-height-small: 100px;
/* hero 收缩后高度 */ /* hero 收缩后高度 */
--hero-margin: 45% 0; --hero-margin-top-small: 6%;
/* hero 边距 */ /* hero 收缩后顶部外边距 */
--hero-min-margin-top: 45%;
/* hero 最小顶边距 */
/* 标题样式 */ /* 标题样式 */
--title-font-size: 3.5rem; --title-font-size: 3.5rem;
/* hero 主标题字号 */ /* hero 主标题字号 */
@@ -385,6 +382,9 @@ p {
/* hero 收缩状态 */ /* hero 收缩状态 */
.hero.small-hero { .hero.small-hero {
height: var(--hero-height-small); height: var(--hero-height-small);
margin-top: var(--hero-margin-top-small);
/* 去除 hero 收缩状态下的position */
position: static;
} }
/* 打字机效果 */ /* 打字机效果 */