56 lines
2.5 KiB
Markdown
56 lines
2.5 KiB
Markdown
# 滚动条覆盖底部导航栏 - 原因分析与解决方案
|
||
|
||
> **已解决**:将滚动从 viewport 移至 `app-main-scroll` 内部,滚动条不再覆盖底部导航。
|
||
|
||
## 现象
|
||
|
||
底部导航栏(v-bottom-navigation)被页面滚动条遮挡,即使设置 `z-index: 1100` 和 `transform: translateZ(0)` 仍无法解决。
|
||
|
||
## 根本原因
|
||
|
||
### 1. 滚动发生在 viewport(body/html)
|
||
|
||
当前布局中,页面滚动发生在 **文档根** 上:
|
||
|
||
- `Home.vue` 使用 `window.scrollY`、`document.documentElement.scrollHeight` 监听滚动
|
||
- `router/index.ts` 的 `scrollBehavior` 返回 `{ top: 0 }`,作用于 `window`
|
||
- `.home-list-scroll` 未设置 `overflow`,内容随 **窗口** 滚动
|
||
|
||
因此,**滚动条属于 viewport**,由浏览器在 html/body 上绘制。
|
||
|
||
### 2. 原生 viewport 滚动条不受 z-index 控制
|
||
|
||
- 滚动条是浏览器原生 UI,不是普通 DOM 元素
|
||
- 它由浏览器在单独图层渲染,与文档层叠上下文分离
|
||
- 不同浏览器行为不同:
|
||
- **Chrome**:fixed 元素有时能盖住滚动条
|
||
- **Firefox / Edge**:滚动条通常绘制在 fixed 元素之上
|
||
- 对这类原生滚动条,**z-index 无法可靠控制其与 fixed 元素的层级**
|
||
|
||
### 3. 当前 DOM 结构
|
||
|
||
```
|
||
v-app
|
||
├── v-app-bar (fixed top)
|
||
├── v-main (flex: 1,内容区)
|
||
│ └── main-content → router-view → Home/Search/Profile
|
||
└── v-bottom-navigation (fixed bottom)
|
||
```
|
||
|
||
- 底部导航是 `v-app` 的子节点,`position: fixed`
|
||
- 滚动发生在 body,滚动条在 viewport 右侧贯穿全屏
|
||
- 底部导航与滚动条在视觉上重叠,且无法通过 z-index 调整
|
||
|
||
## 解决方案(已实现)
|
||
|
||
**核心思路**:把滚动从 viewport 移到 **内部滚动容器** `app-main-scroll`,让滚动条只出现在内容区,不延伸到底部导航区域。
|
||
|
||
### 实现要点
|
||
|
||
1. **App.vue**:`html, body` 与 `.v-application` 设置 `overflow: hidden`;v-main 内新增 `app-main-scroll`(`data-main-scroll`)作为滚动容器,`overflow-y: auto`
|
||
2. **router**:`scrollBehavior` 改为滚动 `[data-main-scroll]` 元素
|
||
3. **Home.vue**:`checkScrollLoad` 使用 scroll 容器的 `scrollTop`/`scrollHeight`/`clientHeight`;`IntersectionObserver` 的 root 改为 scroll 容器;监听 scroll 容器的 `scroll` 事件
|
||
4. **Search.vue**:`IntersectionObserver` 的 root 改为 scroll 容器
|
||
|
||
效果:滚动条仅出现在 `app-main-scroll` 内,底部导航栏固定于 viewport 底部,不再被滚动条覆盖。
|