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

View File

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