2026-01-15 20:10:19 +08:00
|
|
|
<template>
|
2026-01-16 19:10:21 +08:00
|
|
|
<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>
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
<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>
|
2026-01-16 19:10:21 +08:00
|
|
|
</transition>
|
2026-01-15 20:10:19 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref } from 'vue'
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
const currentStage = ref(0)
|
2026-01-15 20:10:19 +08:00
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
const stages = [
|
2026-01-15 20:10:19 +08:00
|
|
|
{
|
2026-01-16 19:10:21 +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
|
|
|
},
|
|
|
|
|
{
|
2026-01-16 19:10:21 +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
|
|
|
},
|
|
|
|
|
{
|
2026-01-16 19:10:21 +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
|
|
|
},
|
|
|
|
|
{
|
2026-01-16 19:10:21 +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
|
|
|
},
|
|
|
|
|
{
|
2026-01-16 19:10:21 +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>
|
2026-01-16 19:10:21 +08:00
|
|
|
.url-to-browser-demo {
|
2026-01-15 20:10:19 +08:00
|
|
|
border: 1px solid var(--vp-c-divider);
|
|
|
|
|
border-radius: 8px;
|
2026-01-16 19:10:21 +08:00
|
|
|
background-color: var(--vp-c-bg-soft);
|
|
|
|
|
padding: 1.5rem;
|
|
|
|
|
margin: 2rem 0;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.stage-nav {
|
2026-01-15 20:10:19 +08:00
|
|
|
display: flex;
|
2026-01-16 19:10:21 +08:00
|
|
|
justify-content: space-between;
|
|
|
|
|
margin-bottom: 2rem;
|
2026-01-15 20:10:19 +08:00
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.stage-nav::before {
|
|
|
|
|
content: '';
|
2026-01-15 20:10:19 +08:00
|
|
|
position: absolute;
|
2026-01-16 19:10:21 +08:00
|
|
|
top: 50%;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
height: 2px;
|
2026-01-15 20:10:19 +08:00
|
|
|
background: var(--vp-c-divider);
|
2026-01-16 19:10:21 +08:00
|
|
|
z-index: 0;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +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);
|
2026-01-16 19:10:21 +08:00
|
|
|
border-radius: 20px;
|
|
|
|
|
padding: 0.5rem 1rem;
|
2026-01-15 20:10:19 +08:00
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
2026-01-16 19:10:21 +08:00
|
|
|
gap: 0.5rem;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +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;
|
2026-01-16 19:10:21 +08:00
|
|
|
transform: scale(1.1);
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.stage-num {
|
2026-01-15 20:10:19 +08:00
|
|
|
font-weight: bold;
|
2026-01-16 19:10:21 +08:00
|
|
|
font-family: monospace;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.stage-content {
|
2026-01-15 20:10:19 +08:00
|
|
|
background: var(--vp-c-bg);
|
|
|
|
|
border-radius: 8px;
|
2026-01-16 19:10:21 +08:00
|
|
|
padding: 2rem;
|
|
|
|
|
text-align: center;
|
|
|
|
|
min-height: 200px;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.viz-icon {
|
|
|
|
|
font-size: 3rem;
|
|
|
|
|
margin-bottom: 1rem;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.viz-desc h3 {
|
|
|
|
|
margin-bottom: 0.5rem;
|
|
|
|
|
color: var(--vp-c-text-1);
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.viz-desc p {
|
2026-01-15 20:10:19 +08:00
|
|
|
color: var(--vp-c-text-2);
|
2026-01-16 19:10:21 +08:00
|
|
|
max-width: 500px;
|
|
|
|
|
margin: 0 auto;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.fade-enter-active,
|
|
|
|
|
.fade-leave-active {
|
|
|
|
|
transition: opacity 0.3s ease;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 19:10:21 +08:00
|
|
|
.fade-enter-from,
|
|
|
|
|
.fade-leave-to {
|
|
|
|
|
opacity: 0;
|
2026-01-15 20:10:19 +08:00
|
|
|
}
|
|
|
|
|
</style>
|