Files
test-repo/docs/.vitepress/theme/components/appendix/web-basics/UrlToBrowserDemo.vue
T

166 lines
3.4 KiB
Vue
Raw Normal View History

2026-01-15 20:10:19 +08:00
<template>
<div class="url-to-browser-demo">
<div class="stage-nav">
<button
v-for="(stage, index) in stages"
:key="index"
:class="{ active: currentStage === index }"
@click="currentStage = index"
>
<span class="stage-num">{{ index + 1 }}</span>
<span class="stage-name">{{ stage.name }}</span>
</button>
2026-01-15 20:10:19 +08:00
</div>
<div class="stage-content">
<transition name="fade" mode="out-in">
<div :key="currentStage" class="stage-viz">
<div class="viz-icon">{{ stages[currentStage].icon }}</div>
<div class="viz-desc">
<h3>{{ stages[currentStage].title }}</h3>
<p>{{ stages[currentStage].desc }}</p>
</div>
<div class="viz-action">
<component
:is="stages[currentStage].component"
v-if="stages[currentStage].component"
/>
2026-01-15 20:10:19 +08:00
</div>
</div>
</transition>
2026-01-15 20:10:19 +08:00
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const currentStage = ref(0)
2026-01-15 20:10:19 +08:00
const stages = [
2026-01-15 20:10:19 +08:00
{
name: 'URL',
title: 'Parsing the Address',
desc: 'Browser breaks down the URL to understand protocol, domain, and path.',
icon: '🔍',
component: 'UrlParserDemo'
2026-01-15 20:10:19 +08:00
},
{
name: 'DNS',
title: 'Finding the IP',
desc: 'Browser asks DNS servers to translate the domain name into an IP address.',
icon: '🌐',
component: 'DnsLookupDemo'
2026-01-15 20:10:19 +08:00
},
{
name: 'TCP',
title: 'Establishing Connection',
desc: 'Browser and Server perform a 3-way handshake to create a reliable connection.',
icon: '🤝',
component: 'TcpHandshakeDemo'
2026-01-15 20:10:19 +08:00
},
{
name: 'HTTP',
title: 'Exchanging Data',
desc: 'Browser sends a request, and the server sends back the website content.',
icon: '📨',
component: 'HttpExchangeDemo'
2026-01-15 20:10:19 +08:00
},
{
name: 'Render',
title: 'Painting the Page',
desc: 'Browser parses HTML/CSS and paints pixels on your screen.',
icon: '🎨',
component: 'BrowserRenderingDemo'
2026-01-15 20:10:19 +08:00
}
]
</script>
<style scoped>
.url-to-browser-demo {
2026-01-15 20:10:19 +08:00
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background-color: var(--vp-c-bg-soft);
padding: 1.5rem;
margin: 2rem 0;
2026-01-15 20:10:19 +08:00
}
.stage-nav {
2026-01-15 20:10:19 +08:00
display: flex;
justify-content: space-between;
margin-bottom: 2rem;
2026-01-15 20:10:19 +08:00
position: relative;
}
.stage-nav::before {
content: '';
2026-01-15 20:10:19 +08:00
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 2px;
2026-01-15 20:10:19 +08:00
background: var(--vp-c-divider);
z-index: 0;
2026-01-15 20:10:19 +08:00
}
.stage-nav button {
position: relative;
z-index: 1;
background: var(--vp-c-bg);
2026-01-15 20:10:19 +08:00
border: 2px solid var(--vp-c-divider);
border-radius: 20px;
padding: 0.5rem 1rem;
2026-01-15 20:10:19 +08:00
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
transition: all 0.2s;
2026-01-15 20:10:19 +08:00
}
.stage-nav button.active {
2026-01-15 20:10:19 +08:00
border-color: var(--vp-c-brand);
background: var(--vp-c-brand);
color: white;
transform: scale(1.1);
2026-01-15 20:10:19 +08:00
}
.stage-num {
2026-01-15 20:10:19 +08:00
font-weight: bold;
font-family: monospace;
2026-01-15 20:10:19 +08:00
}
.stage-content {
2026-01-15 20:10:19 +08:00
background: var(--vp-c-bg);
border-radius: 8px;
padding: 2rem;
text-align: center;
min-height: 200px;
2026-01-15 20:10:19 +08:00
}
.viz-icon {
font-size: 3rem;
margin-bottom: 1rem;
2026-01-15 20:10:19 +08:00
}
.viz-desc h3 {
margin-bottom: 0.5rem;
color: var(--vp-c-text-1);
2026-01-15 20:10:19 +08:00
}
.viz-desc p {
2026-01-15 20:10:19 +08:00
color: var(--vp-c-text-2);
max-width: 500px;
margin: 0 auto;
2026-01-15 20:10:19 +08:00
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
2026-01-15 20:10:19 +08:00
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
2026-01-15 20:10:19 +08:00
}
</style>