Files
microapp-main-interview/src/App.vue
2026-06-21 20:19:21 +08:00

214 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div id="main-app">
<header class="app-header">
<div class="logo" @click="$router.push('/')">
<h1>MicroApp 主应用</h1>
</div>
<nav class="nav-links">
<router-link to="/home">首页</router-link>
<router-link to="/child-app">Vue2 子应用</router-link>
<router-link to="/vue3-app">Vue3 子应用</router-link>
<router-link to="/mock-app">💥主vs子</router-link>
<router-link to="/mock-app-2">🔵子vs子</router-link>
</nav>
</header>
<main class="app-main">
<router-view />
</main>
</div>
</template>
<script setup lang="ts">
// 根组件 — 提供全局布局(头部导航 + 内容区)
</script>
<style>
/* ============================================
全局样式重置(主应用)
注意:以下使用了 h2 / button / p / table / code
等通用选择器。在微前端场景中,这些选择器会:
1. 影响主应用自身的元素 ✅ (预期行为)
2. 泄漏到 iframe: false 的子应用中 ⚠️ (样式冲突)
============================================ */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Microsoft YaHei', sans-serif;
color: #333;
background: #f5f6f7;
}
#app {
height: 100%;
}
/* ---------- 主应用内容区样式(限定在主应用自身页面内) ---------- */
/*
问题:子应用在 iframe: false 模式下DOM 直接嵌入主文档,
挂在 <router-view> → <ChildApp.vue> → <micro-app> 下面,
而 <router-view> 又在 .app-main 内部。
所以 .app-main h2 这种「后代选择器」会穿透到子应用的 h2。
之前(会泄漏): h2 { ... } ← 没有作用域100% 泄漏
中间(仍泄漏): .app-main h2 { ... } ← 子应用也在 .app-main 里!
现在(已修复): .app-main > :not(.child-app-wrapper) h2 { ... }
↑ 用子选择器 > 只匹配 .app-main 的直接子元素,
再用 :not(.child-app-wrapper) 排除子应用容器,
彻底阻断样式进入 micro-app 内部
DOM 层级示意:
.app-main
├── div.home-page ← :not(.child-app-wrapper) → ✅ 样式生效
└── div.child-app-wrapper ← 被 :not() 排除 → ❌ 样式不生效
└── <micro-app>
└── 子应用 h2/button/p... ← 安全,不受主应用样式影响
*/
/* 冲突点 ①h2 — 主应用想要紫色渐变标题 */
.app-main > :not(.child-app-wrapper) h2 {
font-family: 'Microsoft YaHei', sans-serif !important;
font-size: 20px !important;
color: #667eea !important;
border-bottom: 2px solid #667eea !important;
padding-bottom: 8px !important;
margin: 12px 0 !important;
text-transform: none !important;
border-left: none !important;
}
/* 冲突点 ②button — 主应用想要紫色直角按钮 */
.app-main > :not(.child-app-wrapper) button {
background: #667eea !important;
color: #fff !important;
border: none !important;
border-radius: 4px !important;
padding: 6px 16px !important;
font-size: 13px !important;
font-weight: 500 !important;
cursor: pointer !important;
letter-spacing: 0 !important;
}
.app-main > :not(.child-app-wrapper) button:hover {
background: #5a6fd6 !important;
transform: none !important;
}
/* 冲突点 ③p 段落 — 主应用想要紧凑排版 */
.app-main > :not(.child-app-wrapper) p {
font-size: 14px !important;
line-height: 1.6 !important;
color: #444 !important;
margin-bottom: 8px !important;
}
/* 冲突点 ④table — 主应用想要紫色无边框表格 */
.app-main > :not(.child-app-wrapper) table {
border-collapse: collapse !important;
width: 100% !important;
border: none !important;
}
.app-main > :not(.child-app-wrapper) th {
background: #667eea !important;
color: white !important;
padding: 8px !important;
text-align: left !important;
font-size: 13px !important;
}
.app-main > :not(.child-app-wrapper) td {
padding: 6px 8px !important;
border-bottom: 1px solid #e0e0e0 !important;
font-size: 13px !important;
}
/* 冲突点 ⑤code 标签 — 主应用想要紫色代码块 */
.app-main > :not(.child-app-wrapper) code {
background: #e8e0f0 !important;
color: #5e35b1 !important;
border: 1px solid #b39ddb !important;
padding: 2px 6px !important;
border-radius: 3px !important;
font-size: 13px !important;
}
/* 主应用布局 */
.main-style-source {
display: inline-block;
padding: 2px 10px;
border-radius: 4px;
font-size: 11px;
font-weight: bold;
margin-left: 8px;
}
.label-main {
background: #667eea;
color: white;
}
#main-app {
display: flex;
flex-direction: column;
height: 100%;
}
/* 头部导航 */
.app-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 56px;
padding: 0 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
flex-shrink: 0;
}
.logo {
cursor: pointer;
}
.logo h1 {
font-size: 18px;
font-weight: 600;
letter-spacing: 1px;
}
.nav-links {
display: flex;
gap: 8px;
}
.nav-links a {
color: rgba(255, 255, 255, 0.85);
text-decoration: none;
padding: 6px 16px;
border-radius: 6px;
font-size: 14px;
transition: all 0.2s ease;
}
.nav-links a:hover {
color: #fff;
background: rgba(255, 255, 255, 0.15);
}
.nav-links a.router-link-active {
color: #fff;
background: rgba(255, 255, 255, 0.2);
font-weight: 500;
}
/* 主内容区 */
.app-main {
flex: 1;
overflow: auto;
}
</style>