Files
microapp-vue3-interview/docs/interview-question-map-layout.md

6.6 KiB
Raw Permalink Blame History

前端面试题全屏三区布局header + 地图 + 操作栏)且无滚动条

题目描述

你需要实现一个微前端子应用的地图页面,布局要求如下:

┌────────────────────────────────┐
│         sub-app-header         │  ← 高 48px始终可见
│  🟢 Vue3 子应用  [首页][关于][地图] │
├────────────────────────────────┤
│                                │
│                                │
│          🗺️ 高德地图            │  ← 占满剩余空间
│                                │
│                                │
├────────────────────────────────┤
│  🗺️ 高德地图    [📍回到默认] [🎯我的位置] │ ← 高 52px始终可见
└────────────────────────────────┘

核心要求:

  1. 页面不能出现滚动条,三个区域必须同时完整显示在视口内
  2. 地图区域需正确渲染(高德地图 JSAPI 要求容器有明确的像素尺寸)
  3. 该应用既要能在微前端环境中嵌入运行,也要能独立运行

初始代码(有问题)

<!-- App.vue -->
<template>
  <div id="microapp-vue3-container">
    <header class="sub-app-header">
      <h1>🟢 Vue3 子应用</h1>
      <nav>
        <router-link to="/">首页</router-link>
        <router-link to="/about">关于</router-link>
        <router-link to="/map">地图</router-link>
      </nav>
    </header>
    <main class="sub-app-main">
      <router-view />
    </main>
  </div>
</template>

<style>
body {
  margin: 0;
}

#microapp-vue3-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
  background: #fafafa;
}

.sub-app-header {
  height: 48px;
  flex-shrink: 0;
  /* ...其他样式省略 */
}

.sub-app-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
}
</style>
<!-- MapView.vue  地图页面 -->
<template>
  <div class="map-page">
    <div v-if="loading" class="map-status"> 地图加载中...</div>
    <div v-else-if="error" class="map-status map-error"> {{ error }}</div>

    <div ref="containerRef" class="map-container" />

    <div class="map-controls">
      <span>🗺️ 高德地图</span>
      <div>
        <button @click="resetView">📍 回到默认位置</button>
        <button @click="getCurrentPosition">🎯 我的位置</button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.map-page {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.map-container {
  flex: 1;
  min-height: 0;
}

.map-controls {
  flex-shrink: 0;
  /* ... */
}
</style>

问题: 页面出现了垂直滚动条,地图也没有正确渲染。


考察知识点

层级 知识点 具体体现
CSS 盒模型 height: 100% 的继承链 百分比高度必须逐级传递,任意一环缺失都会断裂
Flexbox flex: 1min-height: 0 flex 子项默认 min-height: auto,可能导致溢出
溢出控制 overflow 的层级管理 在哪一层阻止溢出、哪一层允许滚动需要精心设计
第三方库适配 地图 SDK 的容器约束 AMap 要求容器有明确像素高度flex 分配的隐式高度可能不生效
微前端 子应用的挂载点与视口 100vh vs 100% 在不同环境下的差异

期望答案要点

1. 修复百分比高度继承链(关键)

初始html → body → #root无高度→ #container100vh  ❌ 链断裂
修复html → body → #root → #container全部 100%        ✅ 完整链路
html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;          /* 根级截断,杜绝页面级滚动条 */
}

#microapp-vue3-root {
  height: 100%;              /* 关键:挂载点也需撑满 */
}

#microapp-vue3-container {
  height: 100%;              /* 用 % 而非 vh适配微前端环境 */
  overflow: hidden;
}

为什么 100vh 不够好?

  • 移动端浏览器地址栏收起/展开会改变 100vh 的实际值
  • 微前端环境中,子应用容器不一定等于视口高度,100% 跟随父容器更稳健

2. flex 布局的溢出收缩

.sub-app-main {
  flex: 1;
  min-height: 0;            /* 允许收缩到内容以下 */
  display: flex;
  flex-direction: column;
}

.map-page {
  flex: 1;
  min-height: 0;            /* 同上 */
  overflow: hidden;         /* 阻止地图页面自身溢出 */
}

关键原理: flex item 默认 min-height: auto,不允许收缩到内容高度以下;设为 0 后才真正服从 flex 分配。

3. AMap 容器必须有明确的尺寸

.map-container {
  flex: 1;
  width: 100%;
  min-height: 0;
}

/* 避免display: none 导致容器尺寸为 0 */
.map-hidden {
  visibility: hidden;       /* ✅ 保留占位,地图可正常初始化 */
  /* display: none; */      /* ❌ 尺寸归零,地图无法渲染 */
}

配合 JS 端延迟 resize

onMounted(async () => {
  const map = await initMap()
  if (map) {
    nextTick(() => map.resize())   // 修正 flex 布局下的初始尺寸
  }
})

4. 不同页面的滚动策略分离

地图页不需要滚动,但首页/关于页可能需要:

.sub-app-main {
  overflow-y: auto;   /* 允许滚动 */
}

.map-page {
  overflow: hidden;   /* 地图页自己阻止溢出 */
  /* flex: 1 意味着它恰好填满父容器,不会触发父级的 overflow-y */
}

加分项

  • 能说出 display: none vs visibility: hidden 对第三方库 DOM 测量的影响
  • 能解释为什么在 onMounted 中调用 map.resize(),而不是 onBeforeMount
  • 能分析 resizeEnable: true 的 AMap 配置与手动 resize() 的配合关系
  • 能指出微前端场景下 body { margin: 0 } 不生效的边界情况(宿主页面的 body 不由子应用控制)

追问方向

  1. 如果不用 flex还有什么方案 → grid、absolute + calc、vh 运算
  2. 如何保证在其他页面(首页/关于页)的滚动正常? → 仅在父级 .sub-app-mainoverflow-y: auto,子页面不设 overflow: hidden
  3. min-height: 0 为什么是必须的? → flex item 的隐含 min-height: auto 阻止收缩
  4. 如果地图加载失败,当前布局会崩吗? → 状态提示用绝对定位浮层,不占 flex 空间,不影响布局