feat(appendix): 添加多个交互式演示组件,完善 AI/Infra 等章节内容
- 新增 Vibe Coding 全栈相关演示组件 (DeveloperSkillShift, FrontendTriad, BackendCore 等) - 新增 RAG 相关组件 (RAGPipeline, ChunkingStrategy, Retrieval 等) - 新增 Embedding & Vector 相关组件 (EmbeddingConcept, VectorSimilarity 等) - 新增 AI Native App 设计组件 (AINativeArch, PromptDesign 等) - 新增 Infrastructure as Code 组件 (IaCConcept, TerraformWorkflow 等) - 新增 DNS & HTTPS 演示组件 (DnsResolution, HttpsHandshake 等) - 新增 Model Finetuning 组件 (FinetuningPipeline 等) - 更新多个章节的 markdown 内容,集成交互式演示
This commit is contained in:
+373
@@ -0,0 +1,373 @@
|
||||
<template>
|
||||
<div class="ai-vs-traditional-demo">
|
||||
<div class="demo-header">
|
||||
<span class="icon">🤖</span>
|
||||
<span class="title">AI 工程师 vs 传统工程师</span>
|
||||
<span class="subtitle">工作方式的差异</span>
|
||||
</div>
|
||||
|
||||
<div class="comparison-container">
|
||||
<div class="comparison-column traditional">
|
||||
<div class="column-header">
|
||||
<span class="col-icon">👨💻</span>
|
||||
<span class="col-title">传统工程师</span>
|
||||
</div>
|
||||
<div class="work-flow">
|
||||
<div v-for="(step, index) in traditionalSteps" :key="index" class="flow-step">
|
||||
<span class="step-num">{{ index + 1 }}</span>
|
||||
<span class="step-text">{{ step }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column-stats">
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">编码时间占比</span>
|
||||
<span class="stat-value">60-70%</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">思考时间占比</span>
|
||||
<span class="stat-value">30-40%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vs-divider">
|
||||
<span class="vs-text">VS</span>
|
||||
</div>
|
||||
|
||||
<div class="comparison-column ai">
|
||||
<div class="column-header">
|
||||
<span class="col-icon">🤖</span>
|
||||
<span class="col-title">AI 工程师</span>
|
||||
</div>
|
||||
<div class="work-flow">
|
||||
<div v-for="(step, index) in aiSteps" :key="index" class="flow-step">
|
||||
<span class="step-num">{{ index + 1 }}</span>
|
||||
<span class="step-text">{{ step }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column-stats">
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">编码时间占比</span>
|
||||
<span class="stat-value">20-30%</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">思考时间占比</span>
|
||||
<span class="stat-value">70-80%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-shift">
|
||||
<div class="shift-title">📊 能力重心转移</div>
|
||||
<div class="shift-grid">
|
||||
<div v-for="item in skillShift" :key="item.from" class="shift-item">
|
||||
<div class="shift-from">
|
||||
<span class="arrow">↓</span>
|
||||
<span class="text">{{ item.from }}</span>
|
||||
<span class="trend down">重要性下降</span>
|
||||
</div>
|
||||
<div class="shift-to">
|
||||
<span class="arrow">↑</span>
|
||||
<span class="text">{{ item.to }}</span>
|
||||
<span class="trend up">重要性上升</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ai-insight">
|
||||
<div class="insight-icon">💡</div>
|
||||
<div class="insight-text">
|
||||
<strong>AI 时代的核心竞争力:</strong>不是"会写代码",而是"会描述需求、会判断对错、会设计方案"。AI 是你的编程助手,但<strong>决策者永远是你</strong>。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const traditionalSteps = ref([
|
||||
'理解需求',
|
||||
'查阅文档学习语法',
|
||||
'手写代码实现',
|
||||
'调试修复 Bug',
|
||||
'优化代码性能',
|
||||
'编写测试用例'
|
||||
])
|
||||
|
||||
const aiSteps = ref([
|
||||
'理解需求',
|
||||
'用自然语言描述给 AI',
|
||||
'审核 AI 生成的代码',
|
||||
'判断是否符合预期',
|
||||
'调整需求重新生成',
|
||||
'整合到项目中'
|
||||
])
|
||||
|
||||
const skillShift = ref([
|
||||
{ from: '语法记忆', to: '需求描述能力' },
|
||||
{ from: '手写代码速度', to: '代码审核能力' },
|
||||
{ from: '查文档能力', to: '架构设计能力' },
|
||||
{ from: '调试技巧', to: '问题定位能力' }
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ai-vs-traditional-demo {
|
||||
background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid #fed7aa;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.comparison-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.comparison-column {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.column-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.col-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.work-flow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.flow-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: #f8fafc;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.step-num {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #e2e8f0;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.traditional .step-num {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.ai .step-num {
|
||||
background: #dcfce7;
|
||||
color: #15803d;
|
||||
}
|
||||
|
||||
.step-text {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.column-stats {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.vs-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vs-text {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #f97316;
|
||||
background: white;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.skill-shift {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.shift-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.shift-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.shift-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.shift-from,
|
||||
.shift-to {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.shift-from .arrow {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.shift-to .arrow {
|
||||
color: #22c55e;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.trend {
|
||||
font-size: 10px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.trend.down {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.trend.up {
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.ai-insight {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
border-left: 4px solid #f97316;
|
||||
}
|
||||
|
||||
.insight-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.insight-text {
|
||||
font-size: 14px;
|
||||
color: #475569;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.insight-text strong {
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.comparison-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.vs-divider {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.shift-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div class="bios-post-demo">
|
||||
<div class="demo-label">BIOS POST 硬件自检 ── 点击查看检测项目</div>
|
||||
|
||||
<div class="post-items">
|
||||
<div
|
||||
v-for="item in postItems"
|
||||
:key="item.name"
|
||||
class="post-item"
|
||||
:class="{ passed: item.passed, error: item.error }"
|
||||
@click="item.passed = !item.passed"
|
||||
>
|
||||
<div class="item-status">{{ item.passed ? '✅' : item.error ? '❌' : '⏳' }}</div>
|
||||
<div class="item-info">
|
||||
<div class="item-name">{{ item.name }}</div>
|
||||
<div class="item-desc">{{ item.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="post-result">
|
||||
<span v-if="allPassed" class="result-pass">✅ 自检通过,准备启动</span>
|
||||
<span v-else class="result-pending">⏳ 点击项目模拟检测状态</span>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击模拟检测结果</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const postItems = ref([
|
||||
{ name: 'CPU', desc: '处理器完整性检测', passed: false, error: false },
|
||||
{ name: '内存', desc: 'RAM 容量和可用性检测', passed: false, error: false },
|
||||
{ name: '显卡', desc: '显示适配器初始化', passed: false, error: false },
|
||||
{ name: '硬盘', desc: '存储设备识别', passed: false, error: false },
|
||||
{ name: '键盘', desc: '键盘接口检测', passed: false, error: false },
|
||||
{ name: '鼠标', desc: '鼠标接口检测', passed: false, error: false }
|
||||
])
|
||||
|
||||
const allPassed = computed(() => postItems.value.every(item => item.passed))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bios-post-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.post-items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.post-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.post-item.passed {
|
||||
border-color: #22c55e;
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
}
|
||||
|
||||
.post-item.error {
|
||||
border-color: #ef4444;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 0.62rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.1rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.post-result {
|
||||
margin-top: 0.75rem;
|
||||
text-align: center;
|
||||
padding: 0.4rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.result-pass {
|
||||
color: #22c55e;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.result-pending {
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div class="backend-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">后端核心概念</span>
|
||||
<span class="subtitle">服务器端的核心职责</span>
|
||||
</div>
|
||||
|
||||
<div class="core-grid">
|
||||
<div v-for="core in coreConcepts" :key="core.name" class="core-card">
|
||||
<div class="core-name">{{ core.name }}</div>
|
||||
<div class="core-desc">{{ core.desc }}</div>
|
||||
<div class="core-examples">
|
||||
<span v-for="ex in core.examples" :key="ex" class="example-tag">{{ ex }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-section">
|
||||
<div class="flow-title">请求处理流程</div>
|
||||
<div class="flow-steps">
|
||||
<span v-for="(step, i) in flowSteps" :key="step">
|
||||
<span class="flow-step">{{ step }}</span>
|
||||
<span v-if="i < flowSteps.length - 1" class="flow-arrow">→</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>后端的核心价值:</strong>不是写代码,而是设计系统。如何让系统稳定、安全、高效、可扩展,才是后端工程师的真正能力。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const coreConcepts = ref([
|
||||
{ name: 'API 设计', desc: '定义客户端如何与服务端交互', examples: ['RESTful', 'GraphQL'] },
|
||||
{ name: '业务逻辑', desc: '处理核心业务规则和流程', examples: ['订单处理', '支付流程'] },
|
||||
{ name: '数据存储', desc: '数据的持久化和查询', examples: ['MySQL', 'Redis'] },
|
||||
{ name: '认证授权', desc: '用户身份验证和权限控制', examples: ['JWT', 'OAuth'] },
|
||||
{ name: '性能优化', desc: '缓存、异步、并发处理', examples: ['缓存', '消息队列'] },
|
||||
{ name: '安全防护', desc: '防止攻击和数据泄露', examples: ['SQL注入防护', 'HTTPS'] }
|
||||
])
|
||||
|
||||
const flowSteps = ref(['接收请求', '路由解析', '业务处理', '数据操作', '返回响应'])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.backend-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.core-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.core-card {
|
||||
padding: 0.6rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.core-name {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.core-desc {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.core-examples {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.example-tag {
|
||||
font-size: 0.65rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.flow-section {
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.flow-title {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.flow-steps {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.flow-step {
|
||||
font-size: 0.72rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.flow-arrow {
|
||||
color: var(--vp-c-text-3);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.core-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div class="boot-demo">
|
||||
<div class="demo-label">操作系统启动流程 ── 点击逐步启动</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div
|
||||
v-for="(step, index) in steps"
|
||||
:key="step.name"
|
||||
class="timeline-item"
|
||||
:class="{ active: currentStep >= index }"
|
||||
@click="currentStep = index"
|
||||
>
|
||||
<div class="timeline-marker">
|
||||
<span class="marker-dot" :class="{ filled: currentStep >= index }">{{ index + 1 }}</span>
|
||||
<span v-if="index < steps.length - 1" class="marker-line" :class="{ filled: currentStep >= index }"></span>
|
||||
</div>
|
||||
<div class="timeline-content">
|
||||
<div class="step-name">{{ step.name }}</div>
|
||||
<div class="step-desc">{{ step.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击查看各步骤</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const currentStep = ref(0)
|
||||
const steps = [
|
||||
{ name: '引导程序', desc: '从硬盘读取 bootloader' },
|
||||
{ name: '内核加载', desc: '加载操作系统内核' },
|
||||
{ name: '系统服务', desc: '启动各种后台服务' },
|
||||
{ name: '桌面环境', desc: '显示登录界面和桌面' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.boot-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
padding: 0.3rem 0;
|
||||
opacity: 0.4;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.timeline-item.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.timeline-marker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.marker-dot {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 50%;
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-3);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.marker-dot.filled {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.marker-line {
|
||||
flex: 1;
|
||||
width: 2px;
|
||||
background: var(--vp-c-divider);
|
||||
min-height: 1.5rem;
|
||||
}
|
||||
|
||||
.marker-line.filled {
|
||||
background: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
flex: 1;
|
||||
padding-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.step-name {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.step-desc {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div class="browser-demo">
|
||||
<div class="demo-label">浏览器架构 ── 点击查看各模块</div>
|
||||
|
||||
<div class="browser-schema">
|
||||
<div class="browser-layers">
|
||||
<div
|
||||
v-for="layer in layers"
|
||||
:key="layer.name"
|
||||
class="layer"
|
||||
:class="{ active: activeLayer === layer.name }"
|
||||
@click="activeLayer = activeLayer === layer.name ? '' : layer.name"
|
||||
>
|
||||
<div class="layer-header">
|
||||
<span class="layer-name">{{ layer.name }}</span>
|
||||
<span class="layer-icon">{{ layer.icon }}</span>
|
||||
</div>
|
||||
<div v-if="activeLayer === layer.name" class="layer-detail">
|
||||
<div class="detail-text">{{ layer.desc }}</div>
|
||||
<div class="detail-examples">
|
||||
<span v-for="ex in layer.examples" :key="ex" class="example-tag">{{ ex }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击查看各模块详情</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const activeLayer = ref('')
|
||||
const layers = [
|
||||
{ name: '用户界面', icon: '🎨', desc: '你看到的地址栏、标签页、书签等', examples: ['地址栏', '标签页', '书签栏', '工具栏'] },
|
||||
{ name: '浏览器引擎', icon: '⚙️', desc: '协调 UI 和渲染引擎的桥梁', examples: ['Chrome: Blink', 'Firefox: Gecko', 'Safari: WebKit'] },
|
||||
{ name: '渲染引擎', icon: '📄', desc: '解析 HTML/CSS,把网页显示出来', examples: ['Blink', 'Gecko', 'WebKit'] },
|
||||
{ name: 'JavaScript 引擎', icon: '⚡', desc: '执行页面中的 JavaScript 代码', examples: ['V8', 'SpiderMonkey', 'JavaScriptCore'] },
|
||||
{ name: '网络模块', icon: '🌐', desc: '发送 HTTP/HTTPS 请求', examples: ['HTTP', 'HTTP/2', 'HTTP/3', 'WebSocket'] },
|
||||
{ name: '数据存储', icon: '💾', desc: '保存 Cookie、缓存等数据', examples: ['Cookie', 'LocalStorage', 'Cache'] }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.browser-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.browser-layers {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.layer {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.7rem;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.layer.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.layer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layer-name {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.layer-icon {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.layer-detail {
|
||||
margin-top: 0.5rem;
|
||||
padding-top: 0.5rem;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.detail-text {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.detail-examples {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.example-tag {
|
||||
font-size: 0.65rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div class="career-path-demo">
|
||||
<div class="demo-header">
|
||||
<span class="icon">🚀</span>
|
||||
<span class="title">工程师成长路径</span>
|
||||
<span class="subtitle">从入门到精通的技能演进</span>
|
||||
</div>
|
||||
|
||||
<div class="path-container">
|
||||
<div
|
||||
v-for="(stage, index) in stages"
|
||||
:key="stage.name"
|
||||
class="stage-card"
|
||||
:class="{ active: activeStage === index }"
|
||||
@click="activeStage = index"
|
||||
>
|
||||
<div class="stage-header">
|
||||
<span class="stage-icon">{{ stage.icon }}</span>
|
||||
<span class="stage-name">{{ stage.name }}</span>
|
||||
<span class="stage-time">{{ stage.time }}</span>
|
||||
</div>
|
||||
<div class="stage-content">
|
||||
<div class="stage-desc">{{ stage.desc }}</div>
|
||||
<div class="stage-skills">
|
||||
<span class="skill-label">核心技能:</span>
|
||||
<div class="skill-tags">
|
||||
<span v-for="skill in stage.skills" :key="skill" class="skill-tag">
|
||||
{{ skill }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stage-output">
|
||||
<span class="output-label">典型产出:</span>
|
||||
<span class="output-text">{{ stage.output }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="index < stages.length - 1" class="stage-arrow">→</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="path-insight">
|
||||
<div class="insight-icon">💡</div>
|
||||
<div class="insight-content">
|
||||
<div class="insight-title">成长关键点</div>
|
||||
<ul class="insight-list">
|
||||
<li>前 1-2 年:打基础,建立"能独立完成任务"的能力</li>
|
||||
<li>2-3 年:选方向,在某个领域建立深度</li>
|
||||
<li>3-5 年:横向扩展,培养架构思维和团队协作能力</li>
|
||||
<li>5 年+:技术决策、团队带领、技术影响力</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const activeStage = ref(0)
|
||||
|
||||
const stages = ref([
|
||||
{
|
||||
name: '入门期',
|
||||
icon: '🌱',
|
||||
time: '0-1 年',
|
||||
desc: '学习基础语法和工具,能完成简单任务',
|
||||
skills: ['一门语言基础', 'Git 使用', '调试技巧', '阅读文档'],
|
||||
output: '能独立完成小功能、修复简单 Bug'
|
||||
},
|
||||
{
|
||||
name: '成长期',
|
||||
icon: '🌿',
|
||||
time: '1-2 年',
|
||||
desc: '熟悉常用框架和最佳实践,能独立负责模块',
|
||||
skills: ['框架熟练', '代码规范', '单元测试', 'API 设计'],
|
||||
output: '独立负责一个功能模块,代码质量稳定'
|
||||
},
|
||||
{
|
||||
name: '进阶期',
|
||||
icon: '🌳',
|
||||
time: '2-3 年',
|
||||
desc: '深入某个领域,开始有技术选型能力',
|
||||
skills: ['领域深入', '性能优化', '架构设计', '技术选型'],
|
||||
output: '主导技术方案设计,解决复杂问题'
|
||||
},
|
||||
{
|
||||
name: '成熟期',
|
||||
icon: '🌲',
|
||||
time: '3-5 年',
|
||||
desc: '全栈能力或领域专家,能带领小团队',
|
||||
skills: ['全栈能力', '团队协作', '技术分享', '项目管理'],
|
||||
output: '负责核心系统,指导新人成长'
|
||||
},
|
||||
{
|
||||
name: '专家期',
|
||||
icon: '🏔️',
|
||||
time: '5 年+',
|
||||
desc: '技术决策者,有行业影响力',
|
||||
skills: ['技术战略', '团队建设', '行业洞察', '创新引领'],
|
||||
output: '技术方向决策,培养技术团队'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.career-path-demo {
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.path-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stage-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stage-card:hover {
|
||||
transform: translateX(4px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.stage-card.active {
|
||||
border-color: #3b82f6;
|
||||
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
|
||||
}
|
||||
|
||||
.stage-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.stage-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.stage-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.stage-time {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
background: #f1f5f9;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.stage-content {
|
||||
padding-left: 36px;
|
||||
}
|
||||
|
||||
.stage-desc {
|
||||
font-size: 14px;
|
||||
color: #475569;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.stage-skills {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.skill-label,
|
||||
.output-label {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.skill-tags {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.skill-tag {
|
||||
font-size: 12px;
|
||||
background: #e0f2fe;
|
||||
color: #0369a1;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.stage-output {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.output-text {
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.stage-arrow {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 20px;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.path-insight {
|
||||
margin-top: 24px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
border-left: 4px solid #f59e0b;
|
||||
}
|
||||
|
||||
.insight-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.insight-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.insight-list {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.insight-list li {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.stage-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.stage-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<div class="field-map-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">计算机领域全景图</span>
|
||||
<span class="subtitle">点击查看详情</span>
|
||||
</div>
|
||||
|
||||
<div class="field-grid">
|
||||
<div
|
||||
v-for="field in fields"
|
||||
:key="field.name"
|
||||
class="field-card"
|
||||
:class="{ active: activeField === field.name }"
|
||||
@click="activeField = field.name"
|
||||
>
|
||||
<div class="field-name">{{ field.name }}</div>
|
||||
<div class="field-desc">{{ field.desc }}</div>
|
||||
<div class="field-techs">
|
||||
<span v-for="tech in field.techs" :key="tech" class="tech-tag">{{ tech }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>建议:</strong>不要试图一次学完所有方向。先选一个方向深入,建立"根据地",再横向扩展。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const activeField = ref('前端')
|
||||
|
||||
const fields = ref([
|
||||
{
|
||||
name: '前端',
|
||||
desc: '用户能看到、能交互的一切',
|
||||
techs: ['HTML/CSS', 'JavaScript', 'React/Vue']
|
||||
},
|
||||
{
|
||||
name: '后端',
|
||||
desc: '服务器端的业务逻辑和数据处理',
|
||||
techs: ['Node.js', 'Go', 'Java', 'Python']
|
||||
},
|
||||
{
|
||||
name: '移动端',
|
||||
desc: '手机上的应用体验',
|
||||
techs: ['Swift', 'Kotlin', 'Flutter']
|
||||
},
|
||||
{
|
||||
name: 'AI/算法',
|
||||
desc: '让系统变"聪明"',
|
||||
techs: ['PyTorch', 'TensorFlow', '机器学习']
|
||||
},
|
||||
{
|
||||
name: '运维/DevOps',
|
||||
desc: '保证系统稳定运行',
|
||||
techs: ['Docker', 'K8s', 'CI/CD']
|
||||
},
|
||||
{
|
||||
name: '数据工程',
|
||||
desc: '数据采集、存储、分析',
|
||||
techs: ['SQL', 'Spark', '数据仓库']
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.field-map-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.field-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.field-card {
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.field-card:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.field-card.active {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.field-name {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.field-desc {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.field-techs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.tech-tag {
|
||||
font-size: 0.68rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.field-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+750
-302
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div class="desktop-demo">
|
||||
<div class="demo-label">桌面是如何出现的 ── 点击加载</div>
|
||||
|
||||
<div class="desktop-view" @click="loading = !loading">
|
||||
<div class="screen" :class="{ loaded: loading }">
|
||||
<div class="boot-screen" v-if="!loading">
|
||||
<div class="boot-logo">⚙️</div>
|
||||
<div class="boot-text">正在启动...</div>
|
||||
</div>
|
||||
<div class="desktop" v-else>
|
||||
<div class="desktop-icons">
|
||||
<div class="desktop-icon">📁</div>
|
||||
<div class="desktop-icon">🗑️</div>
|
||||
<div class="desktop-icon">⚙️</div>
|
||||
<div class="desktop-icon">🌐</div>
|
||||
</div>
|
||||
<div class="taskbar">
|
||||
<div class="taskbar-icon">🏠</div>
|
||||
<div class="taskbar-icon">📊</div>
|
||||
<div class="taskbar-time">{{ time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击切换开机状态</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
const loading = ref(false)
|
||||
const time = ref('')
|
||||
|
||||
let timer = null
|
||||
|
||||
const updateTime = () => {
|
||||
const now = new Date()
|
||||
time.value = now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
updateTime()
|
||||
timer = setInterval(updateTime, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.desktop-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.desktop-view {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.screen {
|
||||
width: 14rem;
|
||||
height: 9rem;
|
||||
background: #1a1a1a;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.screen.loaded {
|
||||
background: linear-gradient(180deg, #2d5af5 0%, #1e3a8a 100%);
|
||||
}
|
||||
|
||||
.boot-screen {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.boot-logo {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.boot-text {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.desktop {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.desktop-icons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.desktop-icon {
|
||||
width: 2.2rem;
|
||||
height: 2.2rem;
|
||||
background: rgba(255,255,255,0.15);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.taskbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: rgba(0,0,0,0.3);
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.taskbar-icon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
background: rgba(255,255,255,0.2);
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.taskbar-time {
|
||||
margin-left: auto;
|
||||
font-size: 0.7rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div class="skill-shift-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">能力重要性变化</span>
|
||||
<span class="subtitle">AI 时代,哪些能力更重要了?</span>
|
||||
</div>
|
||||
|
||||
<div class="comparison-grid">
|
||||
<div class="column">
|
||||
<div class="column-title">传统时代更重要</div>
|
||||
<div class="skill-list">
|
||||
<div v-for="skill in beforeSkills" :key="skill.name" class="skill-item">
|
||||
<span class="skill-name">{{ skill.name }}</span>
|
||||
<div class="skill-bar">
|
||||
<div class="bar-fill before" :style="{ width: skill.level + '%' }"></div>
|
||||
</div>
|
||||
<span class="skill-desc">{{ skill.desc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="column-title">AI 时代更重要</div>
|
||||
<div class="skill-list">
|
||||
<div v-for="skill in afterSkills" :key="skill.name" class="skill-item">
|
||||
<span class="skill-name">{{ skill.name }}</span>
|
||||
<div class="skill-bar">
|
||||
<div class="bar-fill after" :style="{ width: skill.level + '%' }"></div>
|
||||
</div>
|
||||
<span class="skill-desc">{{ skill.desc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>关键洞察:</strong>AI 能帮你写代码,但判断力、架构思维、领域知识、调试能力是 AI 替代不了的。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const beforeSkills = ref([
|
||||
{ name: '语法记忆', level: 90, desc: '熟记 API 和语法细节' },
|
||||
{ name: '手写代码速度', level: 85, desc: '快速敲代码的能力' },
|
||||
{ name: '查文档能力', level: 80, desc: '快速找到 API 用法' }
|
||||
])
|
||||
|
||||
const afterSkills = ref([
|
||||
{ name: '需求描述能力', level: 95, desc: '用自然语言准确描述需求' },
|
||||
{ name: '代码审核能力', level: 90, desc: '判断 AI 生成代码的对错' },
|
||||
{ name: '架构设计能力', level: 85, desc: '设计系统整体结构' },
|
||||
{ name: '问题定位能力', level: 80, desc: '出问题时知道从哪排查' }
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.skill-shift-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.comparison-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.column-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px dashed var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.skill-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.skill-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.skill-name {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.skill-bar {
|
||||
height: 6px;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.bar-fill.before {
|
||||
background: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.bar-fill.after {
|
||||
background: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.skill-desc {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.comparison-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="framework-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">前端框架演进</span>
|
||||
<span class="subtitle">从 jQuery 到现代框架</span>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div v-for="(era, index) in eras" :key="era.name" class="era-item">
|
||||
<div class="era-marker">
|
||||
<span class="era-dot"></span>
|
||||
<span v-if="index < eras.length - 1" class="era-line"></span>
|
||||
</div>
|
||||
<div class="era-content">
|
||||
<div class="era-header">
|
||||
<span class="era-name">{{ era.name }}</span>
|
||||
<span class="era-time">{{ era.time }}</span>
|
||||
</div>
|
||||
<div class="era-desc">{{ era.desc }}</div>
|
||||
<div class="era-techs">
|
||||
<span v-for="tech in era.techs" :key="tech" class="tech-tag">{{ tech }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>框架的本质:</strong>解决"数据变化后如何高效更新 UI"的问题。现代框架让你只需关注"数据是什么",框架自动处理"UI 怎么变"。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const eras = ref([
|
||||
{
|
||||
name: '原生时代',
|
||||
time: '1990s',
|
||||
desc: '直接操作 DOM,一切从零开始',
|
||||
techs: ['HTML', 'CSS', 'JavaScript']
|
||||
},
|
||||
{
|
||||
name: 'jQuery 时代',
|
||||
time: '2006-2015',
|
||||
desc: '简化 DOM 操作,跨浏览器兼容',
|
||||
techs: ['jQuery', 'Bootstrap']
|
||||
},
|
||||
{
|
||||
name: 'MVVM 时代',
|
||||
time: '2010-2015',
|
||||
desc: '数据驱动视图,双向绑定',
|
||||
techs: ['Angular.js', 'Knockout']
|
||||
},
|
||||
{
|
||||
name: '组件化时代',
|
||||
time: '2013-至今',
|
||||
desc: '声明式、组件化、虚拟 DOM',
|
||||
techs: ['React', 'Vue', 'Angular']
|
||||
},
|
||||
{
|
||||
name: '新时代',
|
||||
time: '2020-至今',
|
||||
desc: '编译时优化,更少运行时开销',
|
||||
techs: ['Svelte', 'Solid']
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.framework-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.era-item {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.era-marker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.era-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: var(--vp-c-brand-1);
|
||||
border: 2px solid var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.era-line {
|
||||
width: 2px;
|
||||
flex: 1;
|
||||
background: var(--vp-c-divider);
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.era-content {
|
||||
flex: 1;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.era-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.era-name {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.era-time {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 0.1rem 0.35rem;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.era-desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.era-techs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.tech-tag {
|
||||
font-size: 0.68rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
</style>
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<div class="triad-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">前端三件套</span>
|
||||
<span class="subtitle">网页开发的三大基石</span>
|
||||
</div>
|
||||
|
||||
<div class="triad-grid">
|
||||
<div
|
||||
v-for="tech in triad"
|
||||
:key="tech.name"
|
||||
class="tech-card"
|
||||
:class="{ active: activeTech === tech.name }"
|
||||
@click="activeTech = tech.name"
|
||||
>
|
||||
<div class="tech-name">{{ tech.name }}</div>
|
||||
<div class="tech-role">{{ tech.role }}</div>
|
||||
<div class="tech-analogy">{{ tech.analogy }}</div>
|
||||
<div class="tech-examples">
|
||||
<span v-for="ex in tech.examples" :key="ex" class="example-tag">{{ ex }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>协作关系:</strong>HTML 搭骨架,CSS 穿衣服,JavaScript 让它动起来。三者缺一不可。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const activeTech = ref('HTML')
|
||||
|
||||
const triad = ref([
|
||||
{
|
||||
name: 'HTML',
|
||||
role: '结构层',
|
||||
analogy: '房子的骨架:墙、门、窗',
|
||||
examples: ['div', 'span', 'form', 'input']
|
||||
},
|
||||
{
|
||||
name: 'CSS',
|
||||
role: '表现层',
|
||||
analogy: '房子的装修:颜色、位置、大小',
|
||||
examples: ['color', 'flex', 'grid', 'animation']
|
||||
},
|
||||
{
|
||||
name: 'JavaScript',
|
||||
role: '行为层',
|
||||
analogy: '房子的智能:开关灯、开门',
|
||||
examples: ['事件', 'DOM操作', '网络请求']
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.triad-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.triad-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.tech-card {
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.tech-card:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.tech-card.active {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.tech-name {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.tech-role {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-brand-1);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.tech-analogy {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.tech-examples {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.example-tag {
|
||||
font-size: 0.68rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.triad-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="full-process-demo">
|
||||
<div class="demo-label">完整流程概览 ── 点击逐步演示</div>
|
||||
|
||||
<div class="process-flow">
|
||||
<div
|
||||
v-for="(phase, index) in phases"
|
||||
:key="phase.name"
|
||||
class="phase"
|
||||
:class="{ active: currentPhase >= index }"
|
||||
@click="currentPhase = index"
|
||||
>
|
||||
<div class="phase-icon">{{ phase.icon }}</div>
|
||||
<div class="phase-name">{{ phase.name }}</div>
|
||||
<div class="phase-steps">
|
||||
<span v-for="step in phase.steps" :key="step" class="step-tag">{{ step }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击查看各阶段</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const currentPhase = ref(0)
|
||||
const phases = [
|
||||
{ icon: '🔌', name: '硬件启动', steps: ['电源', '主板', 'CPU', 'BIOS'] },
|
||||
{ icon: '💻', name: '系统启动', steps: ['引导程序', '内核', '服务', '桌面'] },
|
||||
{ icon: '🌐', name: '浏览器', steps: ['双击图标', '加载程序', '显示窗口'] },
|
||||
{ icon: '📡', name: '网络请求', steps: ['URL解析', 'DNS', 'TCP', 'HTTP'] },
|
||||
{ icon: '🎨', name: '页面渲染', steps: ['HTML解析', 'CSS', '布局', '绘制'] }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.full-process-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.process-flow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.phase {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.6rem 0.4rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
opacity: 0.4;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.phase.active {
|
||||
opacity: 1;
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.phase-icon {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.phase-name {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.phase-steps {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.step-tag {
|
||||
font-size: 0.58rem;
|
||||
text-align: center;
|
||||
padding: 0.15rem 0;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.phase.active .step-tag {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div class="fullstack-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">全栈技能树</span>
|
||||
<span class="subtitle">前后端通吃的核心能力</span>
|
||||
</div>
|
||||
|
||||
<div class="skill-sections">
|
||||
<div class="skill-section">
|
||||
<div class="section-title">前端能力</div>
|
||||
<div class="skill-list">
|
||||
<div v-for="skill in frontendSkills" :key="skill" class="skill-item">{{ skill }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-section bridge">
|
||||
<div class="section-title">全栈核心</div>
|
||||
<div class="skill-list">
|
||||
<div v-for="skill in bridgeSkills" :key="skill" class="skill-item highlight">{{ skill }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-section">
|
||||
<div class="section-title">后端能力</div>
|
||||
<div class="skill-list">
|
||||
<div v-for="skill in backendSkills" :key="skill" class="skill-item">{{ skill }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>全栈不等于全部精通:</strong>核心是打通前后端,能独立完成一个完整功能。不需要在每个领域都达到专家级别。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const frontendSkills = ref(['HTML/CSS', 'JavaScript', '框架使用', '响应式设计'])
|
||||
const backendSkills = ref(['API 设计', '数据库操作', '业务逻辑', '服务器部署'])
|
||||
const bridgeSkills = ref(['HTTP 协议', 'Git 协作', '调试能力', '系统设计'])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fullstack-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.skill-sections {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.skill-section {
|
||||
padding: 0.6rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.skill-section.bridge {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.35rem;
|
||||
border-bottom: 1px dashed var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.skill-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.skill-item {
|
||||
font-size: 0.72rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.skill-item.highlight {
|
||||
background: var(--vp-c-brand-soft);
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.skill-sections {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div class="language-selection-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">语言选择指南</span>
|
||||
<span class="subtitle">根据目标选语言</span>
|
||||
</div>
|
||||
|
||||
<div class="selection-grid">
|
||||
<div v-for="item in selections" :key="item.goal" class="selection-card">
|
||||
<div class="goal-name">{{ item.goal }}</div>
|
||||
<div class="goal-desc">{{ item.desc }}</div>
|
||||
<div class="goal-langs">
|
||||
<span class="lang-label">推荐:</span>
|
||||
<span v-for="lang in item.langs" :key="lang" class="lang-tag">{{ lang }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>核心原则:</strong>语言只是工具,重要的是解决问题的能力。先精通一门,再触类旁通。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const selections = ref([
|
||||
{ goal: 'Web 前端', desc: '网页、小程序、H5', langs: ['JavaScript', 'TypeScript'] },
|
||||
{ goal: 'Web 后端', desc: 'API 服务、业务系统', langs: ['Node.js', 'Go', 'Java', 'Python'] },
|
||||
{ goal: '移动端', desc: 'iOS / Android 应用', langs: ['Swift', 'Kotlin', 'Flutter'] },
|
||||
{ goal: 'AI / 数据科学', desc: '机器学习、数据分析', langs: ['Python'] },
|
||||
{ goal: '系统编程', desc: '操作系统、嵌入式', langs: ['C', 'C++', 'Rust'] },
|
||||
{ goal: '快速原型', desc: '脚本、自动化、小工具', langs: ['Python', 'Shell'] }
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.language-selection-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.selection-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.selection-card {
|
||||
padding: 0.6rem 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.goal-name {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.goal-desc {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.goal-langs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.lang-label {
|
||||
font-size: 0.68rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.lang-tag {
|
||||
font-size: 0.68rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.selection-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div class="strategy-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">Vibe Coding 学习策略</span>
|
||||
<span class="subtitle">AI 时代怎么学更高效</span>
|
||||
</div>
|
||||
|
||||
<div class="strategy-list">
|
||||
<div v-for="(strategy, index) in strategies" :key="index" class="strategy-item">
|
||||
<div class="strategy-num">{{ index + 1 }}</div>
|
||||
<div class="strategy-content">
|
||||
<div class="strategy-title">{{ strategy.title }}</div>
|
||||
<div class="strategy-desc">{{ strategy.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>核心原则:</strong>AI 是你的编程助手,但决策者永远是你。学会提问、学会判断、学会整合,比学会写代码更重要。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const strategies = ref([
|
||||
{
|
||||
title: '先理解,再让 AI 写',
|
||||
desc: '不要一上来就让 AI 写代码。先理解问题是什么,想清楚解决方案,再用 AI 加速实现。'
|
||||
},
|
||||
{
|
||||
title: '把 AI 当结对编程伙伴',
|
||||
desc: '遇到不懂的概念,问 AI 解释。遇到复杂问题,和 AI 讨论方案。AI 是你的知识渊博的同事。'
|
||||
},
|
||||
{
|
||||
title: '学会审核 AI 的输出',
|
||||
desc: 'AI 生成的代码不一定对。你需要有能力判断:逻辑对不对?有没有安全隐患?性能如何?'
|
||||
},
|
||||
{
|
||||
title: '建立自己的知识体系',
|
||||
desc: 'AI 能帮你查漏补缺,但核心知识框架要自己建立。知道"有什么",才能问出"怎么用"。'
|
||||
},
|
||||
{
|
||||
title: '在实践中学习',
|
||||
desc: '做真实的项目,解决真实的问题。AI 帮你扫清语法障碍,你专注于解决业务问题。'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.strategy-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.strategy-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.strategy-item {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.strategy-num {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
background: var(--vp-c-brand-1);
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.strategy-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.strategy-title {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.strategy-desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-3);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,386 @@
|
||||
<template>
|
||||
<div class="cpu-internal-demo">
|
||||
<div class="demo-title">CPU 内部微架构剖析</div>
|
||||
<div class="demo-subtitle">点击下方各个模块,查看其内部由哪些子电路构成以及工作原理</div>
|
||||
|
||||
<div class="demo-container">
|
||||
<div class="cpu-chip">
|
||||
<div class="chip-title">CPU 核心 (Central Processing Unit)</div>
|
||||
|
||||
<div class="bus-top address-bus" :class="{ active: currentModule === 'address_bus' }" @click="selectModule('address_bus')">地址总线 (Address Bus)</div>
|
||||
<div class="bus-top data-bus" :class="{ active: currentModule === 'data_bus' }" @click="selectModule('data_bus')">数据总线 (Data Bus)</div>
|
||||
|
||||
<div class="cpu-layout">
|
||||
<!-- 左侧:控制单元 -->
|
||||
<div class="cu-section section-box" :class="{ active: currentModule === 'cu' }" @click.stop="selectModule('cu')">
|
||||
<h4 class="section-title">控制单元 (Control Unit)</h4>
|
||||
<div class="sub-modules">
|
||||
<div class="sub-mod" :class="{ active: currentModule === 'pc' }" @click.stop="selectModule('pc')">程序计数器 (PC)</div>
|
||||
<div class="sub-mod" :class="{ active: currentModule === 'ir' }" @click.stop="selectModule('ir')">指令寄存器 (IR)</div>
|
||||
<div class="sub-mod" :class="{ active: currentModule === 'decoder' }" @click.stop="selectModule('decoder')">指令译码器</div>
|
||||
<div class="sub-mod" :class="{ active: currentModule === 'clock' }" @click.stop="selectModule('clock')">时钟发生器</div>
|
||||
</div>
|
||||
<div class="control-lines">控制信号线 ↓</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:数据通道(ALU + 寄存器) -->
|
||||
<div class="datapath-section">
|
||||
<!-- 寄存器组 -->
|
||||
<div class="reg-section section-box" :class="{ active: currentModule === 'reg' }" @click.stop="selectModule('reg')">
|
||||
<h4 class="section-title">寄存器组 (Register File)</h4>
|
||||
<div class="sub-modules grid-2">
|
||||
<div class="sub-mod">通用寄存器 R0-R3</div>
|
||||
<div class="sub-mod">累加器 (ACC)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ALU -->
|
||||
<div class="alu-section section-box" :class="{ active: currentModule === 'alu' }" @click.stop="selectModule('alu')">
|
||||
<h4 class="section-title">算术逻辑单元 (ALU)</h4>
|
||||
<div class="sub-modules">
|
||||
<div class="sub-mod" :class="{ active: currentModule === 'adder' }" @click.stop="selectModule('adder')">加法器电路</div>
|
||||
<div class="sub-mod" :class="{ active: currentModule === 'flags' }" @click.stop="selectModule('flags')">状态标志 (Flags)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bus-bottom control-bus" :class="{ active: currentModule === 'control_bus' }" @click="selectModule('control_bus')">控制总线 (Control Bus)</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧/下方详细说明面板 -->
|
||||
<div class="details-panel" v-if="currentModuleData">
|
||||
<h3>{{ currentModuleData.title }}</h3>
|
||||
<p class="desc">{{ currentModuleData.description }}</p>
|
||||
<div class="circuit-impl" v-if="currentModuleData.subCircuit">
|
||||
<h4><span class="icon">🔌</span> 底层子电路实现:</h4>
|
||||
<p>{{ currentModuleData.subCircuit }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="details-panel empty" v-else>
|
||||
<div class="empty-icon">🖱️</div>
|
||||
<p>点击左侧 CPU 内部结构图的各个模块,<br>深入探索其微观电路实现。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const currentModule = ref(null)
|
||||
|
||||
const moduleInfo = {
|
||||
// ALU 相关
|
||||
alu: {
|
||||
title: '算术逻辑单元 (ALU)',
|
||||
description: 'ALU 是 CPU 中负责进行数学运算(加减法)和逻辑运算(与、或、非、异或)的核心引擎。所有的高级数学计算最终都会被分解为 ALU 能够执行的这些基础操作。',
|
||||
subCircuit: '由海量的逻辑门组成。核心是半加器和全加器的级联(如行波进位加法器或超前进位加法器),并结合多路选择器(MUX)来决定当前是输出加法结果还是某种逻辑运算结果。'
|
||||
},
|
||||
adder: {
|
||||
title: '加法器电路 (Adder)',
|
||||
description: '负责执行二进制加法。',
|
||||
subCircuit: '底层由异或门(XOR)负责本位相加,与门(AND)和或门(OR)负责产生对高位的进位信号。几十个全加器串联即可实现 32/64 位数的加法。'
|
||||
},
|
||||
flags: {
|
||||
title: '状态标志寄存器 (Flags)',
|
||||
description: '记录上一次 ALU 运算的“副作用”特征,例如结果是否为零(Z)、是否产生进位(C)、符号是正还是负(S)、是否溢出(O)。它是实现 `if/else` 等条件跳转指令的核心物理依据。',
|
||||
subCircuit: '一组特定的触发器(Flip-Flops),每个触发器通过逻辑门直接连接在 ALU 的输出端电路上。'
|
||||
},
|
||||
|
||||
// 寄存器相关
|
||||
reg: {
|
||||
title: '寄存器组 (Register File)',
|
||||
description: 'CPU 内部的高速“草稿本”。由于直接嵌在指令执行的数据通路中,其读写速度和 CPU 主频几乎一致。用来暂存 ALU 需要的输入数据和刚刚算出的输出结果。',
|
||||
subCircuit: '本质上是由成千上万个 D 型触发器(D Flip-Flop)按位宽(如 64 位)并列组合而成。配合多路选择器和地址译码电路,实现对特定“草稿本”的数据寻址读写。'
|
||||
},
|
||||
|
||||
// 控制单元相关
|
||||
cu: {
|
||||
title: '控制单元 (Control Unit, CU)',
|
||||
description: '整个 CPU 的“大脑和总指挥”。它并不直接参与运算,而是负责从内存读取指令,翻译指令,并像“拉线木偶”一样向全芯片发出各种导通和关断电信号,指挥其余部件开始工作。',
|
||||
subCircuit: '通常存在有限状态机(FSM)或微程序的实现方式。本质上是一组庞大复杂的逻辑门网络和触发器组合,将输入的二进制指令(如 0x01)映射为激活对应模块的控制电平。'
|
||||
},
|
||||
pc: {
|
||||
title: '程序计数器 (Program Counter, PC)',
|
||||
description: '永远指向“下一条要执行的指令”在内存中的具体地址。每次成功执行完一条指令,它就会自动递增。当程序发生函数调用或循环跳转时,它的值会被强行改写。',
|
||||
subCircuit: '一个带有“自增电路(Incrementer)”的寄存器。通过内部的简单半加器加上时钟脉冲边界的触发来同步更新地址值。'
|
||||
},
|
||||
ir: {
|
||||
title: '指令寄存器 (Instruction Register, IR)',
|
||||
description: '暂存刚刚从内存中读出、当前正在处于“译码”阶段的那条二进制机器指令。',
|
||||
subCircuit: '同样是一排带写使能(Write-Enable)控制端的触发器(Flip-Flop),在"取指"周期时,写使能为1,锁存进指令数据。'
|
||||
},
|
||||
decoder: {
|
||||
title: '指令译码器 (Instruction Decoder)',
|
||||
description: '负责破译 IR 中的一长串 0 和 1 到底是什么意思。把二进制的机器码切分成“操作码”(做什么,如做加法)和“操作数”(对谁做,如寻址寄存器)。',
|
||||
subCircuit: '由大量的与门和非门组成的组合电路网络。比如输入操作码 0010,只有代表“ADD操作”的那根特定输出管脚会被置 1,其他管脚保持 0。'
|
||||
},
|
||||
clock: {
|
||||
title: '时钟发生器 (Clock)',
|
||||
description: 'CPU 的心脏节拍器。发出持续的方波信号,同步全系统各个部件的工作节奏。每一次时钟波形的上升沿,所有的触发器才会统一改变锁存状态(即节拍)。',
|
||||
subCircuit: '外部主板上的石英晶振产生极准的基础震荡信号,结合 CPU 内部的锁相环(PLL)倍频电路生成极高频率的脉冲方波。'
|
||||
},
|
||||
|
||||
// 总线
|
||||
address_bus: {
|
||||
title: '地址总线 (Address Bus)',
|
||||
description: '单向传输总线。CPU 通过这组电线,将它想访问的内存单元或 I/O 设备地址发送出去。地址总线的宽度决定了 CPU 最大能寻址多少内存(比如 32 位地址总线最多覆盖 4GB 寻址)。',
|
||||
subCircuit: '物理上就是一块芯片引出的几十根极其细微的平行导线。通常受到三态门缓冲器(Tri-state Buffer)所驱动。'
|
||||
},
|
||||
data_bus: {
|
||||
title: '数据总线 (Data Bus)',
|
||||
description: '双向传输总线。在这组电线上,数据可以从 CPU 流向内存,也可以从内存流回 CPU。它的宽度就是我们平常所说的 32位/64位 处理器一次性处理的数据通路宽度。',
|
||||
subCircuit: '同样是平行的导电线路,但两端接有方向控制引脚的三态门,确保不会由于多方同时施加高低电平导致设备短路。'
|
||||
},
|
||||
control_bus: {
|
||||
title: '控制总线 (Control Bus)',
|
||||
description: '混合传输总线,承载各种不同类型的核心控制信号:例如“我要读(Read)”、“我要写(Write)”、“外设的中断请求”、“等待反馈”等。',
|
||||
subCircuit: '每一条线路一般都有单独而明确的功能分配,直接由控制单元(CU)的逻辑组合端引出,连接并支配外部的所有硬件。'
|
||||
}
|
||||
}
|
||||
|
||||
const currentModuleData = computed(() => moduleInfo[currentModule.value])
|
||||
|
||||
function selectModule(mod) {
|
||||
if (currentModule.value === mod) {
|
||||
currentModule.value = null
|
||||
} else {
|
||||
currentModule.value = mod
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cpu-internal-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
text-align: center;
|
||||
font-weight: 800;
|
||||
font-size: 1.25rem;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.demo-subtitle {
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.cpu-chip {
|
||||
flex: 3;
|
||||
background: var(--vp-c-bg);
|
||||
border: 3px solid #64748b;
|
||||
border-radius: 12px;
|
||||
padding: 1rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.chip-title {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: #64748b;
|
||||
color: #fff;
|
||||
padding: 2px 12px;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bus-top, .bus-bottom {
|
||||
text-align: center;
|
||||
padding: 0.4rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
border: 2px dashed var(--vp-c-text-3);
|
||||
background: var(--vp-c-bg-alt);
|
||||
}
|
||||
|
||||
.bus-top:hover, .bus-bottom:hover, .bus-top.active, .bus-bottom.active {
|
||||
border-style: solid;
|
||||
border-color: var(--vp-c-brand-1);
|
||||
background: var(--vp-c-brand-soft);
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.cpu-layout {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex: 1;
|
||||
min-height: 280px;
|
||||
}
|
||||
|
||||
.section-box {
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 0.8rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: all 0.2s;
|
||||
cursor: pointer;
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.section-box:hover, .section-box.active {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.cu-section { margin-top: 0; }
|
||||
.cu-section:hover, .cu-section.active { border-color: #3b82f6; }
|
||||
.reg-section:hover, .reg-section.active { border-color: #8b5cf6; }
|
||||
.alu-section:hover, .alu-section.active { border-color: #f59e0b; }
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 0.8rem 0;
|
||||
font-size: 0.95rem;
|
||||
text-align: center;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.cu-section {
|
||||
flex: 5;
|
||||
}
|
||||
|
||||
.datapath-section {
|
||||
flex: 7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.sub-modules {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.sub-mod {
|
||||
font-size: 0.8rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.sub-mod:hover, .sub-mod.active {
|
||||
background: var(--vp-c-brand-1);
|
||||
color: #fff;
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.cu-section .sub-mod:hover, .cu-section .sub-mod.active { background: #3b82f6; border-color: #3b82f6; }
|
||||
.alu-section .sub-mod:hover, .alu-section .sub-mod.active { background: #f59e0b; border-color: #f59e0b; }
|
||||
.reg-section .sub-mod:hover, .reg-section .sub-mod.active { background: #8b5cf6; border-color: #8b5cf6; }
|
||||
|
||||
|
||||
.control-lines {
|
||||
text-align: center;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.5rem;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.details-panel {
|
||||
flex: 2;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: inset 0 0 0 1px var(--vp-c-divider);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.details-panel h3 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--vp-c-brand-1);
|
||||
font-size: 1.2rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.details-panel .desc {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.circuit-impl {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-left: 4px solid var(--vp-c-brand-2);
|
||||
padding: 1rem;
|
||||
border-radius: 0 4px 4px 0;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.circuit-impl h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 0.95rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.circuit-impl p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.empty {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
border: 1px dashed var(--vp-c-divider);
|
||||
text-align: center;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.demo-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
.cpu-layout {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="power-on-demo">
|
||||
<div class="demo-label">电脑启动第一步 ── 点击通电</div>
|
||||
|
||||
<div class="sequence" @click="powerOn = !powerOn">
|
||||
<div class="step" :class="{ active: powerOn }">
|
||||
<div class="step-icon">🔌</div>
|
||||
<div class="step-name">电源</div>
|
||||
<div class="step-status">{{ powerOn ? '✅ 供电中' : '⬜ 等待' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">→</div>
|
||||
|
||||
<div class="step" :class="{ active: powerOn }">
|
||||
<div class="step-icon">🔋</div>
|
||||
<div class="step-name">主板</div>
|
||||
<div class="step-status">{{ powerOn ? '✅ 唤醒' : '⬜ 等待' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">→</div>
|
||||
|
||||
<div class="step" :class="{ active: powerOn }">
|
||||
<div class="step-icon">⚙️</div>
|
||||
<div class="step-name">CPU</div>
|
||||
<div class="step-status">{{ powerOn ? '✅ 复位' : '⬜ 等待' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">→</div>
|
||||
|
||||
<div class="step" :class="{ active: powerOn }">
|
||||
<div class="step-icon">💾</div>
|
||||
<div class="step-name">BIOS</div>
|
||||
<div class="step-status">{{ powerOn ? '✅ 启动' : '⬜ 等待' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击切换电源状态</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const powerOn = ref(false)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.power-on-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.sequence {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.6rem;
|
||||
border-radius: 6px;
|
||||
opacity: 0.4;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.step.active {
|
||||
opacity: 1;
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.step-icon {
|
||||
font-size: 1.3rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.step-name {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.step-status {
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<div class="language-map-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">编程语言分类</span>
|
||||
<span class="subtitle">不同维度看语言</span>
|
||||
</div>
|
||||
|
||||
<div class="classification-tabs">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
class="tab-btn"
|
||||
:class="{ active: activeTab === tab.key }"
|
||||
@click="activeTab = tab.key"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="classification-content">
|
||||
<div v-for="item in currentItems" :key="item.name" class="item-card">
|
||||
<div class="item-name">{{ item.name }}</div>
|
||||
<div class="item-desc">{{ item.desc }}</div>
|
||||
<div class="item-examples">
|
||||
<span v-for="ex in item.examples" :key="ex" class="example-tag">{{ ex }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>选择建议:</strong>先学一门主流语言深入,理解编程思想,再学其他语言会容易很多。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const activeTab = ref('type')
|
||||
|
||||
const tabs = [
|
||||
{ key: 'type', label: '按类型系统' },
|
||||
{ key: 'level', label: '按抽象层级' },
|
||||
{ key: 'paradigm', label: '按编程范式' }
|
||||
]
|
||||
|
||||
const classifications = {
|
||||
type: [
|
||||
{ name: '静态类型', desc: '变量类型在编译时确定', examples: ['Java', 'C++', 'Go', 'TypeScript'] },
|
||||
{ name: '动态类型', desc: '变量类型在运行时确定', examples: ['Python', 'JavaScript', 'Ruby'] }
|
||||
],
|
||||
level: [
|
||||
{ name: '低级语言', desc: '接近硬件,执行效率高', examples: ['C', '汇编'] },
|
||||
{ name: '高级语言', desc: '接近人类语言,开发效率高', examples: ['Python', 'Java', 'JavaScript'] }
|
||||
],
|
||||
paradigm: [
|
||||
{ name: '面向对象', desc: '以对象为中心组织代码', examples: ['Java', 'C++', 'Python'] },
|
||||
{ name: '函数式', desc: '以函数为中心,强调不可变', examples: ['Haskell', 'Elixir', 'Clojure'] },
|
||||
{ name: '多范式', desc: '支持多种编程风格', examples: ['Python', 'JavaScript', 'Rust'] }
|
||||
]
|
||||
}
|
||||
|
||||
const currentItems = computed(() => classifications[activeTab.value])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.language-map-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.classification-tabs {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
padding: 0.35rem 0.75rem;
|
||||
font-size: 0.78rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-2);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: var(--vp-c-brand-1);
|
||||
border-color: var(--vp-c-brand-1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.classification-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.item-card {
|
||||
padding: 0.6rem 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.item-examples {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.example-tag {
|
||||
font-size: 0.68rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
border-left: 3px solid var(--vp-c-brand-1);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="rendering-demo">
|
||||
<div class="demo-label">浏览器渲染过程 ── 点击逐步演示</div>
|
||||
|
||||
<div class="pipeline">
|
||||
<div
|
||||
v-for="(stage, index) in stages"
|
||||
:key="stage.name"
|
||||
class="pipeline-stage"
|
||||
:class="{ active: currentStage >= index }"
|
||||
@click="currentStage = index"
|
||||
>
|
||||
<div class="stage-header">
|
||||
<span class="stage-num">{{ index + 1 }}</span>
|
||||
<span class="stage-name">{{ stage.name }}</span>
|
||||
</div>
|
||||
<div class="stage-desc">{{ stage.desc }}</div>
|
||||
<div v-if="currentStage >= index" class="stage-detail">
|
||||
{{ stage.detail }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击查看各阶段详情</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const currentStage = ref(0)
|
||||
const stages = [
|
||||
{ name: 'HTML 解析', desc: '把 HTML 变成 DOM 树', detail: '<div> → Document Object Model 树结构' },
|
||||
{ name: 'CSS 解析', desc: '把 CSS 变成样式规则', detail: '选择器 + 属性 → 样式规则表' },
|
||||
{ name: '渲染树', desc: 'DOM + CSS = 渲染树', detail: '哪些节点显示、什么样式' },
|
||||
{ name: '布局计算', desc: '计算每个元素的位置', detail: '宽高、坐标、层级' },
|
||||
{ name: '绘制', desc: '把内容画到像素缓冲区', detail: '文字、颜色、图片、边框' },
|
||||
{ name: '合成', desc: '多层合成一张图', detail: 'GPU 合成,显示到屏幕' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.rendering-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.pipeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.pipeline-stage {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.6rem;
|
||||
opacity: 0.4;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.pipeline-stage.active {
|
||||
opacity: 1;
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.stage-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.stage-num {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.6rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.pipeline-stage.active .stage-num {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.stage-name {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.stage-desc {
|
||||
font-size: 0.68rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.stage-detail {
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-brand);
|
||||
margin-top: 0.3rem;
|
||||
padding: 0.25rem 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div class="url-demo">
|
||||
<div class="demo-label">URL 访问流程 ── 点击逐步演示</div>
|
||||
|
||||
<div class="flow">
|
||||
<div
|
||||
v-for="(step, index) in steps"
|
||||
:key="step.name"
|
||||
class="flow-step"
|
||||
:class="{ active: currentStep >= index }"
|
||||
@click="currentStep = index"
|
||||
>
|
||||
<div class="step-num">{{ index + 1 }}</div>
|
||||
<div class="step-content">
|
||||
<div class="step-name">{{ step.name }}</div>
|
||||
<div class="step-desc">{{ step.desc }}</div>
|
||||
<div v-if="currentStep >= index && step.detail" class="step-detail">
|
||||
{{ step.detail }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tap-hint">👆 点击查看各步骤详情</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const currentStep = ref(0)
|
||||
const steps = [
|
||||
{ name: 'URL 解析', desc: '提取协议、域名、路径', detail: 'https://www.example.com → 协议:https, 域名:www.example.com' },
|
||||
{ name: 'DNS 解析', desc: '域名转换为 IP 地址', detail: 'www.example.com → 93.184.216.34' },
|
||||
{ name: 'TCP 连接', desc: '建立与服务器的连接', detail: '三次握手完成' },
|
||||
{ name: 'TLS 握手', desc: '建立加密通道(HTTPS)', detail: '交换密钥,验证证书' },
|
||||
{ name: '发送请求', desc: '发送 HTTP 请求', detail: 'GET /index.html HTTP/1.1' },
|
||||
{ name: '服务器处理', desc: '后端处理请求', detail: '查询数据库,返回 HTML' },
|
||||
{ name: '返回响应', desc: '接收服务器响应', detail: 'HTTP/1.1 200 OK, Content-Type: text/html' },
|
||||
{ name: '浏览器渲染', desc: '解析并显示页面', detail: '构建 DOM 树,计算样式,绘制页面' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.url-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.2rem;
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.demo-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.flow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.flow-step {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
padding: 0.4rem;
|
||||
border-radius: 6px;
|
||||
opacity: 0.4;
|
||||
transition: all 0.3s;
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.flow-step.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.step-num {
|
||||
width: 1.3rem;
|
||||
height: 1.3rem;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.flow-step.active .step-num {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.step-name {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.step-desc {
|
||||
font-size: 0.68rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.step-detail {
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-brand);
|
||||
margin-top: 0.3rem;
|
||||
padding: 0.3rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.tap-hint {
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user