feat: add 30 interactive components for computer fundamentals section

Added comprehensive interactive demos covering:
- Operating systems (2): OS overview, process/memory/filesystem
- Data encoding (2): data lifecycle, encoding/storage/transmission
- Network basics (5): overview, physical/data-link/transport/application layers
- Data structures (5): overview, linear structures, hash table, tree, selector
- Algorithms (4): overview, recursion, greedy thinking, paradigms
- Programming languages (5): evolution, paradigms, scenarios, comparison, type models
- Compilers (2): analogy, practice demo
- Additional (5): search/sort algorithms, network principles, encoding basics, storage hierarchy, graph structures

Also updated component registration in theme index.js and fixed minor formatting issues in related docs.
This commit is contained in:
sanbuphy
2026-02-20 21:59:52 +08:00
parent 0e8618f902
commit ec9d52033f
39 changed files with 13733 additions and 43 deletions
@@ -0,0 +1,514 @@
<template>
<div class="algorithm-overview-demo">
<div class="demo-header">
<span class="icon">🧮</span>
<span class="title">算法思维入门</span>
<span class="subtitle">解决问题的一套步骤和方法</span>
</div>
<div class="analogy-box">
<div class="analogy-content">
<div class="analogy-icon">📖</div>
<div class="analogy-text">
<strong>算法就像菜谱</strong><br>
食材 = 数据<br>
烹饪步骤 = 算法<br>
美味菜肴 = 结果
</div>
</div>
</div>
<div class="algorithm-categories">
<div class="category-title">常见算法类型</div>
<div class="category-grid">
<div
v-for="category in categories"
:key="category.id"
:class="['category-card', { active: activeCategory === category.id }]"
@click="activeCategory = category.id"
>
<div class="card-icon">{{ category.icon }}</div>
<div class="card-name">{{ category.name }}</div>
<div class="card-desc">{{ category.desc }}</div>
</div>
</div>
</div>
<!-- 算法详解 -->
<div v-if="activeCategory" class="algorithm-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentCategory.icon }}</span>
<span class="detail-title">{{ currentCategory.name }}</span>
</div>
<div class="detail-content">
<div class="detail-section">
<div class="section-title">核心思想</div>
<div class="section-text">{{ currentCategory.idea }}</div>
</div>
<div class="detail-section">
<div class="section-title">生活类比</div>
<div class="analogy-card">
<div class="analogy-scenario">{{ currentCategory.analogy.scenario }}</div>
<div class="analogy-explanation">{{ currentCategory.analogy.explanation }}</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">时间复杂度</div>
<div class="complexity-display">
<div class="complexity-bigO">{{ currentCategory.complexity }}</div>
<div class="complexity-desc">{{ currentCategory.complexityDesc }}</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">典型应用</div>
<div class="app-list">
<div
v-for="(app, index) in currentCategory.applications"
:key="index"
class="app-tag"
>
{{ app }}
</div>
</div>
</div>
</div>
</div>
<!-- 复杂度对比 -->
<div class="complexity-comparison">
<div class="comparison-title">常见算法复杂度对比</div>
<div class="comparison-chart">
<div
v-for="(item, index) in complexityChart"
:key="index"
class="chart-item"
>
<div class="chart-label">{{ item.name }}</div>
<div class="chart-bar-container">
<div
class="chart-bar"
:style="{ width: item.width, backgroundColor: item.color }"
></div>
</div>
<div class="chart-value">{{ item.complexity }}</div>
</div>
</div>
</div>
<!-- 学习建议 -->
<div class="learning-tips">
<div class="tips-title">算法学习建议</div>
<div class="tips-grid">
<div class="tip-card">
<div class="tip-icon">📚</div>
<div class="tip-title">理解优先</div>
<div class="tip-desc">先理解算法思想再关注代码实现</div>
</div>
<div class="tip-card">
<div class="tip-icon"></div>
<div class="tip-title">动手实践</div>
<div class="tip-desc">自己实现一遍加深理解</div>
</div>
<div class="tip-card">
<div class="tip-icon">🔄</div>
<div class="tip-title">多次练习</div>
<div class="tip-desc">不同场景反复应用同一算法</div>
</div>
<div class="tip-card">
<div class="tip-icon"></div>
<div class="tip-title">分析优化</div>
<div class="tip-desc">思考时间和空间复杂度寻找优化方案</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeCategory = ref('search')
const categories = [
{
id: 'search',
name: '查找算法',
icon: '🔍',
desc: '在一堆数据中找到目标',
idea: '从数据集合中找到特定元素的过程',
analogy: {
scenario: '在字典里查单词',
explanation: '顺序查找 = 从第一页翻到最后一页;二分查找 = 直接翻到中间,判断在前半还是后半'
},
complexity: 'O(log n)',
complexityDesc: '二分查找非常快,每次排除一半数据',
applications: ['搜索引擎', '数据库查询', '自动补全']
},
{
id: 'sort',
name: '排序算法',
icon: '📊',
desc: '把数据按顺序排列',
idea: '将无序数据重新排列成有序序列',
analogy: {
scenario: '整理扑克牌',
explanation: '插入排序 = 每次拿一张牌插到正确的位置;快速排序 = 把牌分成大小两堆,递归整理'
},
complexity: 'O(n log n)',
complexityDesc: '快速排序、归并排序是最高效的通用排序算法',
applications: ['排行榜', '文件排序', '数据可视化']
},
{
id: 'recursive',
name: '递归算法',
icon: '🔄',
desc: '自己调用自己',
idea: '将大问题分解为相同类型的小问题',
analogy: {
scenario: '俄罗斯套娃',
explanation: '打开一个大娃娃,里面有个小一点的娃娃,再打开还有更小的...直到最小的一个'
},
complexity: 'O(log n) 到 O(2ⁿ)',
complexityDesc: '取决于问题类型,二分查找递归很快,斐波那契递归较慢',
applications: ['树遍历', '分治算法', '动态规划']
},
{
id: 'greedy',
name: '贪心算法',
icon: '🎯',
desc: '每步都选当前最优',
idea: '在每一步选择中都采取当前状态下最优的选择',
analogy: {
scenario: '找零钱',
explanation: '找 37 元零钱:先拿一张 20(最大可能),再拿 10、5、1、1,每次都选最大的面值'
},
complexity: 'O(n) 或 O(n log n)',
complexityDesc: '通常很快,但可能得不到全局最优解',
applications: ['最短路径', '背包问题', '任务调度']
},
{
id: 'dynamic',
name: '动态规划',
icon: '📈',
desc: '保存中间结果避免重复',
idea: '将复杂问题分解为子问题,保存子问题的解',
analogy: {
scenario: '爬楼梯',
explanation: '要爬到第 n 级,可以从 n-1 级跨 1 步,或从 n-2 级跨 2 步,记住之前的结果避免重复计算'
},
complexity: 'O(n²) 或 O(n³)',
complexityDesc: '用空间换时间,比递归快很多',
applications: ['最短路径', '背包问题', '字符串匹配']
}
]
const complexityChart = [
{ name: '二分查找', complexity: 'O(log n)', width: '10%', color: '#10b981' },
{ name: '快速排序', complexity: 'O(n log n)', width: '25%', color: '#3b82f6' },
{ name: '插入排序', complexity: 'O(n²)', width: '50%', color: '#f59e0b' },
{ name: '暴力递归', complexity: 'O(2ⁿ)', width: '100%', color: '#ef4444' }
]
const currentCategory = computed(() => categories.find(c => c.id === activeCategory.value))
</script>
<style scoped>
.algorithm-overview-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.analogy-box {
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.analogy-content {
display: flex;
gap: 1.5rem;
align-items: center;
}
.analogy-icon {
font-size: 3rem;
flex-shrink: 0;
}
.analogy-text {
font-size: 1rem;
line-height: 1.8;
}
.algorithm-categories {
margin-bottom: 2rem;
}
.category-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.category-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
}
.category-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.category-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.category-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.card-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.algorithm-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.detail-section {}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.section-text {
font-size: 0.9rem;
line-height: 1.6;
}
.analogy-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.analogy-scenario {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.analogy-explanation {
font-size: 0.85rem;
line-height: 1.6;
color: var(--vp-c-text-1);
}
.complexity-display {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.complexity-bigO {
font-family: 'Courier New', monospace;
font-size: 1.5rem;
font-weight: 700;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.complexity-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.app-list {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.app-tag {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 20px;
font-size: 0.85rem;
}
.complexity-comparison {
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-chart {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.chart-item {
display: grid;
grid-template-columns: 100px 1fr 80px;
gap: 1rem;
align-items: center;
margin-bottom: 1rem;
}
.chart-item:last-child {
margin-bottom: 0;
}
.chart-label {
font-size: 0.85rem;
font-weight: 600;
}
.chart-bar-container {
background: var(--vp-c-bg-soft);
border-radius: 4px;
height: 24px;
overflow: hidden;
}
.chart-bar {
height: 100%;
transition: width 0.5s ease-out;
border-radius: 4px;
}
.chart-value {
font-family: 'Courier New', monospace;
font-size: 0.85rem;
font-weight: 600;
color: var(--vp-c-brand);
}
.learning-tips {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.tips-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.tips-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.tip-card {
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.tip-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.tip-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.tip-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
</style>
@@ -0,0 +1,490 @@
<template>
<div class="algorithm-paradigm-demo">
<div class="demo-header">
<span class="icon">🔧</span>
<span class="title">算法设计范式</span>
<span class="subtitle">解决问题的常用套路</span>
</div>
<div class="intro-text">
算法设计范式是解决问题的<strong>通用策略</strong>掌握这些套路可以快速找到解题思路
</div>
<div class="paradigm-grid">
<div
v-for="paradigm in paradigms"
:key="paradigm.id"
:class="['paradigm-card', { active: activeParadigm === paradigm.id }]"
@click="activeParadigm = paradigm.id"
>
<div class="card-icon">{{ paradigm.icon }}</div>
<div class="card-name">{{ paradigm.name }}</div>
<div class="card-tagline">{{ paradigm.tagline }}</div>
</div>
</div>
<!-- 详细说明 -->
<div v-if="activeParadigm" class="paradigm-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentParadigm.icon }}</span>
<span class="detail-title">{{ currentParadigm.name }}</span>
</div>
<div class="detail-content">
<div class="detail-section">
<div class="section-title">核心思想</div>
<div class="section-text">{{ currentParadigm.idea }}</div>
</div>
<div class="detail-section">
<div class="section-title">适用场景</div>
<div class="scenario-tags">
<span
v-for="(scenario, index) in currentParadigm.scenarios"
:key="index"
class="scenario-tag"
>
{{ scenario }}
</span>
</div>
</div>
<div class="detail-section">
<div class="section-title">经典问题</div>
<div class="problems-list">
<div
v-for="(problem, index) in currentParadigm.problems"
:key="index"
class="problem-item"
>
<div class="problem-icon">📝</div>
<div class="problem-text">{{ problem }}</div>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">时间复杂度</div>
<div class="complexity-box">
<div class="complexity-value">{{ currentParadigm.complexity }}</div>
<div class="complexity-note">{{ currentParadigm.complexityNote }}</div>
</div>
</div>
</div>
</div>
<!-- 对比总结 -->
<div class="paradigm-comparison">
<div class="comparison-title">范式对比总结</div>
<table class="comparison-table">
<thead>
<tr>
<th>范式</th>
<th>核心策略</th>
<th>最优性</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in comparisonData"
:key="index"
:class="{ highlighted: item.id === activeParadigm }"
>
<td>{{ item.icon }} {{ item.name }}</td>
<td>{{ item.strategy }}</td>
<td>{{ item.optimal }}</td>
<td>{{ item.use }}</td>
</tr>
</tbody>
</table>
</div>
<!-- 选择建议 -->
<div class="selection-guide">
<div class="guide-title">如何选择合适的范式</div>
<div class="guide-steps">
<div class="guide-step">
<div class="step-number">1</div>
<div class="step-content">
<div class="step-title">分析问题特征</div>
<div class="step-desc">是否有重叠子问题是否有最优子结构</div>
</div>
</div>
<div class="guide-step">
<div class="step-number">2</div>
<div class="step-content">
<div class="step-title">判断是否需要最优解</div>
<div class="step-desc">贪心不一定最优动态规划保证最优</div>
</div>
</div>
<div class="guide-step">
<div class="step-number">3</div>
<div class="step-content">
<div class="step-title">考虑数据规模</div>
<div class="step-desc">回溯适合小规模分治适合大规模</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeParadigm = ref('divide')
const paradigms = [
{
id: 'divide',
name: '分治法',
icon: '✂️',
tagline: '分而治之',
idea: '将大问题分解成多个小问题,递归解决小问题,最后合并结果',
scenarios: ['数组排序', '矩阵乘法', '大整数运算'],
problems: ['归并排序', '快速排序', '二分查找', 'Strassen 矩阵乘法'],
complexity: 'O(n log n)',
complexityNote: '通常比暴力法快很多'
},
{
id: 'dynamic',
name: '动态规划',
icon: '📊',
tagline: '保存结果避免重复',
idea: '将问题分解为重叠子问题,保存子问题的解,避免重复计算',
scenarios: ['最优解问题', '计数问题', '路径问题'],
problems: ['斐波那契数列', '背包问题', '最长公共子序列', '最短路径'],
complexity: 'O(n²) 或 O(n³)',
complexityNote: '用空间换时间,比递归快'
},
{
id: 'greedy',
name: '贪心法',
icon: '🎯',
tagline: '局部最优',
idea: '在每一步选择中都采取当前状态下最优的选择,希望达到全局最优',
scenarios: ['优化问题', '调度问题', '图问题'],
problems: ['找零钱', '活动选择', 'Huffman 编码', '最小生成树'],
complexity: 'O(n log n)',
complexityNote: '最快,但不一定最优'
},
{
id: 'backtrack',
name: '回溯法',
icon: '🔙',
tagline: '试错法',
idea: '系统性地搜索解空间,遇到死路就回退到上一个分岔口',
scenarios: ['组合问题', '排列问题', '约束满足'],
problems: ['N 皇后问题', '数独', '全排列', '子集问题'],
complexity: 'O(2ⁿ) 或 O(n!)',
complexityNote: '指数级,适合小规模'
}
]
const comparisonData = [
{
id: 'divide',
name: '分治法',
icon: '✂️',
strategy: '分解 → 递归 → 合并',
optimal: '保证最优',
use: '问题可独立分解'
},
{
id: 'dynamic',
name: '动态规划',
icon: '📊',
strategy: '保存子问题解',
optimal: '保证最优',
use: '有重叠子问题'
},
{
id: 'greedy',
name: '贪心法',
icon: '🎯',
strategy: '每次选最优',
optimal: '不一定最优',
use: '局部最优 → 全局最优'
},
{
id: 'backtrack',
name: '回溯法',
icon: '🔙',
strategy: '深度优先搜索',
optimal: '保证最优',
use: '解空间小,需要穷举'
}
]
const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadigm.value))
</script>
<style scoped>
.algorithm-paradigm-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.intro-text {
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
margin-bottom: 2rem;
font-size: 0.95rem;
line-height: 1.6;
}
.paradigm-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.paradigm-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.paradigm-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.paradigm-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.card-name {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.5rem;
}
.card-tagline {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.paradigm-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.detail-section {}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.section-text {
font-size: 0.9rem;
line-height: 1.6;
}
.scenario-tags {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.scenario-tag {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 20px;
font-size: 0.85rem;
}
.problems-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.75rem;
}
.problem-item {
display: flex;
gap: 0.5rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.problem-icon {
font-size: 1rem;
flex-shrink: 0;
}
.problem-text {
font-size: 0.85rem;
line-height: 1.5;
}
.complexity-box {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.complexity-value {
font-family: 'Courier New', monospace;
font-size: 1.3rem;
font-weight: 700;
color: var(--vp-c-brand);
margin-bottom: 0.35rem;
}
.complexity-note {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.paradigm-comparison {
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.comparison-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
font-size: 0.85rem;
}
tr.highlighted {
background: var(--vp-c-brand-soft);
}
.selection-guide {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.guide-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
color: var(--vp-c-brand);
}
.guide-steps {
display: flex;
flex-direction: column;
gap: 1rem;
}
.guide-step {
display: flex;
gap: 1rem;
align-items: start;
}
.step-number {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.9rem;
font-weight: 600;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.35rem;
}
.step-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.5;
}
</style>
@@ -0,0 +1,531 @@
<template>
<div class="application-layer-demo">
<div class="demo-header">
<span class="icon">🌍</span>
<span class="title">应用层为你服务的各种协议</span>
<span class="subtitle">HTTPDNSDHCP 等协议如何工作</span>
</div>
<div class="protocol-gallery">
<div
v-for="protocol in protocols"
:key="protocol.id"
:class="['protocol-card', { active: activeProtocol === protocol.id }]"
@click="activeProtocol = protocol.id"
>
<div class="card-icon">{{ protocol.icon }}</div>
<div class="card-name">{{ protocol.name }}</div>
<div class="card-desc">{{ protocol.desc }}</div>
</div>
</div>
<!-- 协议详情 -->
<div class="protocol-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentProtocol.icon }}</span>
<span class="detail-title">{{ currentProtocol.name }} 协议</span>
</div>
<div class="detail-content">
<div class="detail-section">
<div class="section-title">作用</div>
<div class="section-text">{{ currentProtocol.purpose }}</div>
</div>
<div class="detail-section">
<div class="section-title">工作原理</div>
<div class="section-steps">
<div v-for="(step, index) in currentProtocol.steps" :key="index" class="step-item">
<span class="step-num">{{ index + 1 }}</span>
<span class="step-text">{{ step }}</span>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">日常应用</div>
<div class="app-list">
<div v-for="(app, index) in currentProtocol.apps" :key="index" class="app-tag">
{{ app.icon }} {{ app.name }}
</div>
</div>
</div>
</div>
</div>
<!-- HTTP 请求响应示例 -->
<div v-if="activeProtocol === 'http'" class="http-example">
<div class="example-title">HTTP 请求/响应示例</div>
<div class="example-content">
<div class="request-response">
<div class="request-box">
<div class="box-header">📤 请求 (Request)</div>
<div class="box-body">
<div class="line method">GET /index.html HTTP/1.1</div>
<div class="line header">Host: www.example.com</div>
<div class="line header">User-Agent: Mozilla/5.0</div>
<div class="line header">Accept: text/html</div>
</div>
</div>
<div class="arrow"></div>
<div class="response-box">
<div class="box-header">📥 响应 (Response)</div>
<div class="box-body">
<div class="line status">HTTP/1.1 200 OK</div>
<div class="line header">Content-Type: text/html</div>
<div class="line header">Content-Length: 1234</div>
<div class="line empty"></div>
<div class="line body">&lt;html&gt;...&lt;/html&gt;</div>
</div>
</div>
</div>
</div>
</div>
<!-- DNS 查询示例 -->
<div v-if="activeProtocol === 'dns'" class="dns-example">
<div class="example-title">DNS 查询过程</div>
<div class="dns-flow">
<div class="flow-step">
<div class="step-icon">💻</div>
<div class="step-text">用户输入 www.example.com</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="step-icon">🔍</div>
<div class="step-text">DNS 服务器查询</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="step-icon">📍</div>
<div class="step-text">返回 IP: 93.184.216.34</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeProtocol = ref('http')
const protocols = [
{
id: 'http',
name: 'HTTP',
icon: '🌐',
desc: '网页浏览的基础'
},
{
id: 'https',
name: 'HTTPS',
icon: '🔐',
desc: '加密的安全连接'
},
{
id: 'dns',
name: 'DNS',
icon: '🔍',
desc: '域名解析服务'
},
{
id: 'dhcp',
name: 'DHCP',
icon: '📡',
desc: '自动分配 IP 地址'
},
{
id: 'smtp',
name: 'SMTP',
icon: '📧',
desc: '发送邮件'
},
{
id: 'ftp',
name: 'FTP',
icon: '📁',
desc: '文件传输'
}
]
const protocolDetails = {
http: {
name: 'HTTP',
icon: '🌐',
purpose: '超文本传输协议,用于在浏览器和服务器之间传输网页数据',
steps: [
'浏览器发起 HTTP 请求',
'服务器接收并处理请求',
'服务器返回 HTTP 响应',
'浏览器解析并显示网页'
],
apps: [
{ icon: '🌍', name: '网页浏览' },
{ icon: '📱', name: '移动应用 API' },
{ icon: '🔌', name: 'RESTful 服务' }
]
},
https: {
name: 'HTTPS',
icon: '🔐',
purpose: 'HTTP Secure,在 HTTP 基础上加入 SSL/TLS 加密层',
steps: [
'客户端请求 HTTPS 连接',
'服务器发送数字证书',
'客户端验证证书并生成会话密钥',
'使用加密通道传输数据'
],
apps: [
{ icon: '🏦', name: '网上银行' },
{ icon: '🛒', name: '在线支付' },
{ icon: '🔑', name: '登录认证' }
]
},
dns: {
name: 'DNS',
icon: '🔍',
purpose: '域名系统,将人类可读的域名转换为机器可读的 IP 地址',
steps: [
'用户输入域名',
'查询本地 DNS 缓存',
'若缓存未命中,查询 DNS 服务器',
'返回对应的 IP 地址'
],
apps: [
{ icon: '🌐', name: '网址访问' },
{ icon: '📧', name: '邮件服务器' },
{ icon: '🎮', name: '游戏连接' }
]
},
dhcp: {
name: 'DHCP',
icon: '📡',
purpose: '动态主机配置协议,自动为设备分配 IP 地址和网络配置',
steps: [
'设备发送 DHCP Discover',
'DHCP 服务器发送 Offer',
'设备发送 Request',
'服务器发送 ACK,完成分配'
],
apps: [
{ icon: '📱', name: '手机连 WiFi' },
{ icon: '💻', name: '电脑入网' },
{ icon: '🏠', name: '家庭网络' }
]
},
smtp: {
name: 'SMTP',
icon: '📧',
purpose: '简单邮件传输协议,用于发送电子邮件',
steps: [
'邮件客户端连接 SMTP 服务器',
'验证发件人身份',
'传输邮件内容和附件',
'服务器将邮件投递到收件人服务器'
],
apps: [
{ icon: '📬', name: '邮件发送' },
{ icon: '🔔', name: '邮件通知' },
{ icon: '📋', name: '邮件列表' }
]
},
ftp: {
name: 'FTP',
icon: '📁',
purpose: '文件传输协议,用于在网络上进行文件传输',
steps: [
'客户端建立 FTP 控制连接',
'用户认证(用户名密码)',
'建立数据连接传输文件',
'传输完成后关闭连接'
],
apps: [
{ icon: '⬆️', name: '文件上传' },
{ icon: '⬇️', name: '文件下载' },
{ icon: '📂', name: '文件管理' }
]
}
}
const currentProtocol = computed(() => protocolDetails[activeProtocol.value])
</script>
<style scoped>
.application-layer-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.protocol-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.protocol-card {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
}
.protocol-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.protocol-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
.card-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.35rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.protocol-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.detail-section {
}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.section-text {
font-size: 0.9rem;
line-height: 1.6;
color: var(--vp-c-text-1);
}
.section-steps {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.step-item {
display: flex;
gap: 0.75rem;
align-items: start;
}
.step-num {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
flex-shrink: 0;
}
.step-text {
font-size: 0.85rem;
line-height: 1.5;
padding-top: 0.15rem;
}
.app-list {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.app-tag {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 20px;
font-size: 0.85rem;
}
.http-example,
.dns-example {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.example-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.request-response {
display: flex;
align-items: stretch;
gap: 1rem;
}
.request-box,
.response-box {
flex: 1;
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
overflow: hidden;
}
.box-header {
background: var(--vp-c-brand);
color: white;
padding: 0.5rem;
font-size: 0.85rem;
font-weight: 600;
text-align: center;
}
.box-body {
padding: 0.75rem;
background: var(--vp-c-bg-soft);
font-family: 'Courier New', monospace;
font-size: 0.75rem;
line-height: 1.6;
}
.line {
padding: 0.25rem 0;
}
.line.method {
color: var(--vp-c-brand);
font-weight: 600;
}
.line.status {
color: #10b981;
font-weight: 600;
}
.line.header {
color: var(--vp-c-text-2);
}
.line.body {
color: var(--vp-c-text-1);
}
.arrow {
display: flex;
align-items: center;
font-size: 2rem;
color: var(--vp-c-brand);
}
.dns-flow {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
flex-wrap: wrap;
}
.flow-step {
flex: 1;
min-width: 150px;
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.step-icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
.step-text {
font-size: 0.85rem;
color: var(--vp-c-text-1);
}
.flow-arrow {
font-size: 1.5rem;
color: var(--vp-c-brand);
}
@media (max-width: 768px) {
.request-response {
flex-direction: column;
}
.arrow {
transform: rotate(90deg);
}
}
</style>
@@ -0,0 +1,327 @@
<template>
<div class="compilation-practice-demo">
<div class="demo-header">
<span class="icon"></span>
<span class="title">编译过程实践</span>
<span class="subtitle">从代码到可执行文件</span>
</div>
<div class="code-input">
<div class="input-title">输入代码</div>
<textarea
v-model="sourceCode"
class="code-textarea"
placeholder="输入 C 语言代码..."
></textarea>
</div>
<div class="compilation-steps">
<div class="steps-title">编译步骤</div>
<div class="steps-flow">
<div
v-for="(step, index) in steps"
:key="index"
class="step-item"
>
<div class="step-number">{{ index + 1 }}</div>
<div class="step-content">
<div class="step-name">{{ step.name }}</div>
<div class="step-command">{{ step.command }}</div>
<div class="step-output">{{ step.output }}</div>
</div>
</div>
</div>
</div>
<div class="file-outputs">
<div class="outputs-title">生成的文件</div>
<div class="file-list">
<div
v-for="file in outputFiles"
:key="file.name"
class="file-item"
>
<div class="file-icon">{{ file.icon }}</div>
<div class="file-info">
<div class="file-name">{{ file.name }}</div>
<div class="file-desc">{{ file.desc }}</div>
</div>
</div>
</div>
</div>
<div class="tools">
<div class="tools-title">常用编译工具</div>
<div class="tools-grid">
<div class="tool-card">
<div class="tool-name">GCC</div>
<div class="tool-desc">GNU Compiler Collection</div>
</div>
<div class="tool-card">
<div class="tool-name">Clang</div>
<div class="tool-desc">LLVM C/C++ 编译器</div>
</div>
<div class="tool-card">
<div class="tool-name">MSVC</div>
<div class="tool-desc">Microsoft Visual C++</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const sourceCode = ref(`#include <stdio.h>
int main() {
printf("Hello, World!\\n");
return 0;
}`)
const steps = [
{
name: '预处理',
command: 'gcc -E hello.c -o hello.i',
output: '处理 #include,展开宏定义'
},
{
name: '编译',
command: 'gcc -S hello.i -o hello.s',
output: '生成汇编代码'
},
{
name: '汇编',
command: 'gcc -c hello.s -o hello.o',
output: '生成目标文件'
},
{
name: '链接',
command: 'gcc hello.o -o hello',
output: '生成可执行文件'
}
]
const outputFiles = [
{
name: 'hello.c',
icon: '📄',
desc: '源代码文件'
},
{
name: 'hello.i',
icon: '📝',
desc: '预处理后的文件'
},
{
name: 'hello.s',
icon: '⚙️',
desc: '汇编代码文件'
},
{
name: 'hello.o',
icon: '📦',
desc: '目标文件'
},
{
name: 'hello',
icon: '🚀',
desc: '可执行文件'
}
]
</script>
<style scoped>
.compilation-practice-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.code-input {
margin-bottom: 2rem;
}
.input-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.code-textarea {
width: 100%;
min-height: 150px;
padding: 1rem;
background: #1e1e1e;
color: #d4d4d4;
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.6;
resize: vertical;
}
.compilation-steps {
margin-bottom: 2rem;
}
.steps-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.steps-flow {
display: flex;
flex-direction: column;
gap: 1rem;
}
.step-item {
display: flex;
gap: 1rem;
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.step-number {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.9rem;
font-weight: 600;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.step-command {
font-family: 'Courier New', monospace;
font-size: 0.8rem;
color: var(--vp-c-brand);
margin-bottom: 0.35rem;
}
.step-output {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.file-outputs {
margin-bottom: 2rem;
}
.outputs-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.file-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.file-item {
display: flex;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.file-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.file-info {
flex: 1;
}
.file-name {
font-family: 'Courier New', monospace;
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.file-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.tools {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.tools-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.tools-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.tool-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
text-align: center;
}
.tool-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.tool-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
</style>
@@ -0,0 +1,529 @@
<template>
<div class="compiler-analogy-demo">
<div class="demo-header">
<span class="icon">🌐</span>
<span class="title">编译原理翻译的艺术</span>
<span class="subtitle">如何把代码翻译成机器指令</span>
</div>
<div class="analogy-intro">
<div class="analogy-box">
<div class="analogy-text">
编译器就像<strong>翻译官</strong>把人类能懂的代码翻译成机器能懂的指令
</div>
</div>
</div>
<!-- 翻译过程 -->
<div class="translation-process">
<div class="process-title">代码翻译的完整流程</div>
<div class="process-flow">
<div
v-for="(step, index) in translationSteps"
:key="index"
class="process-step"
>
<div class="step-number">{{ index + 1 }}</div>
<div class="step-content">
<div class="step-name">{{ step.name }}</div>
<div class="step-desc">{{ step.desc }}</div>
<div class="step-example">{{ step.example }}</div>
</div>
<div v-if="index < translationSteps.length - 1" class="step-arrow"></div>
</div>
</div>
</div>
<!-- 词法分析 -->
<div class="analyzer-section">
<div class="analyzer-title">词法分析分词</div>
<div class="lexical-demo">
<div class="source-code">
<code>int age = 25;</code>
</div>
<div class="token-arrow"></div>
<div class="tokens-list">
<div
v-for="(token, index) in tokens"
:key="index"
class="token-item"
>
<span class="token-type">{{ token.type }}</span>
<span class="token-value">{{ token.value }}</span>
</div>
</div>
</div>
</div>
<!-- 语法分析 -->
<div class="analyzer-section">
<div class="analyzer-title">语法分析构建树</div>
<div class="syntax-demo">
<div class="syntax-tree">
<div class="tree-node root">
<span class="node-label">赋值语句</span>
<div class="node-children">
<div class="tree-node">
<span class="node-label">变量</span>
<span class="node-value">age</span>
</div>
<div class="tree-node">
<span class="node-label">运算符</span>
<span class="node-value">=</span>
</div>
<div class="tree-node">
<span class="node-label">数字</span>
<span class="node-value">25</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 编译 vs 解释 -->
<div class="comparison">
<div class="comparison-title">编译 vs 解释</div>
<div class="comparison-box">
<div class="compare-side compile">
<div class="side-header">编译型语言</div>
<div class="side-content">
<div class="side-step">源代码 编译器 机器码</div>
<div class="side-example">C, Go, Rust</div>
<div class="side-features">
<div class="feature"> 执行快</div>
<div class="feature"> 一次编译多次运行</div>
<div class="feature"> 编译慢</div>
</div>
</div>
</div>
<div class="compare-side interpret">
<div class="side-header">解释型语言</div>
<div class="side-content">
<div class="side-step">源代码 解释器 逐行执行</div>
<div class="side-example">Python, JavaScript, PHP</div>
<div class="side-features">
<div class="feature"> 开发快</div>
<div class="feature"> 跨平台</div>
<div class="feature"> 执行慢</div>
</div>
</div>
</div>
</div>
</div>
<!-- 优化 -->
<div class="optimization">
<div class="optimization-title">编译器优化</div>
<div class="optimization-content">
<div class="opt-examples">
<div class="opt-item">
<div class="opt-before">优化前</div>
<div class="opt-code">x = 5 + 3 + 2</div>
</div>
<div class="opt-arrow"></div>
<div class="opt-item">
<div class="opt-after">优化后</div>
<div class="opt-code">x = 10</div>
</div>
</div>
<div class="opt-note">
编译器会自动优化代码提高运行效率
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const translationSteps = [
{
name: '词法分析',
desc: '将代码分解成一个个单词(token)',
example: 'int age = 25 → [int, age, =, 25]'
},
{
name: '语法分析',
desc: '检查代码是否符合语法规则,构建语法树',
example: '验证语句结构是否正确'
},
{
name: '语义分析',
desc: '检查代码的含义是否合理',
example: '检查变量是否定义、类型是否匹配'
},
{
name: '中间代码生成',
desc: '生成与机器无关的中间表示',
example: '生成字节码或中间表示'
},
{
name: '优化',
desc: '改进代码,提高执行效率',
example: '常量折叠、死代码消除'
},
{
name: '目标代码生成',
desc: '生成机器码或目标代码',
example: '生成 x86、ARM 等机器指令'
}
]
const tokens = [
{ type: '关键字', value: 'int' },
{ type: '标识符', value: 'age' },
{ type: '运算符', value: '=' },
{ type: '数字', value: '25' },
{ type: '分隔符', value: ';' }
]
</script>
<style scoped>
.compiler-analogy-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.analogy-intro {
margin-bottom: 2rem;
}
.analogy-box {
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
}
.analogy-text {
font-size: 0.95rem;
line-height: 1.6;
}
.translation-process {
margin-bottom: 2rem;
}
.process-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
text-align: center;
color: var(--vp-c-brand);
}
.process-flow {
display: flex;
flex-direction: column;
gap: 1rem;
}
.process-step {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
}
.step-number {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.9rem;
font-weight: 600;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.35rem;
color: var(--vp-c-brand);
}
.step-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.step-example {
font-family: 'Courier New', monospace;
font-size: 0.8rem;
color: var(--vp-c-text-1);
background: var(--vp-c-bg-soft);
padding: 0.5rem;
border-radius: 4px;
}
.step-arrow {
font-size: 1.5rem;
color: var(--vp-c-brand);
flex-shrink: 0;
}
.analyzer-section {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.analyzer-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
color: var(--vp-c-brand);
}
.lexical-demo {
text-align: center;
}
.source-code {
padding: 1rem;
background: #1e1e1e;
border-radius: 6px;
margin-bottom: 1rem;
}
.source-code code {
color: #d4d4d4;
font-size: 1rem;
}
.token-arrow {
font-size: 1.5rem;
color: var(--vp-c-brand);
margin-bottom: 1rem;
}
.tokens-list {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
}
.token-item {
display: flex;
flex-direction: column;
gap: 0.35rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
min-width: 100px;
}
.token-type {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.token-value {
font-family: 'Courier New', monospace;
font-size: 0.9rem;
font-weight: 600;
color: var(--vp-c-brand);
}
.syntax-demo {
display: flex;
justify-content: center;
}
.syntax-tree {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.tree-node {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.tree-node.root {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
}
.node-label {
font-size: 0.85rem;
font-weight: 600;
}
.node-value {
font-family: 'Courier New', monospace;
font-size: 0.8rem;
color: var(--vp-c-brand);
}
.node-children {
display: flex;
gap: 0.5rem;
margin-left: 1rem;
}
.comparison {
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-box {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
@media (max-width: 768px) {
.comparison-box {
grid-template-columns: 1fr;
}
}
.compare-side {
padding: 1.5rem;
border-radius: 8px;
}
.side-header {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
text-align: center;
}
.compile .side-header {
color: #10b981;
}
.interpret .side-header {
color: #3b82f6;
}
.side-step {
text-align: center;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.side-example {
text-align: center;
margin-bottom: 1rem;
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.side-features {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.feature {
font-size: 0.85rem;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 4px;
}
.optimization {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.optimization-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
color: var(--vp-c-brand);
}
.optimization-content {
text-align: center;
}
.opt-examples {
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
margin-bottom: 1rem;
}
.opt-item {
text-align: center;
}
.opt-before,
.opt-after {
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.opt-code {
font-family: 'Courier New', monospace;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
font-size: 0.9rem;
}
.opt-arrow {
font-size: 1.5rem;
}
.opt-note {
font-size: 0.85rem;
color: var(--vp-c-text-2);
font-style: italic;
}
</style>
@@ -0,0 +1,263 @@
<template>
<div class="data-encoding-basics-demo">
<div class="demo-header">
<span class="icon">🔤</span>
<span class="title">数据编码基础</span>
<span class="subtitle">信息如何被表示和存储</span>
</div>
<div class="encoding-intro">
计算机只能识别 <strong>0 1</strong>所有数据都需要转换成二进制
</div>
<div class="bit-byte">
<div class="bb-cards">
<div class="bb-card">
<div class="bb-title"> (Bit)</div>
<div class="bb-value">0 1</div>
<div class="bb-desc">最小数据单位</div>
</div>
<div class="bb-card">
<div class="bb-title">字节 (Byte)</div>
<div class="bb-value">8 </div>
<div class="bb-desc">常用存储单位</div>
</div>
</div>
</div>
<div class="encoding-examples">
<div class="example-title">不同数据的编码方式</div>
<div class="example-grid">
<div class="example-card">
<div class="card-icon">🔢</div>
<div class="card-title">数字</div>
<div class="card-encoding">
<div class="encoding-label">十进制</div>
<div class="encoding-value">25</div>
</div>
<div class="card-encoding">
<div class="encoding-label">二进制</div>
<div class="encoding-value">00011001</div>
</div>
</div>
<div class="example-card">
<div class="card-icon">🔤</div>
<div class="card-title">字符</div>
<div class="card-encoding">
<div class="encoding-label">字符</div>
<div class="encoding-value">A</div>
</div>
<div class="card-encoding">
<div class="encoding-label">ASCII</div>
<div class="encoding-value">01000001</div>
</div>
</div>
<div class="example-card">
<div class="card-icon">🎨</div>
<div class="card-title">颜色</div>
<div class="card-encoding">
<div class="encoding-label">RGB</div>
<div class="encoding-value">255,0,0</div>
</div>
<div class="card-encoding">
<div class="encoding-label">十六进制</div>
<div class="encoding-value">#FF0000</div>
</div>
</div>
</div>
</div>
<div class="encoding-standards">
<div class="standards-title">常见编码标准</div>
<table class="standards-table">
<thead>
<tr>
<th>编码</th>
<th>说明</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>ASCII</td>
<td>7 128 个字符</td>
<td>英文字符</td>
</tr>
<tr>
<td>Unicode</td>
<td>统一码全球字符</td>
<td>多语言文本</td>
</tr>
<tr>
<td>UTF-8</td>
<td>变长编码1-4 字节</td>
<td>网页文本</td>
</tr>
<tr>
<td>Base64</td>
<td>二进制转文本</td>
<td>邮件图片</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
</script>
<style scoped>
.data-encoding-basics-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.encoding-intro {
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
margin-bottom: 2rem;
font-size: 0.95rem;
line-height: 1.6;
}
.bit-byte {
margin-bottom: 2rem;
}
.bb-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.bb-card {
padding: 1.5rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
}
.bb-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.75rem;
}
.bb-value {
font-family: 'Courier New', monospace;
font-size: 1.2rem;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.bb-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.encoding-examples {
margin-bottom: 2rem;
}
.example-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
text-align: center;
color: var(--vp-c-brand);
}
.example-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.example-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.card-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 1rem;
}
.card-encoding {
margin-bottom: 0.75rem;
}
.encoding-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.encoding-value {
font-family: 'Courier New', monospace;
font-size: 0.9rem;
color: var(--vp-c-brand);
}
.encoding-standards {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.standards-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.standards-table {
width: 100%;
border-collapse: collapse;
}
.standards-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: left;
font-size: 0.85rem;
}
.standards-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
font-size: 0.85rem;
}
</style>
@@ -0,0 +1,401 @@
<template>
<div class="data-lifecycle-demo">
<div class="demo-header">
<span class="icon">🔄</span>
<span class="title">数据的生命周期</span>
<span class="subtitle">从输入到存储到传输到输出的全过程</span>
</div>
<div class="lifecycle-flow">
<div class="flow-stage" v-for="(stage, index) in stages" :key="stage.id">
<div class="stage-header" @click="activeStage = index">
<span class="stage-number">{{ index + 1 }}</span>
<span class="stage-name">{{ stage.name }}</span>
<span class="stage-icon">{{ stage.icon }}</span>
</div>
<Transition name="slide">
<div v-if="activeStage === index" class="stage-detail">
<div class="detail-content">
<h4>{{ stage.title }}</h4>
<p>{{ stage.description }}</p>
<div class="stage-example">
<div class="example-label">示例{{ stage.example.label }}</div>
<div class="example-content">
<div v-for="(item, i) in stage.example.items" :key="i" class="example-item">
<span class="item-label">{{ item.label }}:</span>
<span class="item-value">{{ item.value }}</span>
</div>
</div>
</div>
<div class="stage-encoding">
<div class="encoding-label">编码方式:</div>
<div class="encoding-value">{{ stage.encoding }}</div>
</div>
</div>
</div>
</Transition>
<div v-if="index < stages.length - 1" class="flow-arrow"></div>
</div>
</div>
<div class="lifecycle-summary">
<div class="summary-title">数据转换的关键点</div>
<div class="summary-grid">
<div v-for="(point, index) in keyPoints" :key="index" class="summary-card">
<div class="card-icon">{{ point.icon }}</div>
<div class="card-text">
<div class="card-title">{{ point.title }}</div>
<div class="card-desc">{{ point.desc }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeStage = ref(0)
const stages = [
{
id: 'input',
name: '数据输入',
icon: '⌨️',
title: '阶段 1:数据输入',
description: '用户通过各种输入设备(键盘、鼠标、触摸屏、麦克风等)将信息输入到计算机系统中。',
example: {
label: '用户输入文字',
items: [
{ label: '原始动作', value: '按下键盘 A 键' },
{ label: '硬件信号', value: '键盘扫描码' },
{ label: '操作系统', value: '键盘中断' }
]
},
encoding: 'ASCII: 01000001 (65)'
},
{
id: 'processing',
name: '数据处理',
icon: '🔄',
title: '阶段 2:数据处理',
description: 'CPU 对输入的数据进行计算、转换、格式化等操作,应用程序根据业务逻辑处理数据。',
example: {
label: '文本编辑器处理',
items: [
{ label: '应用程序', value: '接收字符 "A"' },
{ label: '内存存储', value: 'Unicode: U+0041' },
{ label: '显示准备', value: '字体渲染' }
]
},
encoding: 'UTF-8: 0x41 (单字节)'
},
{
id: 'storage',
name: '数据存储',
icon: '💾',
title: '阶段 3:数据存储',
description: '处理后的数据被保存到存储设备中(内存、硬盘、SSD、云存储等),以便后续使用。',
example: {
label: '保存文档',
items: [
{ label: '内存数据', value: '文本内容' },
{ label: '文件系统', value: '创建 .txt 文件' },
{ label: '磁盘写入', value: '二进制数据' }
]
},
encoding: '磁盘: 二进制位序列'
},
{
id: 'transmission',
name: '数据传输',
icon: '📡',
title: '阶段 4:数据传输',
description: '数据通过网络(局域网、互联网)或内部总线从一个位置传输到另一个位置。',
example: {
label: '上传文件',
items: [
{ label: '文件读取', value: '从磁盘加载' },
{ label: '网络封装', value: 'TCP/IP 数据包' },
{ label: '物理传输', value: '电信号/光信号' }
]
},
encoding: '网络: 数据包帧格式'
},
{
id: 'output',
name: '数据输出',
icon: '🖥️',
title: '阶段 5:数据输出',
description: '数据通过输出设备(显示器、打印机、扬声器等)呈现给用户,或传输给其他系统。',
example: {
label: '显示网页',
items: [
{ label: '浏览器接收', value: 'HTML 数据' },
{ label: '渲染引擎', value: '解析样式、布局' },
{ label: '屏幕显示', value: '像素点阵' }
]
},
encoding: '显示: RGB 像素值'
}
]
const keyPoints = [
{
icon: '🔤',
title: '编码转换',
desc: '数据在不同阶段使用不同的编码方式(ASCII、Unicode、二进制等)'
},
{
icon: '📦',
title: '封装格式',
desc: '传输和存储时需要封装成特定格式(文件、数据包、帧等)'
},
{
icon: '🎯',
title: '协议标准',
desc: '每个环节都遵循相应的协议和标准(TCP/IP、USB、HDMI等)'
},
{
icon: '⚡',
title: '性能优化',
desc: '编码压缩、缓存、流水线等技术提升数据处理效率'
}
]
</script>
<style scoped>
.data-lifecycle-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.lifecycle-flow {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 2rem;
}
.flow-stage {
display: flex;
flex-direction: column;
align-items: center;
}
.stage-header {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem 1.5rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
width: 100%;
max-width: 500px;
}
.stage-header:hover {
border-color: var(--vp-c-brand);
transform: translateX(5px);
}
.stage-number {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-weight: 600;
font-size: 0.9rem;
}
.stage-name {
flex: 1;
font-weight: 600;
font-size: 1rem;
}
.stage-icon {
font-size: 1.5rem;
}
.flow-arrow {
font-size: 1.5rem;
color: var(--vp-c-text-2);
margin: 0.5rem 0;
}
.stage-detail {
width: 100%;
max-width: 600px;
margin-top: 1rem;
}
.detail-content {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.25rem;
}
.detail-content h4 {
margin: 0 0 0.75rem 0;
color: var(--vp-c-brand);
font-size: 1rem;
}
.detail-content > p {
margin: 0 0 1rem 0;
font-size: 0.9rem;
line-height: 1.6;
color: var(--vp-c-text-1);
}
.stage-example {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 0.75rem;
margin-bottom: 0.75rem;
}
.example-label {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.example-item {
display: flex;
gap: 0.5rem;
font-size: 0.85rem;
margin-bottom: 0.35rem;
}
.example-item:last-child {
margin-bottom: 0;
}
.item-label {
color: var(--vp-c-text-2);
flex-shrink: 0;
}
.item-value {
color: var(--vp-c-text-1);
font-weight: 500;
}
.stage-encoding {
display: flex;
gap: 0.5rem;
align-items: center;
font-size: 0.85rem;
padding: 0.5rem 0.75rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
}
.encoding-label {
font-weight: 600;
color: var(--vp-c-brand);
}
.encoding-value {
font-family: 'Courier New', monospace;
color: var(--vp-c-text-1);
}
.lifecycle-summary {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.summary-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.summary-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.summary-card {
display: flex;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.card-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.card-text {
flex: 1;
}
.card-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
overflow: hidden;
}
.slide-enter-from,
.slide-leave-to {
opacity: 0;
max-height: 0;
transform: translateY(-10px);
}
.slide-enter-to,
.slide-leave-from {
opacity: 1;
max-height: 500px;
transform: translateY(0);
}
</style>
@@ -0,0 +1,480 @@
<template>
<div class="data-link-demo">
<div class="demo-header">
<span class="icon">🔗</span>
<span class="title">数据链路层帧的传递</span>
<span class="subtitle">MAC 地址如何定位设备</span>
</div>
<div class="lan-scene">
<div class="lan-title">局域网场景</div>
<div class="lan-devices">
<div
v-for="device in devices"
:key="device.id"
:class="['lan-device', { active: activeDevice === device.id, sender: device.role === 'sender', receiver: device.role === 'receiver' }]"
@click="activeDevice = device.id"
>
<div class="device-icon">{{ device.icon }}</div>
<div class="device-name">{{ device.name }}</div>
<div class="device-mac">{{ device.mac }}</div>
<div v-if="device.role" class="device-role">{{ device.roleText }}</div>
</div>
</div>
<!-- 交换机 -->
<div class="switch">
<div class="switch-icon">🔄</div>
<div class="switch-name">交换机</div>
<div class="switch-desc">根据 MAC 地址转发数据帧</div>
</div>
</div>
<!-- 帧结构 -->
<div class="frame-structure">
<div class="frame-title">以太网帧结构</div>
<div class="frame-visual">
<div class="frame-fields">
<div
v-for="(field, index) in frameFields"
:key="index"
:class="['frame-field', { highlighted: activeDevice !== null }]"
:style="{ width: field.width }"
>
<div class="field-name">{{ field.name }}</div>
<div class="field-value">{{ field.value }}</div>
<div class="field-size">{{ field.size }}</div>
</div>
</div>
</div>
</div>
<!-- 传输过程 -->
<div class="transfer-process">
<div class="process-title">数据帧传输过程</div>
<div class="process-steps">
<div
v-for="(step, index) in transferSteps"
:key="index"
:class="['process-step', { active: activeStep === index }]"
>
<div class="step-number">{{ index + 1 }}</div>
<div class="step-content">
<div class="step-title">{{ step.title }}</div>
<div class="step-desc">{{ step.desc }}</div>
</div>
</div>
</div>
</div>
<!-- ARP 协议 -->
<div class="arp-section">
<div class="arp-title">ARPIP 地址到 MAC 地址的映射</div>
<div class="arp-example">
<div class="arp-question">
<span class="question-icon"></span>
<span class="question-text">谁有 IP 地址 192.168.1.200</span>
</div>
<div class="arp-arrow"> 广播到局域网</div>
<div class="arp-answer">
<span class="answer-icon"></span>
<span class="answer-text">我是我的 MAC 地址是 00:11:22:33:44:66</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeDevice = ref(null)
const activeStep = ref(0)
const devices = [
{
id: 'pc1',
name: '电脑 A',
icon: '💻',
mac: '00:11:22:33:44:55',
ip: '192.168.1.100',
role: 'sender',
roleText: '发送方'
},
{
id: 'pc2',
name: '电脑 B',
icon: '🖥️',
mac: '00:11:22:33:44:66',
ip: '192.168.1.200',
role: 'receiver',
roleText: '接收方'
},
{
id: 'printer',
name: '打印机',
icon: '🖨️',
mac: '00:11:22:33:44:77',
ip: '192.168.1.50'
},
{
id: 'phone',
name: '手机',
icon: '📱',
mac: '00:11:22:33:44:88',
ip: '192.168.1.150'
}
]
const frameFields = [
{
name: '目的 MAC',
value: '00:11:22:33:44:66',
size: '6 字节',
width: '18%'
},
{
name: '源 MAC',
value: '00:11:22:33:44:55',
size: '6 字节',
width: '18%'
},
{
name: '类型',
value: '0x0800 (IPv4)',
size: '2 字节',
width: '12%'
},
{
name: '数据',
value: 'IP 数据包...',
size: '46-1500 字节',
width: '44%'
},
{
name: 'FCS',
value: '校验序列',
size: '4 字节',
width: '8%'
}
]
const transferSteps = [
{
title: '封装成帧',
desc: '发送方将数据封装成以太网帧,添加源 MAC 和目的 MAC 地址'
},
{
title: '发送到交换机',
desc: '帧通过物理介质(网线或 WiFi)发送到交换机'
},
{
title: '交换机转发',
desc: '交换机根据目的 MAC 地址,将帧转发到对应端口'
},
{
title: '接收方处理',
desc: '接收方检查目的 MAC 地址,匹配后接收并处理数据'
}
]
</script>
<style scoped>
.data-link-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.lan-scene {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.lan-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.lan-devices {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.lan-device {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.lan-device:hover {
border-color: var(--vp-c-brand);
}
.lan-device.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.lan-device.sender {
border-color: #10b981;
background: rgba(16, 185, 129, 0.1);
}
.lan-device.receiver {
border-color: #3b82f6;
background: rgba(59, 130, 246, 0.1);
}
.device-icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
.device-name {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.device-mac {
font-family: 'Courier New', monospace;
font-size: 0.7rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.device-role {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
background: var(--vp-c-brand);
color: white;
border-radius: 10px;
display: inline-block;
}
.switch {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border: 2px dashed var(--vp-c-divider);
border-radius: 8px;
}
.switch-icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
.switch-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.35rem;
}
.switch-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.frame-structure {
margin-bottom: 1.5rem;
}
.frame-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.frame-visual {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
}
.frame-fields {
display: flex;
gap: 0.5rem;
}
.frame-field {
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
padding: 0.75rem 0.5rem;
text-align: center;
background: var(--vp-c-bg-soft);
transition: all 0.3s;
}
.frame-field.highlighted {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.field-name {
font-weight: 600;
font-size: 0.8rem;
margin-bottom: 0.35rem;
}
.field-value {
font-family: 'Courier New', monospace;
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.field-size {
font-size: 0.7rem;
color: var(--vp-c-text-2);
}
.transfer-process {
margin-bottom: 1.5rem;
}
.process-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.process-steps {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.process-step {
display: flex;
gap: 1rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.step-number {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.85rem;
font-weight: 600;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.step-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.arp-section {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.arp-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.arp-example {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
}
.arp-question,
.arp-answer {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 0.75rem;
}
.arp-question {
background: rgba(59, 130, 246, 0.1);
}
.arp-answer {
background: rgba(16, 185, 129, 0.1);
margin-bottom: 0;
}
.question-icon,
.answer-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.question-text,
.answer-text {
font-size: 0.9rem;
}
.arp-arrow {
text-align: center;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin: 0.75rem 0;
}
@media (max-width: 768px) {
.frame-fields {
flex-wrap: wrap;
}
.frame-field {
min-width: 100px;
}
}
</style>
@@ -0,0 +1,530 @@
<template>
<div class="ds-overview-demo">
<div class="demo-header">
<span class="icon">🏗</span>
<span class="title">数据结构全景图</span>
<span class="subtitle">不同场景选择不同的数据组织方式</span>
</div>
<div class="structure-map">
<div class="map-intro">
数据结构就像整理房间的方式把衣服放进衣柜书放在书架杂物放抽屉
</div>
<div class="structure-categories">
<div
v-for="category in categories"
:key="category.id"
:class="['category-card', { active: activeCategory === category.id }]"
@click="activeCategory = category.id"
>
<div class="category-icon">{{ category.icon }}</div>
<div class="category-name">{{ category.name }}</div>
<div class="category-desc">{{ category.desc }}</div>
<div class="category-examples">
<span
v-for="example in category.examples"
:key="example"
class="example-tag"
>
{{ example }}
</span>
</div>
</div>
</div>
</div>
<!-- 详细说明 -->
<div class="category-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentCategory.icon }}</span>
<span class="detail-title">{{ currentCategory.name }}</span>
</div>
<div class="detail-content">
<div class="detail-section">
<div class="section-title">特点</div>
<div class="feature-grid">
<div
v-for="(feature, index) in currentCategory.features"
:key="index"
class="feature-item"
>
<span class="feature-icon"></span>
<span class="feature-text">{{ feature }}</span>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">适用场景</div>
<div class="scenario-list">
<div
v-for="(scenario, index) in currentCategory.scenarios"
:key="index"
class="scenario-card"
>
<div class="scenario-icon">{{ scenario.icon }}</div>
<div class="scenario-content">
<div class="scenario-title">{{ scenario.title }}</div>
<div class="scenario-desc">{{ scenario.desc }}</div>
</div>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">操作复杂度</div>
<div class="complexity-table">
<div class="table-header">
<span class="header-cell">操作</span>
<span class="header-cell">平均时间</span>
</div>
<div
v-for="(op, index) in currentCategory.complexity"
:key="index"
class="table-row"
>
<span class="data-cell">{{ op.operation }}</span>
<span class="data-cell highlight">{{ op.time }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- 类比说明 -->
<div class="analogy-section">
<div class="analogy-title">生活类比</div>
<div class="analogy-content">
<div class="analogy-text">{{ currentCategory.analogy.text }}</div>
<div class="analogy-example">{{ currentCategory.analogy.example }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeCategory = ref('linear')
const categories = [
{
id: 'linear',
name: '线性结构',
icon: '📚',
desc: '数据按顺序排列,像一排书',
examples: ['数组', '链表', '栈', '队列'],
features: [
'数据元素之间一对一关系',
'有明确的先后顺序',
'可以是连续存储或链式存储'
],
scenarios: [
{
icon: '📝',
title: '数组:列表数据',
desc: '存储学生成绩、商品价格等有序数据'
},
{
icon: '🔄',
title: '栈:撤销操作',
desc: '文本编辑器的撤销功能,后进先出'
},
{
icon: '🎫',
title: '队列:任务调度',
desc: '打印队列、任务队列,先进先出'
}
],
complexity: [
{ operation: '访问元素', time: 'O(1)' },
{ operation: '插入/删除', time: 'O(n)' }
],
analogy: {
text: '像一列火车,车厢按顺序连接',
example: '要找到第 5 节车厢,直接数过去;要插入新车厢,需要断开连接'
}
},
{
id: 'hash',
name: '哈希结构',
icon: '🗂️',
desc: '通过关键词快速查找',
examples: ['哈希表', '字典', '集合'],
features: [
'通过键值对存储数据',
'查找速度极快',
'数据之间没有顺序关系'
],
scenarios: [
{
icon: '📖',
title: '字典:单词查找',
desc: '根据英文单词快速找到中文释义'
},
{
icon: '👤',
title: '用户信息:ID 查询',
desc: '根据用户 ID 快速获取用户资料'
},
{
icon: '🛒',
title: '购物车:商品管理',
desc: '记录商品 ID 和数量,快速结算'
}
],
complexity: [
{ operation: '查找', time: 'O(1)' },
{ operation: '插入/删除', time: 'O(1)' }
],
analogy: {
text: '像图书馆的索引卡片',
example: '不用在一排排书架上找,直接查索引就能找到位置'
}
},
{
id: 'tree',
name: '树形结构',
icon: '🌳',
desc: '层级关系,像家谱',
examples: ['二叉树', 'B 树', '堆'],
features: [
'一对多的层级关系',
'有明确的根节点',
'适合表示分类和层级'
],
scenarios: [
{
icon: '📁',
title: '文件系统:目录树',
desc: '文件夹和文件的层级组织'
},
{
icon: '🏢',
title: '组织架构:管理树',
desc: '公司管理层级关系'
},
{
icon: '💻',
title: 'HTMLDOM 树',
desc: '网页元素的嵌套结构'
}
],
complexity: [
{ operation: '查找', time: 'O(log n)' },
{ operation: '插入/删除', time: 'O(log n)' }
],
analogy: {
text: '像家谱树或公司组织架构',
example: '从根节点(祖先)开始,一层层向下找,路径唯一'
}
},
{
id: 'graph',
name: '图结构',
icon: '🕸️',
desc: '复杂关系网络',
examples: ['有向图', '无向图', '网络图'],
features: [
'多对多的复杂关系',
'节点之间可以任意连接',
'可以表示复杂网络'
],
scenarios: [
{
icon: '🗺️',
title: '地图:路径规划',
desc: '城市之间的道路连接,导航系统'
},
{
icon: '👥',
title: '社交网络:好友关系',
desc: '用户之间的关注、好友关系'
},
{
icon: '🔗',
title: '网页:链接关系',
desc: '网页之间的超链接网络'
}
],
complexity: [
{ operation: '遍历', time: 'O(V + E)' },
{ operation: '最短路径', time: 'O(E + V log V)' }
],
analogy: {
text: '像地铁线路图或航空网络',
example: '多个站点,多条线路,站点之间可以有多种连接方式'
}
}
]
const currentCategory = computed(() => categories.find(c => c.id === activeCategory.value))
</script>
<style scoped>
.ds-overview-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.structure-map {
margin-bottom: 2rem;
}
.map-intro {
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
font-size: 0.9rem;
line-height: 1.6;
margin-bottom: 1.5rem;
}
.structure-categories {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.category-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
}
.category-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.category-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.category-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.category-name {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.5rem;
}
.category-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-bottom: 1rem;
}
.category-examples {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.example-tag {
padding: 0.25rem 0.6rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
font-size: 0.75rem;
}
.category-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.detail-section {}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.75rem;
}
.feature-item {
display: flex;
gap: 0.5rem;
align-items: start;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.feature-icon {
color: #10b981;
font-weight: 700;
flex-shrink: 0;
}
.feature-text {
font-size: 0.85rem;
line-height: 1.5;
}
.scenario-list {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.scenario-card {
display: flex;
gap: 0.75rem;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.scenario-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.scenario-content {
flex: 1;
}
.scenario-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.scenario-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.complexity-table {
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
overflow: hidden;
}
.table-header {
display: grid;
grid-template-columns: 1fr 1fr;
background: var(--vp-c-brand);
color: white;
}
.header-cell {
padding: 0.6rem;
font-size: 0.85rem;
font-weight: 600;
text-align: center;
}
.table-row {
display: grid;
grid-template-columns: 1fr 1fr;
border-top: 1px solid var(--vp-c-divider);
}
.data-cell {
padding: 0.6rem;
font-size: 0.85rem;
text-align: center;
font-family: 'Courier New', monospace;
}
.data-cell.highlight {
color: var(--vp-c-brand);
font-weight: 600;
}
.analogy-section {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.analogy-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.analogy-content {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.analogy-text {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
font-size: 0.95rem;
line-height: 1.6;
}
.analogy-example {
padding: 0.75rem;
background: var(--vp-c-bg);
border-left: 3px solid var(--vp-c-brand);
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.5;
}
</style>
@@ -0,0 +1,486 @@
<template>
<div class="ds-selector-demo">
<div class="demo-header">
<span class="icon">🎯</span>
<span class="title">如何选择合适的数据结构</span>
<span class="subtitle">根据场景需求做出最佳选择</span>
</div>
<div class="scenario-selector">
<div class="selector-title">你的使用场景是</div>
<div class="scenario-grid">
<div
v-for="scenario in scenarios"
:key="scenario.id"
:class="['scenario-card', { active: activeScenario === scenario.id }]"
@click="activeScenario = scenario.id"
>
<div class="scenario-icon">{{ scenario.icon }}</div>
<div class="scenario-name">{{ scenario.name }}</div>
<div class="scenario-desc">{{ scenario.desc }}</div>
</div>
</div>
</div>
<!-- 推荐结果 -->
<div v-if="activeScenario" class="recommendation">
<div class="rec-header">
<span class="rec-icon">💡</span>
<span class="rec-title">推荐使用{{ currentScenario.recommendation }}</span>
</div>
<div class="rec-reason">
<div class="reason-title">为什么</div>
<div class="reason-list">
<div
v-for="(reason, index) in currentScenario.reasons"
:key="index"
class="reason-item"
>
<span class="reason-bullet"></span>
<span class="reason-text">{{ reason }}</span>
</div>
</div>
</div>
<div class="rec-example">
<div class="example-title">实际例子</div>
<div class="example-content">{{ currentScenario.example }}</div>
</div>
</div>
<!-- 快速参考表 -->
<div class="quick-reference">
<div class="ref-title">快速参考表</div>
<table class="ref-table">
<thead>
<tr>
<th>场景需求</th>
<th>推荐数据结构</th>
<th>时间复杂度</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in referenceTable" :key="index">
<td>{{ row.scenario }}</td>
<td>{{ row.structure }}</td>
<td class="complexity">{{ row.complexity }}</td>
</tr>
</tbody>
</table>
</div>
<!-- 决策流程 -->
<div class="decision-flow">
<div class="flow-title">选择决策流程</div>
<div class="flow-diagram">
<div class="flow-step question">
<div class="step-icon"></div>
<div class="step-text">需要快速访问元素</div>
</div>
<div class="flow-branch">
<div class="branch-yes">
<div class="branch-label"></div>
<div class="flow-result">数组 / 哈希表</div>
</div>
<div class="branch-no">
<div class="branch-label"></div>
<div class="flow-step question">
<div class="step-text">需要频繁插入删除</div>
</div>
<div class="flow-branch">
<div class="branch-yes">
<div class="branch-label"></div>
<div class="flow-result">链表</div>
</div>
<div class="branch-no">
<div class="branch-label"></div>
<div class="flow-step question">
<div class="step-text">需要保持顺序</div>
</div>
<div class="flow-branch">
<div class="branch-yes">
<div class="branch-label"></div>
<div class="flow-result"> / 队列</div>
</div>
<div class="branch-no">
<div class="branch-label"></div>
<div class="flow-result"> / </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeScenario = ref(null)
const scenarios = [
{
id: 'lookup',
icon: '🔍',
name: '快速查找',
desc: '根据关键词快速找到对应数据',
recommendation: '哈希表',
reasons: [
'平均查找时间 O(1),瞬间找到',
'键值对存储,语义清晰',
'无需遍历整个数据集'
],
example: '用户 ID 查找用户资料、字典查词、缓存系统'
},
{
id: 'ordered',
icon: '📊',
name: '保持顺序',
desc: '数据需要按插入顺序或特定顺序存储',
recommendation: '数组 或 链表',
reasons: [
'数组支持索引直接访问',
'链表可以灵活调整大小',
'按位置访问速度快'
],
example: '学生成绩列表、时间序列数据、排行榜'
},
{
id: 'lifo',
icon: '🥞',
name: '后进先出',
desc: '最后进入的最先处理',
recommendation: '栈',
reasons: [
'只能在栈顶操作',
'入栈出栈都是 O(1)',
'适合回溯和撤销操作'
],
example: '浏览器后退、编辑器撤销、函数调用栈'
},
{
id: 'fifo',
icon: '🚶',
name: '先进先出',
desc: '先来的先处理',
recommendation: '队列',
reasons: [
'一端入队,另一端出队',
'入队出队都是 O(1)',
'公平的调度方式'
],
example: '打印队列、任务调度、消息队列'
},
{
id: 'hierarchy',
icon: '🌳',
name: '层级关系',
desc: '数据之间有父子层级关系',
recommendation: '树',
reasons: [
'清晰表达层级结构',
'查找效率 O(log n)',
'支持多种遍历方式'
],
example: '文件系统、组织架构、HTML DOM'
},
{
id: 'relationship',
icon: '🕸️',
name: '复杂关系',
desc: '数据之间有多对多的复杂连接',
recommendation: '图',
reasons: [
'可以表示任意关系',
'支持路径搜索算法',
'适合网络和社交关系'
],
example: '社交网络、地图导航、网页链接'
}
]
const referenceTable = [
{ scenario: '随机访问', structure: '数组', complexity: 'O(1)' },
{ scenario: '快速查找', structure: '哈希表', complexity: 'O(1)' },
{ scenario: '有序查找', structure: '二叉搜索树', complexity: 'O(log n)' },
{ scenario: '频繁插入删除', structure: '链表', complexity: 'O(1)' },
{ scenario: '撤销操作', structure: '栈', complexity: 'O(1)' },
{ scenario: '任务调度', structure: '队列', complexity: 'O(1)' }
]
const currentScenario = computed(() => {
return scenarios.find(s => s.id === activeScenario.value)
})
</script>
<style scoped>
.ds-selector-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.scenario-selector {
margin-bottom: 2rem;
}
.selector-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.scenario-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.scenario-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.scenario-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.scenario-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.scenario-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.scenario-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.scenario-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.recommendation {
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-brand);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.rec-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
}
.rec-icon {
font-size: 1.5rem;
}
.rec-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.rec-reason {
margin-bottom: 1.5rem;
}
.reason-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.reason-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.reason-item {
display: flex;
gap: 0.75rem;
align-items: start;
}
.reason-bullet {
color: #10b981;
font-weight: 700;
flex-shrink: 0;
}
.reason-text {
font-size: 0.9rem;
line-height: 1.5;
}
.rec-example {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.example-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.example-content {
font-size: 0.85rem;
line-height: 1.6;
color: var(--vp-c-text-1);
}
.quick-reference {
margin-bottom: 2rem;
}
.ref-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.ref-table {
width: 100%;
border-collapse: collapse;
}
.ref-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: left;
font-size: 0.85rem;
}
.ref-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
font-size: 0.85rem;
}
.complexity {
font-family: 'Courier New', monospace;
color: var(--vp-c-brand);
font-weight: 600;
}
.decision-flow {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.flow-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.flow-diagram {
display: flex;
flex-direction: column;
gap: 1rem;
}
.flow-step {
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.flow-step.question {
background: rgba(59, 130, 246, 0.1);
border-color: #3b82f6;
}
.step-icon {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.step-text {
font-size: 0.9rem;
font-weight: 500;
}
.flow-branch {
display: flex;
gap: 1rem;
margin-left: 1rem;
}
.branch-yes,
.branch-no {
flex: 1;
}
.branch-label {
text-align: center;
padding: 0.5rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-size: 0.8rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
.flow-result {
text-align: center;
padding: 0.75rem;
background: #10b981;
color: white;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
}
</style>
@@ -0,0 +1,637 @@
<template>
<div class="est-demo">
<div class="demo-header">
<span class="icon">🔗</span>
<span class="title">编码存储与传输的协作</span>
<span class="subtitle">三大系统如何协同处理数据</span>
</div>
<div class="scenario-selector">
<div class="selector-label">选择场景</div>
<div class="scenario-buttons">
<button
v-for="scenario in scenarios"
:key="scenario.id"
:class="['scenario-btn', { active: activeScenario === scenario.id }]"
@click="activeScenario = scenario.id"
>
{{ scenario.icon }} {{ scenario.name }}
</button>
</div>
</div>
<div class="collab-diagram">
<div class="diagram-flow">
<!-- 编码阶段 -->
<div class="flow-stage encoding-stage">
<div class="stage-header">
<span class="stage-icon">🔤</span>
<span class="stage-title">编码</span>
</div>
<div class="stage-content">
<div class="input-box">
<div class="box-label">原始数据</div>
<div class="box-value">{{ currentScenario.encoding.input }}</div>
</div>
<div class="arrow"></div>
<div class="output-box">
<div class="box-label">编码后</div>
<div class="box-value code">{{ currentScenario.encoding.output }}</div>
</div>
</div>
</div>
<!-- 存储阶段 -->
<div class="flow-stage storage-stage">
<div class="stage-header">
<span class="stage-icon">💾</span>
<span class="stage-title">存储</span>
</div>
<div class="stage-content">
<div class="storage-visual">
<div class="storage-blocks">
<div
v-for="(block, index) in currentScenario.storage.blocks"
:key="index"
class="storage-block"
:title="block"
>
{{ block }}
</div>
</div>
</div>
<div class="storage-info">
<div class="info-item">
<span class="info-label">位置:</span>
<span class="info-value">{{ currentScenario.storage.location }}</span>
</div>
<div class="info-item">
<span class="info-label">大小:</span>
<span class="info-value">{{ currentScenario.storage.size }}</span>
</div>
</div>
</div>
</div>
<!-- 传输阶段 -->
<div class="flow-stage transmission-stage">
<div class="stage-header">
<span class="stage-icon">📡</span>
<span class="stage-title">传输</span>
</div>
<div class="stage-content">
<div class="transmission-flow">
<div class="transmission-packet">
<div class="packet-header">数据包</div>
<div class="packet-body">
<div class="packet-layer" v-for="(layer, index) in currentScenario.transmission.layers" :key="index">
<span class="layer-name">{{ layer.name }}:</span>
<span class="layer-value">{{ layer.value }}</span>
</div>
</div>
</div>
</div>
<div class="transmission-info">
<div class="info-item">
<span class="info-label">协议:</span>
<span class="info-value">{{ currentScenario.transmission.protocol }}</span>
</div>
<div class="info-item">
<span class="info-label">路径:</span>
<span class="info-value">{{ currentScenario.transmission.path }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- 协作关系 -->
<div class="collab-relationships">
<div class="relationship-arrow encoding-to-storage">
<span class="arrow-text">{{ currentScenario.relationships.encodingToStorage }}</span>
<span class="arrow-icon"></span>
</div>
<div class="relationship-arrow storage-to-transmission">
<span class="arrow-text">{{ currentScenario.relationships.storageToTransmission }}</span>
<span class="arrow-icon"></span>
</div>
</div>
</div>
<!-- 关键要点 -->
<div class="key-points">
<div class="points-title">协作要点</div>
<div class="points-grid">
<div v-for="(point, index) in currentScenario.points" :key="index" class="point-card">
<div class="point-icon">{{ point.icon }}</div>
<div class="point-content">
<div class="point-title">{{ point.title }}</div>
<div class="point-desc">{{ point.desc }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeScenario = ref('text-file')
const scenarios = [
{
id: 'text-file',
name: '保存文本文件',
icon: '📝'
},
{
id: 'upload-image',
name: '上传图片',
icon: '🖼️'
},
{
id: 'stream-video',
name: '流媒体播放',
icon: '🎬'
},
{
id: 'send-message',
name: '发送消息',
icon: '💬'
}
]
const scenarioData = {
'text-file': {
encoding: {
input: '你好',
output: 'U+4F60 U+597D'
},
storage: {
location: '文档文件夹 /hello.txt',
size: '6 字节 (UTF-8)',
blocks: ['E4', 'BD', 'A0', 'E5', 'A5', 'BD']
},
transmission: {
protocol: 'HTTP + TCP/IP',
path: '客户端 → 服务器 → 云存储',
layers: [
{ name: '应用层', value: 'HTTP POST' },
{ name: '传输层', value: 'TCP 端口 443' },
{ name: '网络层', value: 'IP 数据包' }
]
},
relationships: {
encodingToStorage: 'UTF-8 编码后的字节序列写入磁盘',
storageToTransmission: '读取文件并通过网络发送'
},
points: [
{
icon: '🔤',
title: '编码统一',
desc: '使用 UTF-8 编码确保中文字符正确存储和传输'
},
{
icon: '📦',
title: '文件封装',
desc: '文本内容被封装成 .txt 文件格式存储'
},
{
icon: '🔄',
title: '协议转换',
desc: '存储时用文件系统协议,传输时用 HTTP 协议'
}
]
},
'upload-image': {
encoding: {
input: '图片数据',
output: 'JPEG 压缩编码'
},
storage: {
location: '相册 /photo.jpg',
size: '2.5 MB',
blocks: ['FF', 'D8', 'FF', 'E0', '...', 'FF', 'D9']
},
transmission: {
protocol: 'HTTPS + MIME multipart',
path: '手机 → API 网关 → 对象存储',
layers: [
{ name: '应用层', value: 'HTTPS POST' },
{ name: '传输层', value: 'TLS 加密' },
{ name: '网络层', value: 'IP 分片' }
]
},
relationships: {
encodingToStorage: 'JPEG 压缩编码减少文件大小',
storageToTransmission: '二进制数据分块上传'
},
points: [
{
icon: '🗜️',
title: '压缩编码',
desc: 'JPEG 压缩算法减少图片体积,节省存储空间'
},
{
icon: '🔐',
title: '安全传输',
desc: 'HTTPS 加密保护图片数据在网络传输中的安全'
},
{
icon: '⚡',
title: '分块上传',
desc: '大文件分块传输,支持断点续传'
}
]
},
'stream-video': {
encoding: {
input: '视频流',
output: 'H.264 编码'
},
storage: {
location: 'CDN 缓存节点',
size: '动态调整',
blocks: ['帧1', '帧2', '帧3', '...']
},
transmission: {
protocol: 'HLS + DASH',
path: '服务器 → CDN → 用户设备',
layers: [
{ name: '应用层', value: 'HLS 播放列表' },
{ name: '传输层', value: 'TCP 流式' },
{ name: '网络层', value: 'UDP 可能' }
]
},
relationships: {
encodingToStorage: '视频分段存储在 CDN',
storageToTransmission: '根据网络状况自适应码率'
},
points: [
{
icon: '🎬',
title: '流式编码',
desc: 'H.264 视频编码压缩,适合网络传输'
},
{
icon: '🌐',
title: 'CDN 加速',
desc: '内容分发网络缓存视频,就近提供服务'
},
{
icon: '📊',
title: '自适应码率',
desc: '根据网络状况动态调整视频质量'
}
]
},
'send-message': {
encoding: {
input: '消息内容',
output: 'JSON 格式'
},
storage: {
location: '本地数据库 + 服务器',
size: '约 200 字节',
blocks: ['JSON格式']
},
transmission: {
protocol: 'WebSocket',
path: '发送方 → 即时通讯服务器 → 接收方',
layers: [
{ name: '应用层', value: 'WebSocket 帧' },
{ name: '传输层', value: 'TCP 长连接' },
{ name: '网络层', value: 'IP 路由' }
]
},
relationships: {
encodingToStorage: 'JSON 格式便于解析和存储',
storageToTransmission: 'WebSocket 保持实时连接'
},
points: [
{
icon: '📨',
title: '实时推送',
desc: 'WebSocket 长连接实现消息即时送达'
},
{
icon: '💾',
title: '双重存储',
desc: '本地存储离线消息,服务器存储历史记录'
},
{
icon: '🔗',
title: 'JSON 编码',
desc: '结构化数据格式,易于解析和扩展'
}
]
}
}
const currentScenario = computed(() => scenarioData[activeScenario.value])
</script>
<style scoped>
.est-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.scenario-selector {
margin-bottom: 2rem;
}
.selector-label {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.scenario-buttons {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
}
.scenario-btn {
padding: 0.6rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.scenario-btn:hover {
border-color: var(--vp-c-brand);
}
.scenario-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.collab-diagram {
position: relative;
margin-bottom: 2rem;
}
.diagram-flow {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
margin-bottom: 2rem;
}
@media (max-width: 968px) {
.diagram-flow {
grid-template-columns: 1fr;
}
}
.flow-stage {
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
background: var(--vp-c-bg);
}
.stage-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.stage-icon { font-size: 1.3rem; }
.stage-title { font-weight: 600; font-size: 0.95rem; }
.stage-content {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.input-box,
.output-box {
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.box-label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.box-value {
font-size: 0.9rem;
font-weight: 500;
}
.box-value.code {
font-family: 'Courier New', monospace;
color: var(--vp-c-brand);
}
.arrow {
text-align: center;
font-size: 1.2rem;
color: var(--vp-c-text-2);
}
.storage-visual {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 0.75rem;
margin-bottom: 0.5rem;
}
.storage-blocks {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
}
.storage-block {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand-soft);
border: 1px solid var(--vp-c-brand);
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 0.75rem;
color: var(--vp-c-brand);
font-weight: 600;
}
.storage-info {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.info-item {
display: flex;
gap: 0.5rem;
font-size: 0.85rem;
}
.info-label {
color: var(--vp-c-text-2);
flex-shrink: 0;
}
.info-value {
color: var(--vp-c-text-1);
font-weight: 500;
}
.transmission-flow {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 0.75rem;
margin-bottom: 0.5rem;
}
.transmission-packet {
border: 2px solid var(--vp-c-brand);
border-radius: 6px;
overflow: hidden;
}
.packet-header {
background: var(--vp-c-brand);
color: white;
padding: 0.5rem;
font-size: 0.8rem;
font-weight: 600;
text-align: center;
}
.packet-body {
padding: 0.75rem;
}
.packet-layer {
display: flex;
gap: 0.5rem;
font-size: 0.8rem;
margin-bottom: 0.5rem;
}
.packet-layer:last-child {
margin-bottom: 0;
}
.layer-name {
color: var(--vp-c-text-2);
flex-shrink: 0;
}
.layer-value {
color: var(--vp-c-text-1);
font-weight: 500;
}
.collab-relationships {
display: flex;
justify-content: space-around;
gap: 1rem;
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
}
.relationship-arrow {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
flex: 1;
text-align: center;
}
.arrow-text {
font-size: 0.85rem;
color: var(--vp-c-text-1);
line-height: 1.4;
}
.arrow-icon {
font-size: 1.5rem;
color: var(--vp-c-brand);
}
.key-points {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.points-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.points-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.point-card {
display: flex;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.point-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.point-content {
flex: 1;
}
.point-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.point-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
</style>
@@ -0,0 +1,309 @@
<template>
<div class="graph-structure-demo">
<div class="demo-header">
<span class="icon">🕸</span>
<span class="title">图结构复杂关系的表示</span>
<span class="subtitle">节点和边的网络</span>
</div>
<div class="graph-types">
<div class="type-selector">
<button
:class="['type-btn', { active: graphType === 'undirected' }]"
@click="graphType = 'undirected'"
>
无向图
</button>
<button
:class="['type-btn', { active: graphType === 'directed' }]"
@click="graphType = 'directed'"
>
有向图
</button>
<button
:class="['type-btn', { active: graphType === 'weighted' }]"
@click="graphType = 'weighted'"
>
带权图
</button>
</div>
</div>
<div class="graph-visualization">
<svg viewBox="0 0 400 300" class="graph-svg">
<!-- 连接线 -->
<line
v-for="edge in edges"
:key="edge.id"
:x1="nodes[edge.from].x"
:y1="nodes[edge.from].y"
:x2="nodes[edge.to].x"
:y2="nodes[edge.to].y"
:stroke="edge.weight ? '#3b82f6' : 'var(--vp-c-divider)'"
:stroke-width="edge.weight ? '3' : '2'"
:marker-end="graphType === 'directed' ? 'url(#arrow)' : ''"
/>
<!-- 箭头定义 -->
<defs v-if="graphType === 'directed'">
<marker
id="arrow"
viewBox="0 0 10 10"
refX="20"
refY="5"
markerWidth="6"
markerHeight="6"
orient="auto"
>
<path d="M 0 0 L 10 5 L 0 10 z" fill="var(--vp-c-divider)" />
</marker>
</defs>
<!-- 节点 -->
<g
v-for="(node, index) in nodes"
:key="index"
class="graph-node"
@click="selectedNode = index"
>
<circle
:cx="node.x"
:cy="node.y"
r="20"
:fill="selectedNode === index ? 'var(--vp-c-brand)' : 'var(--vp-c-brand-soft)'"
stroke="var(--vp-c-brand)"
stroke-width="2"
/>
<text
:x="node.x"
:y="node.y"
text-anchor="middle"
dominant-baseline="middle"
fill="white"
font-size="12"
font-weight="600"
>
{{ node.label }}
</text>
</g>
</svg>
</div>
<div class="graph-info">
<div class="info-title">图的特点</div>
<div class="info-grid">
<div class="info-item">
<div class="item-label">节点 (V)</div>
<div class="item-value">{{ nodes.length }}</div>
</div>
<div class="info-item">
<div class="item-label"> (E)</div>
<div class="item-value">{{ edges.length }}</div>
</div>
<div class="info-item">
<div class="item-label"></div>
<div class="item-value">{{ averageDegree }}</div>
</div>
</div>
</div>
<div class="applications">
<div class="app-title">应用场景</div>
<div class="app-list">
<div class="app-item">
<span class="app-icon">🗺</span>
<span class="app-text">地图导航最短路径</span>
</div>
<div class="app-item">
<span class="app-icon">👥</span>
<span class="app-text">社交网络好友关系</span>
</div>
<div class="app-item">
<span class="app-icon">🌐</span>
<span class="app-text">网页链接PageRank</span>
</div>
<div class="app-item">
<span class="app-icon">🔗</span>
<span class="app-text">依赖关系包管理</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const graphType = ref('undirected')
const selectedNode = ref(null)
const nodes = [
{ label: 'A', x: 200, y: 50 },
{ label: 'B', x: 100, y: 130 },
{ label: 'C', x: 300, y: 130 },
{ label: 'D', x: 100, y: 250 },
{ label: 'E', x: 300, y: 250 }
]
const edges = ref([
{ id: 1, from: 0, to: 1 },
{ id: 2, from: 0, to: 2 },
{ id: 3, from: 1, to: 2 },
{ id: 4, from: 1, to: 3 },
{ id: 5, from: 2, to: 4 },
{ id: 6, from: 3, to: 4 }
])
const averageDegree = computed(() => {
return (edges.value.length * 2 / nodes.length).toFixed(1)
})
</script>
<style scoped>
.graph-structure-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.graph-types {
margin-bottom: 2rem;
}
.type-selector {
display: flex;
gap: 1rem;
justify-content: center;
}
.type-btn {
padding: 0.6rem 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s;
}
.type-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.graph-visualization {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.graph-svg {
width: 100%;
height: auto;
}
.graph-node {
cursor: pointer;
}
.graph-node circle {
transition: all 0.3s;
}
.graph-node:hover circle {
r: 25;
}
.graph-info {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.info-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.info-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.info-item {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.item-label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.item-value {
font-size: 1.5rem;
font-weight: 700;
color: var(--vp-c-brand);
}
.applications {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.app-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.app-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.75rem;
}
.app-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.app-icon {
font-size: 1.3rem;
}
.app-text {
font-size: 0.85rem;
}
</style>
@@ -0,0 +1,560 @@
<template>
<div class="greedy-thinking-demo">
<div class="demo-header">
<span class="icon">🎯</span>
<span class="title">贪心算法每步都选当前最优</span>
<span class="subtitle">局部最优 全局最优?</span>
</div>
<div class="core-idea">
<div class="idea-box">
<div class="idea-icon">💡</div>
<div class="idea-text">
贪心算法在每一步选择中都采取当前状态下<strong>最优</strong>的选择<br>
希望通过一系列局部最优选择达到<strong>全局最优</strong>
</div>
</div>
</div>
<div class="scenario-selector">
<div class="selector-title">经典问题</div>
<div class="scenario-buttons">
<button
v-for="scenario in scenarios"
:key="scenario.id"
:class="['scenario-btn', { active: activeScenario === scenario.id }]"
@click="activeScenario = scenario.id"
>
{{ scenario.icon }} {{ scenario.name }}
</button>
</div>
</div>
<!-- 找零钱问题 -->
<div v-if="activeScenario === 'change'" class="scenario-content">
<div class="content-title">找零钱问题</div>
<div class="change-demo">
<div class="change-amount">
需要找零<span class="amount">{{ changeAmount }}</span>
</div>
<div class="change-process">
<div class="process-step" v-for="(step, index) in changeSteps" :key="index">
<div class="step-coin">{{ step.coin }}</div>
<div class="step-text">× {{ step.count }} = {{ step.value }}</div>
</div>
</div>
<div class="change-result">
共需要 <strong>{{ totalCoins }}</strong> 个硬币
</div>
</div>
<div class="scenario-note">
贪心策略每次选择面值最大的硬币<br>
适用于人民币美元等货币系统
</div>
</div>
<!-- 活动选择问题 -->
<div v-if="activeScenario === 'activity'" class="scenario-content">
<div class="content-title">活动选择问题</div>
<div class="activity-demo">
<div class="activities-list">
<div
v-for="(activity, index) in activities"
:key="index"
:class="['activity-item', { selected: activity.selected, conflicting: activity.conflicting }]"
>
<div class="activity-time">{{ activity.start }} - {{ activity.end }}</div>
<div class="activity-name">{{ activity.name }}</div>
</div>
</div>
<div class="activity-rule">
贪心策略<strong>选择最早结束</strong>的活动
</div>
<div class="activity-result">
最多可以参加 <strong>{{ selectedCount }}</strong> 个活动
</div>
</div>
</div>
<!-- 最短路径 -->
<div v-if="activeScenario === 'shortest'" class="scenario-content">
<div class="content-title">最短路径问题 (Dijkstra)</div>
<div class="shortest-demo">
<div class="path-graph">
<div class="graph-nodes">
<div class="node start">A(起点)</div>
<div class="node">B</div>
<div class="node">C</div>
<div class="node">D</div>
<div class="node end">E(终点)</div>
</div>
<div class="graph-edges">
<div class="edge">A-B: 4</div>
<div class="edge">A-C: 2</div>
<div class="edge">B-D: 3</div>
<div class="edge">C-D: 1</div>
<div class="edge">C-E: 5</div>
<div class="edge">D-E: 2</div>
</div>
</div>
<div class="path-result">
<div class="result-step"> A 出发选择距离最近的节点</div>
<div class="result-path">A C D E</div>
<div class="result-distance">总距离2 + 1 + 2 = 5</div>
</div>
</div>
</div>
<!-- 贪心 vs 动态规划 -->
<div class="comparison">
<div class="comparison-title">贪心 vs 动态规划</div>
<div class="comparison-table">
<table>
<thead>
<tr>
<th>特点</th>
<th>贪心算法</th>
<th>动态规划</th>
</tr>
</thead>
<tbody>
<tr>
<td>决策方式</td>
<td>每步选当前最优</td>
<td>考虑所有可能选最优</td>
</tr>
<tr>
<td>最优性</td>
<td>可能不是全局最优</td>
<td>保证全局最优</td>
</tr>
<tr>
<td>时间复杂度</td>
<td>O(n) O(n log n)</td>
<td>O() 或更高</td>
</tr>
<tr>
<td>适用场景</td>
<td>局部最优 全局最优</td>
<td>重叠子问题</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 优缺点 -->
<div class="pros-cons">
<div class="pros-column">
<div class="column-title"> 优点</div>
<ul>
<li>实现简单</li>
<li>效率高</li>
<li>空间复杂度低</li>
</ul>
</div>
<div class="cons-column">
<div class="column-title"> 缺点</div>
<ul>
<li>不保证全局最优</li>
<li>适用范围有限</li>
<li>需要证明最优性</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeScenario = ref('change')
const scenarios = [
{ id: 'change', name: '找零钱', icon: '💰' },
{ id: 'activity', name: '活动选择', icon: '📅' },
{ id: 'shortest', name: '最短路径', icon: '🗺️' }
]
const changeAmount = ref(37)
const changeSteps = [
{ coin: '20元', count: 1, value: 20 },
{ coin: '10元', count: 1, value: 10 },
{ coin: '5元', count: 1, value: 5 },
{ coin: '1元', count: 2, value: 2 }
]
const totalCoins = computed(() => changeSteps.reduce((sum, step) => sum + step.count, 0))
const activities = [
{ start: '9:00', end: '10:00', name: '活动1', selected: true, conflicting: false },
{ start: '9:30', end: '11:30', name: '活动2', selected: false, conflicting: true },
{ start: '10:00', end: '11:00', name: '活动3', selected: true, conflicting: false },
{ start: '10:30', end: '12:00', name: '活动4', selected: false, conflicting: true },
{ start: '11:00', end: '12:00', name: '活动5', selected: true, conflicting: false }
]
const selectedCount = computed(() => activities.filter(a => a.selected).length)
</script>
<style scoped>
.greedy-thinking-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.core-idea {
margin-bottom: 2rem;
}
.idea-box {
display: flex;
gap: 1rem;
padding: 1.25rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
}
.idea-icon {
font-size: 2rem;
flex-shrink: 0;
}
.idea-text {
font-size: 0.95rem;
line-height: 1.8;
}
.scenario-selector {
margin-bottom: 2rem;
}
.selector-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.scenario-buttons {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
}
.scenario-btn {
padding: 0.6rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.scenario-btn:hover {
border-color: var(--vp-c-brand);
}
.scenario-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.scenario-content {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.content-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
text-align: center;
color: var(--vp-c-brand);
}
.change-demo {
text-align: center;
}
.change-amount {
font-size: 1.1rem;
margin-bottom: 1.5rem;
}
.amount {
color: var(--vp-c-brand);
font-weight: 700;
font-size: 1.3rem;
}
.change-process {
display: flex;
justify-content: center;
gap: 1rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.process-step {
text-align: center;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.step-coin {
font-size: 1.2rem;
font-weight: 600;
color: var(--vp-c-brand);
margin-bottom: 0.35rem;
}
.step-text {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.change-result {
font-size: 1rem;
padding: 0.75rem;
background: rgba(16, 185, 129, 0.1);
border: 1px solid #10b981;
border-radius: 6px;
}
.scenario-note {
margin-top: 1rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
font-size: 0.85rem;
line-height: 1.6;
}
.activities-list {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-bottom: 1.5rem;
}
.activity-item {
display: flex;
gap: 1rem;
padding: 0.75rem;
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.activity-item.selected {
background: rgba(16, 185, 129, 0.1);
border-color: #10b981;
}
.activity-item.conflicting {
opacity: 0.5;
}
.activity-time {
font-family: 'Courier New', monospace;
font-weight: 600;
flex-shrink: 0;
}
.activity-name {
flex: 1;
}
.activity-rule {
text-align: center;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.activity-result {
text-align: center;
font-size: 1rem;
}
.shortest-demo {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
@media (max-width: 768px) {
.shortest-demo {
grid-template-columns: 1fr;
}
}
.path-graph {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 1rem;
}
.graph-nodes {
display: flex;
justify-content: space-around;
margin-bottom: 1rem;
}
.node {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.85rem;
}
.node.start {
background: rgba(16, 185, 129, 0.1);
border-color: #10b981;
font-weight: 600;
}
.node.end {
background: rgba(59, 130, 246, 0.1);
border-color: #3b82f6;
font-weight: 600;
}
.graph-edges {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.edge {
font-size: 0.8rem;
color: var(--vp-c-text-2);
text-align: center;
}
.path-result {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.result-step {
font-size: 0.9rem;
color: var(--vp-c-text-2);
}
.result-path {
font-size: 1.1rem;
font-weight: 600;
color: var(--vp-c-brand);
text-align: center;
}
.result-distance {
text-align: center;
font-size: 0.95rem;
}
.comparison {
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-table table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.comparison-table td {
padding: 0.75rem;
border: 1px solid var(--vp-c-divider);
text-align: center;
font-size: 0.85rem;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
@media (max-width: 768px) {
.pros-cons {
grid-template-columns: 1fr;
}
}
.pros-column,
.cons-column {
padding: 1.25rem;
border-radius: 8px;
}
.pros-column {
background: rgba(16, 185, 129, 0.1);
border: 1px solid #10b981;
}
.cons-column {
background: rgba(239, 68, 68, 0.1);
border: 1px solid #ef4444;
}
.column-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
}
.pros-column ul,
.cons-column ul {
margin: 0;
padding-left: 1.25rem;
}
.pros-column li,
.cons-column li {
font-size: 0.9rem;
line-height: 1.8;
}
</style>
@@ -0,0 +1,434 @@
<template>
<div class="hash-table-demo">
<div class="demo-header">
<span class="icon">🗂</span>
<span class="title">哈希表超快的查找</span>
<span class="subtitle">通过关键词直接找到数据</span>
</div>
<div class="analogy-box">
<div class="analogy-icon">📚</div>
<div class="analogy-text">
哈希表就像图书馆的<strong>索引卡片</strong>不用在一排排书架上找直接查索引就能找到书的位置
</div>
</div>
<div class="hash-visual">
<div class="input-section">
<div class="section-title">存储数据</div>
<div class="input-group">
<input
v-model="newKey"
type="text"
placeholder="键 (如: apple)"
class="hash-input"
/>
<input
v-model="newValue"
type="text"
placeholder="值 (如: 苹果)"
class="hash-input"
/>
<button @click="addData" class="add-btn">
添加
</button>
</div>
</div>
<div class="hash-process">
<div class="process-title">哈希过程</div>
<div class="process-diagram">
<div class="process-step">
<div class="step-label">输入键</div>
<div class="step-box">{{ exampleKey }}</div>
</div>
<div class="process-arrow"></div>
<div class="process-step">
<div class="step-label">哈希函数</div>
<div class="step-box func">hash(key) % 10</div>
</div>
<div class="process-arrow"></div>
<div class="process-step">
<div class="step-label">数组索引</div>
<div class="step-box index">{{ exampleIndex }}</div>
</div>
</div>
</div>
<div class="hash-table-display">
<div class="section-title">哈希表</div>
<div class="table-slots">
<div
v-for="(slot, index) in hashTable"
:key="index"
:class="['table-slot', { occupied: slot !== null, highlighted: index === exampleIndex }]"
>
<div class="slot-index">{{ index }}</div>
<div class="slot-value">{{ slot || '空' }}</div>
</div>
</div>
</div>
</div>
<div class="performance-comparison">
<div class="comparison-title">性能对比</div>
<div class="comparison-grid">
<div class="comparison-item">
<div class="item-label">哈希表查找</div>
<div class="item-value excellent">O(1)</div>
<div class="item-desc">瞬间找到</div>
</div>
<div class="comparison-item">
<div class="item-label">数组查找</div>
<div class="item-value good">O(n)</div>
<div class="item-desc">需要遍历</div>
</div>
<div class="comparison-item">
<div class="item-label">二分查找</div>
<div class="item-value better">O(log n)</div>
<div class="item-desc">需要排序</div>
</div>
</div>
</div>
<div class="applications">
<div class="app-title">常见应用</div>
<div class="app-list">
<div class="app-item">
<span class="app-icon">👤</span>
<div class="app-text">用户信息表用户ID 用户资料</div>
</div>
<div class="app-item">
<span class="app-icon">🛒</span>
<div class="app-text">购物车商品ID 数量</div>
</div>
<div class="app-item">
<span class="app-icon">📝</span>
<div class="app-text">缓存系统URL 网页内容</div>
</div>
<div class="app-item">
<span class="app-icon">🔍</span>
<div class="app-text">字典单词 释义</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const newKey = ref('')
const newValue = ref('')
const exampleKey = ref('apple')
const hashTable = ref([null, null, null, null, null, null, null, null, null, null])
// 初始化一些数据
const initData = () => {
const data = [
{ key: 'apple', value: '苹果' },
{ key: 'banana', value: '香蕉' },
{ key: 'orange', value: '橙子' }
]
data.forEach(item => {
const index = simpleHash(item.key)
hashTable.value[index] = `${item.key}: ${item.value}`
})
}
const simpleHash = (key) => {
let hash = 0
for (let i = 0; i < key.length; i++) {
hash += key.charCodeAt(i)
}
return hash % 10
}
const exampleIndex = computed(() => simpleHash(exampleKey.value))
const addData = () => {
if (newKey.value && newValue.value) {
const index = simpleHash(newKey.value)
hashTable.value[index] = `${newKey.value}: ${newValue.value}`
newKey.value = ''
newValue.value = ''
}
}
initData()
</script>
<style scoped>
.hash-table-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.analogy-box {
display: flex;
gap: 1rem;
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
margin-bottom: 2rem;
}
.analogy-icon {
font-size: 2rem;
flex-shrink: 0;
}
.analogy-text {
font-size: 0.9rem;
line-height: 1.6;
}
.hash-visual {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
@media (max-width: 768px) {
.hash-visual {
grid-template-columns: 1fr;
}
}
.section-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.input-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.hash-input {
padding: 0.75rem;
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
}
.add-btn {
padding: 0.75rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.add-btn:hover {
transform: translateY(-2px);
}
.process-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.process-diagram {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.75rem;
}
.process-step {
text-align: center;
}
.step-label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.step-box {
padding: 0.75rem 1.5rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
}
.step-box.func {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
color: var(--vp-c-brand);
}
.step-box.index {
background: #10b981;
border-color: #10b981;
color: white;
}
.process-arrow {
font-size: 1.5rem;
color: var(--vp-c-text-2);
}
.hash-table-display {
grid-column: 1 / -1;
}
.table-slots {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 0.75rem;
}
.table-slot {
text-align: center;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
}
.table-slot.occupied {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
}
.table-slot.highlighted {
border-color: #10b981;
background: rgba(16, 185, 129, 0.1);
}
.slot-index {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.slot-value {
font-size: 0.85rem;
font-weight: 600;
}
.performance-comparison {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.comparison-item {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.item-label {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.item-value {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.35rem;
}
.item-value.excellent {
color: #10b981;
}
.item-value.good {
color: var(--vp-c-brand);
}
.item-value.better {
color: #f59e0b;
}
.item-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.applications {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.app-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.app-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 0.75rem;
}
.app-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.app-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.app-text {
font-size: 0.85rem;
color: var(--vp-c-text-1);
}
</style>
@@ -0,0 +1,514 @@
<template>
<div class="language-evolution-demo">
<div class="demo-header">
<span class="icon">📜</span>
<span class="title">编程语言的演化</span>
<span class="subtitle">从机器语言到高级语言</span>
</div>
<div class="evolution-timeline">
<div class="timeline-track">
<div
v-for="(era, index) in eras"
:key="index"
:class="['era-marker', { active: activeEra === index }]"
:style="{ left: era.position }"
@click="activeEra = index"
>
<div class="marker-dot"></div>
<div class="marker-label">{{ era.name }}</div>
</div>
</div>
</div>
<div class="era-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentEra.icon }}</span>
<span class="detail-title">{{ currentEra.fullname }}</span>
<span class="detail-years">{{ currentEra.years }}</span>
</div>
<div class="detail-content">
<div class="content-section">
<div class="section-title">代码示例</div>
<div class="code-example">
<pre><code>{{ currentEra.example }}</code></pre>
</div>
</div>
<div class="content-section">
<div class="section-title">特点</div>
<div class="features-list">
<div
v-for="(feature, index) in currentEra.features"
:key="index"
class="feature-item"
>
<span class="feature-icon"></span>
<span class="feature-text">{{ feature }}</span>
</div>
</div>
</div>
<div class="content-section">
<div class="section-title">优缺点</div>
<div class="pros-cons">
<div class="pros">
<div class="list-title"> 优点</div>
<ul>
<li v-for="(pro, index) in currentEra.pros" :key="index">{{ pro }}</li>
</ul>
</div>
<div class="cons">
<div class="list-title"> 缺点</div>
<ul>
<li v-for="(con, index) in currentEra.cons" :key="index">{{ con }}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- 演化总结 -->
<div class="evolution-summary">
<div class="summary-title">演化的趋势</div>
<div class="trend-grid">
<div class="trend-card">
<div class="trend-icon">🚀</div>
<div class="trend-title">越来越抽象</div>
<div class="trend-desc">远离硬件细节更接近人类思维</div>
</div>
<div class="trend-card">
<div class="trend-icon">👥</div>
<div class="trend-title">越来越易用</div>
<div class="trend-desc">语法更简洁学习曲线更平缓</div>
</div>
<div class="trend-card">
<div class="trend-icon">🛡</div>
<div class="trend-title">越来越安全</div>
<div class="trend-desc">类型系统内存管理等安全机制</div>
</div>
<div class="trend-card">
<div class="trend-icon"></div>
<div class="trend-title">越来越高效</div>
<div class="trend-desc">编译器优化JIT 技术提升性能</div>
</div>
</div>
</div>
<!-- 现代语言生态 -->
<div class="modern-languages">
<div class="modern-title">现代编程语言生态</div>
<div class="language-grid">
<div
v-for="lang in modernLanguages"
:key="lang.name"
class="lang-card"
>
<div class="lang-name">{{ lang.name }}</div>
<div class="lang-year">{{ lang.year }}</div>
<div class="lang-uses">
<span
v-for="(use, index) in lang.uses"
:key="index"
class="use-tag"
>
{{ use }}
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeEra = ref(3)
const eras = [
{
name: '机器语言',
fullname: '机器语言时代',
years: '1940s - 1950s',
icon: '0️⃣',
position: '5%',
example: '10110000 11000000\n(add two numbers)',
features: [
'直接用二进制代码',
'机器可以直接执行',
'完全依赖硬件'
],
pros: ['执行速度最快', '直接控制硬件'],
cons: ['极难编写', '容易出错', '不可移植']
},
{
name: '汇编语言',
fullname: '汇编语言时代',
years: '1950s - 1960s',
icon: '🔧',
position: '25%',
example: 'MOV AX, 5\nADD AX, 3\n(add 5 and 3)',
features: [
'用助记符代替二进制',
'需要汇编器翻译',
'仍然依赖硬件'
],
pros: ['比机器语言好懂', '效率仍然很高'],
cons: ['代码冗长', '不可移植', '需要了解硬件']
},
{
name: '面向过程',
fullname: '面向过程语言',
years: '1970s - 1980s',
icon: '📋',
position: '50%',
example: 'int add(int a, int b) {\n return a + b;\n}',
features: [
'函数、变量等抽象',
'结构化编程',
'可移植性好'
],
pros: ['易读易写', '可移植', '效率较高'],
cons: ['大型项目难以维护', '代码重用性差']
},
{
name: '面向对象',
fullname: '面向对象语言',
years: '1990s - 2000s',
icon: '🎯',
position: '75%',
example: 'class Calculator {\n add(a, b) { return a + b; }\n}',
features: [
'类、对象、封装、继承',
'模块化设计',
'代码复用性强'
],
pros: ['适合大型项目', '易维护', '可扩展'],
cons: ['学习曲线陡', '代码量较大']
},
{
name: '现代语言',
fullname: '现代多范式语言',
years: '2010s - 现在',
icon: '🚀',
position: '95%',
example: 'const add = (a, b) => a + b;\n(add arrow function)',
features: [
'简洁优雅的语法',
'多范式支持',
'强大的标准库'
],
pros: ['开发效率高', '生态丰富', '社区活跃'],
cons: ['抽象层多', '性能可能不如底层语言']
}
]
const modernLanguages = [
{ name: 'Python', year: '1991', uses: ['AI/ML', '数据分析', 'Web'] },
{ name: 'JavaScript', year: '1995', uses: ['Web', 'Node.js', '前端'] },
{ name: 'Rust', year: '2010', uses: ['系统', 'WebAssembly', '性能'] },
{ name: 'Go', year: '2009', uses: ['后端', '云', '微服务'] },
{ name: 'TypeScript', year: '2012', uses: ['Web', '大型项目'] },
{ name: 'Swift', year: '2014', uses: ['iOS', 'macOS'] }
]
const currentEra = computed(() => eras[activeEra.value])
</script>
<style scoped>
.language-evolution-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.evolution-timeline {
background: var(--vp-c-bg);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.timeline-track {
position: relative;
height: 60px;
border-top: 3px solid var(--vp-c-divider);
}
.era-marker {
position: absolute;
top: -10px;
transform: translateX(-50%);
cursor: pointer;
transition: all 0.3s;
}
.marker-dot {
width: 20px;
height: 20px;
background: var(--vp-c-divider);
border: 3px solid var(--vp-c-bg);
border-radius: 50%;
margin: 0 auto 0.5rem;
transition: all 0.3s;
}
.era-marker:hover .marker-dot,
.era-marker.active .marker-dot {
background: var(--vp-c-brand);
transform: scale(1.3);
}
.marker-label {
font-size: 0.75rem;
font-weight: 600;
text-align: center;
}
.era-marker.active .marker-label {
color: var(--vp-c-brand);
}
.era-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-years {
margin-left: auto;
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.content-section {}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.code-example {
background: #1e1e1e;
border-radius: 6px;
padding: 1rem;
overflow-x: auto;
}
.code-example pre {
margin: 0;
color: #d4d4d4;
font-size: 0.8rem;
line-height: 1.6;
}
.features-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.feature-item {
display: flex;
gap: 0.75rem;
align-items: center;
}
.feature-icon {
color: #10b981;
font-weight: 700;
}
.feature-text {
font-size: 0.9rem;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
@media (max-width: 768px) {
.pros-cons {
grid-template-columns: 1fr;
}
}
.pros,
.cons {
padding: 1rem;
border-radius: 6px;
}
.pros {
background: rgba(16, 185, 129, 0.1);
border: 1px solid #10b981;
}
.cons {
background: rgba(239, 68, 68, 0.1);
border: 1px solid #ef4444;
}
.list-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.75rem;
}
.pros ul,
.cons ul {
margin: 0;
padding-left: 1.25rem;
}
.pros li,
.cons li {
font-size: 0.85rem;
line-height: 1.8;
}
.evolution-summary {
margin-bottom: 2rem;
}
.summary-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.trend-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.trend-card {
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.trend-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.trend-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.trend-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.modern-languages {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.modern-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.language-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.lang-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.lang-name {
font-weight: 700;
font-size: 1rem;
margin-bottom: 0.35rem;
color: var(--vp-c-brand);
}
.lang-year {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.75rem;
}
.lang-uses {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
justify-content: center;
}
.use-tag {
padding: 0.25rem 0.5rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 10px;
font-size: 0.7rem;
}
</style>
@@ -0,0 +1,505 @@
<template>
<div class="language-scenario-demo">
<div class="demo-header">
<span class="icon">🎬</span>
<span class="title">为什么需要编程语言</span>
<span class="subtitle">从场景看编程语言的价值</span>
</div>
<div class="scenario-intro">
编程语言是<strong>人类思维</strong><strong>计算机执行</strong>之间的桥梁
</div>
<div class="scenario-cards">
<div
v-for="scenario in scenarios"
:key="scenario.id"
:class="['scenario-card', { active: activeScenario === scenario.id }]"
@click="activeScenario = scenario.id"
>
<div class="card-icon">{{ scenario.icon }}</div>
<div class="card-title">{{ scenario.title }}</div>
<div class="card-desc">{{ scenario.desc }}</div>
</div>
</div>
<!-- 场景详解 -->
<div v-if="activeScenario" class="scenario-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentScenario.icon }}</span>
<span class="detail-title">{{ currentScenario.title }}</span>
</div>
<div class="detail-content">
<div class="detail-section">
<div class="section-title">场景描述</div>
<div class="section-text">{{ currentScenario.fullDesc }}</div>
</div>
<div class="detail-section">
<div class="section-title">为什么需要编程语言</div>
<div class="reason-steps">
<div
v-for="(step, index) in currentScenario.reasons"
:key="index"
class="reason-step"
>
<div class="step-number">{{ index + 1 }}</div>
<div class="step-text">{{ step }}</div>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">不用编程语言会怎样</div>
<div class="without-code">
<div class="without-box">
<div class="without-icon">😰</div>
<div class="without-text">{{ currentScenario.withoutLang }}</div>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">适合的语言</div>
<div class="lang-tags">
<span
v-for="(lang, index) in currentScenario.languages"
:key="index"
class="lang-tag"
>
{{ lang }}
</span>
</div>
</div>
</div>
</div>
<!-- 编程语言的作用 -->
<div class="language-role">
<div class="role-title">编程语言的三大作用</div>
<div class="role-grid">
<div class="role-card">
<div class="role-icon">💬</div>
<div class="role-title">表达思想</div>
<div class="role-desc">将人类思维转化为计算机可理解的指令</div>
</div>
<div class="role-card">
<div class="role-icon">🔧</div>
<div class="role-title">控制硬件</div>
<div class="role-desc">精确控制计算机执行各种操作</div>
</div>
<div class="role-card">
<div class="role-icon">🤝</div>
<div class="role-title">团队协作</div>
<div class="role-desc">标准化的语法便于多人协作开发</div>
</div>
</div>
</div>
<!-- 演化历程 -->
<div class="evolution">
<div class="evolution-title">从机器码到高级语言</div>
<div class="evolution-steps">
<div class="evo-step">
<div class="evo-level">低级</div>
<div class="evo-name">机器语言</div>
<div class="evo-arrow"></div>
</div>
<div class="evo-step">
<div class="evo-level">低级</div>
<div class="evo-name">汇编语言</div>
<div class="evo-arrow"></div>
</div>
<div class="evo-step">
<div class="evo-level">中级</div>
<div class="evo-name">C 语言</div>
<div class="evo-arrow"></div>
</div>
<div class="evo-step">
<div class="evo-level">高级</div>
<div class="evo-name">现代语言</div>
<div class="evo-arrow"></div>
</div>
<div class="evo-result">
越来越接近<br>人类思维
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeScenario = ref('web')
const scenarios = [
{
id: 'web',
icon: '🌐',
title: '开发网站',
desc: '创建交互式网页',
fullDesc: '你需要创建一个在线购物网站,用户可以浏览商品、加入购物车、下单支付',
reasons: [
'HTML 定义网页结构',
'CSS 实现美观样式',
'JavaScript 实现交互功能',
'Python/Node.js 处理后端逻辑'
],
withoutLang: '只能手工编写网页,无法实现动态内容和用户交互',
languages: ['JavaScript', 'HTML', 'CSS', 'Python', 'TypeScript']
},
{
id: 'mobile',
icon: '📱',
title: '开发 App',
desc: '创建手机应用',
fullDesc: '开发一个功能丰富的手机应用,支持 iOS 和 Android 平台',
reasons: [
'Swift/Kotlin 提供原生体验',
'React Native 实现跨平台',
'编程语言调用设备功能',
'管理应用状态和数据'
],
withoutLang: '无法创建手机应用,只能使用系统自带的功能',
languages: ['Swift', 'Kotlin', 'React Native', 'Flutter']
},
{
id: 'data',
icon: '📊',
title: '数据分析',
desc: '处理和分析大量数据',
fullDesc: '分析百万级用户数据,找出行为模式和趋势',
reasons: [
'Python 提供丰富的数据科学库',
'简洁的语法便于快速迭代',
'强大的数据处理能力',
'可视化工具支持'
],
withoutLang: '手工计算几乎不可能,需要几天才能完成分析',
languages: ['Python', 'R', 'SQL', 'Julia']
},
{
id: 'system',
icon: '⚙️',
title: '系统编程',
desc: '编写操作系统和驱动',
fullDesc: '开发操作系统内核、设备驱动等底层软件',
reasons: [
'C/C++ 提供底层访问能力',
'精确控制内存管理',
'高效的执行性能',
'直接操作硬件'
],
withoutLang: '无法控制系统硬件,只能使用现有的操作系统功能',
languages: ['C', 'C++', 'Rust', 'Assembly']
},
{
id: 'ai',
icon: '🤖',
title: '人工智能',
desc: '训练机器学习模型',
fullDesc: '构建深度学习模型,识别图像、理解自然语言',
reasons: [
'Python 拥有丰富的 AI 框架',
'简洁的数学表达',
'GPU 加速支持',
'庞大的社区支持'
],
withoutLang: '无法实现复杂的 AI 算法,只能使用简单的规则',
languages: ['Python', 'R', 'Julia', 'C++']
}
]
const currentScenario = computed(() => scenarios.find(s => s.id === activeScenario.value))
</script>
<style scoped>
.language-scenario-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.scenario-intro {
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
margin-bottom: 2rem;
font-size: 0.95rem;
line-height: 1.6;
}
.scenario-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.scenario-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.scenario-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.scenario-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.card-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.scenario-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.detail-section {}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.section-text {
font-size: 0.9rem;
line-height: 1.6;
}
.reason-steps {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.reason-step {
display: flex;
gap: 0.75rem;
align-items: start;
}
.step-number {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
flex-shrink: 0;
}
.step-text {
font-size: 0.85rem;
line-height: 1.5;
padding-top: 0.15rem;
}
.without-code {
text-align: center;
}
.without-box {
display: inline-flex;
gap: 0.75rem;
align-items: center;
padding: 0.75rem 1rem;
background: rgba(239, 68, 68, 0.1);
border: 1px solid #ef4444;
border-radius: 6px;
}
.without-icon {
font-size: 1.5rem;
}
.without-text {
font-size: 0.85rem;
color: #ef4444;
}
.lang-tags {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.lang-tag {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.85rem;
}
.language-role {
margin-bottom: 2rem;
}
.role-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.role-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.role-card {
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.role-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.role-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.role-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.evolution {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.evolution-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.evolution-steps {
display: flex;
align-items: center;
justify-content: center;
gap: 1.5rem;
flex-wrap: wrap;
}
.evo-step {
text-align: center;
}
.evo-level {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.evo-name {
padding: 0.5rem 1rem;
background: var(--vp-c-brand-soft);
border: 1px solid var(--vp-c-brand);
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
.evo-arrow {
font-size: 1.2rem;
color: var(--vp-c-brand);
}
.evo-result {
padding: 0.75rem 1rem;
background: #10b981;
color: white;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
text-align: center;
}
</style>
@@ -0,0 +1,255 @@
<template>
<div class="language-type-model-demo">
<div class="demo-header">
<span class="icon">🏗</span>
<span class="title">编程语言的类型模型</span>
<span class="subtitle">不同语言的类型系统差异</span>
</div>
<div class="dimension-grid">
<div
v-for="dim in dimensions"
:key="dim.id"
class="dimension-card"
>
<div class="card-title">{{ dim.title }}</div>
<div class="card-options">
<div
v-for="opt in dim.options"
:key="opt.name"
class="option-item"
>
<div class="option-name">{{ opt.name }}</div>
<div class="option-langs">{{ opt.langs }}</div>
</div>
</div>
</div>
</div>
<div class="quadrant-matrix">
<div class="matrix-title">类型系统分类矩阵</div>
<div class="matrix-grid">
<div class="matrix-cell">
<div class="cell-title">静态 + </div>
<div class="cell-langs">Java, C++, Rust, Go</div>
<div class="cell-desc">编译期检查类型安全</div>
</div>
<div class="matrix-cell">
<div class="cell-title">静态 + </div>
<div class="cell-langs">C</div>
<div class="cell-desc">编译期检查可随意转换</div>
</div>
<div class="matrix-cell">
<div class="cell-title">动态 + </div>
<div class="cell-langs">Python, Ruby</div>
<div class="cell-desc">运行时检查类型安全</div>
</div>
<div class="matrix-cell">
<div class="cell-title">动态 + </div>
<div class="cell-langs">JavaScript, PHP</div>
<div class="cell-desc">运行时检查类型灵活</div>
</div>
</div>
</div>
<div class="type-inference">
<div class="inference-title">类型推断</div>
<div class="inference-content">
<div class="inference-desc">
现代语言可以自动推断变量类型无需显式声明
</div>
<div class="inference-examples">
<div class="example-lang">
<div class="lang-header">TypeScript</div>
<pre><code>let x = 5; // 推断为 number
let name = "Alice"; // string</code></pre>
</div>
<div class="example-lang">
<div class="lang-header">Rust</div>
<pre><code>let x = 5; // 推断为 i32
let name = "Alice"; // &str</code></pre>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const dimensions = [
{
id: 'static',
title: '类型检查时机',
options: [
{ name: '静态类型', langs: 'Java, C++, Rust, Go' },
{ name: '动态类型', langs: 'Python, JavaScript, Ruby' }
]
},
{
id: 'strength',
title: '类型强度',
options: [
{ name: '强类型', langs: 'Python, Java, Rust' },
{ name: '弱类型', langs: 'JavaScript, C, PHP' }
]
}
]
</script>
<style scoped>
.language-type-model-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.dimension-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.dimension-card {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.25rem;
}
.card-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.card-options {
display: flex;
flex-direction: column;
gap: 1rem;
}
.option-item {
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.option-name {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.option-langs {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.quadrant-matrix {
margin-bottom: 2rem;
}
.matrix-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.matrix-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.matrix-cell {
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.cell-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.cell-langs {
font-size: 0.85rem;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.cell-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.type-inference {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.inference-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.inference-desc {
font-size: 0.9rem;
margin-bottom: 1rem;
line-height: 1.6;
}
.inference-examples {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
.example-lang {
background: #1e1e1e;
border-radius: 6px;
overflow: hidden;
}
.lang-header {
background: var(--vp-c-brand);
color: white;
padding: 0.5rem;
font-size: 0.85rem;
font-weight: 600;
}
.example-lang pre {
margin: 0;
padding: 1rem;
}
.example-lang code {
color: #d4d4d4;
font-size: 0.75rem;
line-height: 1.6;
}
</style>
@@ -0,0 +1,579 @@
<template>
<div class="linear-structures-demo">
<div class="demo-header">
<span class="icon">📚</span>
<span class="title">线性结构的四种形态</span>
<span class="subtitle">数组链表队列的区别</span>
</div>
<div class="structure-tabs">
<button
v-for="structure in structures"
:key="structure.id"
:class="['tab-btn', { active: activeStructure === structure.id }]"
@click="activeStructure = structure.id"
>
{{ structure.icon }} {{ structure.name }}
</button>
</div>
<!-- 可视化展示 -->
<div class="structure-visual">
<div class="visual-header">
<span class="structure-title">{{ currentStructure.name }}</span>
<span class="structure-tagline">{{ currentStructure.tagline }}</span>
</div>
<!-- 数组 -->
<div v-if="activeStructure === 'array'" class="array-visual">
<div class="memory-block">
<div
v-for="(item, index) in arrayData"
:key="index"
class="array-cell"
>
<div class="cell-index">{{ index }}</div>
<div class="cell-value">{{ item }}</div>
</div>
</div>
<div class="visual-note">
连续内存存储 | 快速访问 (O(1)) | 插入删除慢 (O(n))
</div>
</div>
<!-- 链表 -->
<div v-if="activeStructure === 'linkedlist'" class="linkedlist-visual">
<div class="nodes-chain">
<div
v-for="(item, index) in linkedListData"
:key="index"
class="linked-node"
>
<div class="node-data">{{ item }}</div>
<div class="node-pointer"></div>
</div>
<div class="linked-node null">
<div class="node-data">NULL</div>
</div>
</div>
<div class="visual-note">
非连续内存 | 访问慢 (O(n)) | 快速插入删除
</div>
</div>
<!-- -->
<div v-if="activeStructure === 'stack'" class="stack-visual">
<div class="stack-container">
<div class="stack-top">栈顶 </div>
<div class="stack-items">
<div
v-for="(item, index) in stackData"
:key="index"
class="stack-item"
>
{{ item }}
</div>
</div>
<div class="stack-bottom">栈底</div>
</div>
<div class="stack-operations">
<button class="op-btn" @click="pushStack">
入栈 (PUSH)
</button>
<button class="op-btn" @click="popStack">
出栈 (POP)
</button>
</div>
<div class="visual-note">
后进先出 (LIFO) | 应用撤销操作函数调用
</div>
</div>
<!-- 队列 -->
<div v-if="activeStructure === 'queue'" class="queue-visual">
<div class="queue-container">
<div class="queue-front">队首 </div>
<div class="queue-items">
<div
v-for="(item, index) in queueData"
:key="index"
class="queue-item"
>
{{ item }}
</div>
</div>
<div class="queue-rear"> 队尾</div>
</div>
<div class="queue-operations">
<button class="op-btn" @click="enqueue">
入队 (ENQUEUE)
</button>
<button class="op-btn" @click="dequeue">
出队 (DEQUEUE)
</button>
</div>
<div class="visual-note">
先进先出 (FIFO) | 应用任务队列打印队列
</div>
</div>
</div>
<!-- 对比表格 -->
<div class="comparison-table">
<div class="table-title">操作对比</div>
<table>
<thead>
<tr>
<th>数据结构</th>
<th>访问</th>
<th>插入</th>
<th>删除</th>
<th>特点</th>
</tr>
</thead>
<tbody>
<tr
v-for="struct in structures"
:key="struct.id"
:class="{ highlighted: struct.id === activeStructure }"
>
<td>{{ struct.icon }} {{ struct.name }}</td>
<td>{{ struct.access }}</td>
<td>{{ struct.insert }}</td>
<td>{{ struct.delete }}</td>
<td>{{ struct.feature }}</td>
</tr>
</tbody>
</table>
</div>
<!-- 应用场景 -->
<div class="applications">
<div class="app-title">实际应用场景</div>
<div class="app-list">
<div
v-for="(app, index) in currentStructure.applications"
:key="index"
class="app-card"
>
<div class="app-icon">{{ app.icon }}</div>
<div class="app-content">
<div class="app-name">{{ app.name }}</div>
<div class="app-desc">{{ app.desc }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeStructure = ref('array')
const structures = [
{
id: 'array',
name: '数组',
icon: '📊',
tagline: '连续内存,编号访问',
access: 'O(1) 快',
insert: 'O(n) 慢',
delete: 'O(n) 慢',
feature: '大小固定',
applications: [
{ icon: '📋', name: '列表数据', desc: '学生成绩、商品价格列表' },
{ icon: '🖼️', name: '图像处理', desc: '像素矩阵存储' },
{ icon: '📈', name: '统计图表', desc: '按时间顺序的数据' }
]
},
{
id: 'linkedlist',
name: '链表',
icon: '🔗',
tagline: '指针链接,灵活增删',
access: 'O(n) 慢',
insert: 'O(1) 快',
delete: 'O(1) 快',
feature: '大小可变',
applications: [
{ icon: '↩️', name: '撤销功能', desc: '操作历史记录' },
{ icon: '🎵', name: '音乐播放', desc: '播放列表' },
{ icon: '📝', name: '文本编辑', desc: '文档内容的动态存储' }
]
},
{
id: 'stack',
name: '栈',
icon: '🥞',
tagline: '后进先出',
access: 'O(n)',
insert: 'O(1) 快',
delete: 'O(1) 快',
feature: '一端操作',
applications: [
{ icon: '↩️', name: '撤销操作', desc: '编辑器的撤销功能' },
{ icon: '🔙', name: '浏览器历史', desc: '后退按钮实现' },
{ icon: '📞', name: '函数调用', desc: '程序调用栈管理' }
]
},
{
id: 'queue',
name: '队列',
icon: '🚶',
tagline: '先进先出',
access: 'O(n)',
insert: 'O(1) 快',
delete: 'O(1) 快',
feature: '两端操作',
applications: [
{ icon: '🖨️', name: '打印队列', desc: '文档按顺序打印' },
{ icon: '🎫', name: '任务调度', desc: '操作系统进程调度' },
{ icon: '💬', name: '消息队列', desc: '异步任务处理' }
]
}
]
const arrayData = ref([10, 25, 33, 47, 59, 62])
const linkedListData = ref(['A', 'B', 'C', 'D', 'E'])
const stackData = ref(['书5', '书4', '书3', '书2', '书1'])
const queueData = ref(['人1', '人2', '人3', '人4'])
const currentStructure = computed(() => structures.find(s => s.id === activeStructure.value))
const pushStack = () => {
const newItem = `${stackData.value.length + 1}`
stackData.value.unshift(newItem)
}
const popStack = () => {
if (stackData.value.length > 0) {
stackData.value.shift()
}
}
const enqueue = () => {
const newItem = `${queueData.value.length + 1}`
queueData.value.push(newItem)
}
const dequeue = () => {
if (queueData.value.length > 0) {
queueData.value.shift()
}
}
</script>
<style scoped>
.linear-structures-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.structure-tabs {
display: flex;
gap: 0.75rem;
margin-bottom: 2rem;
flex-wrap: wrap;
}
.tab-btn {
padding: 0.75rem 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s;
}
.tab-btn:hover {
border-color: var(--vp-c-brand);
}
.tab-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.structure-visual {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.visual-header {
text-align: center;
margin-bottom: 2rem;
}
.structure-title {
display: block;
font-size: 1.3rem;
font-weight: 700;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.structure-tagline {
font-size: 0.9rem;
color: var(--vp-c-text-2);
}
.memory-block {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.array-cell {
width: 70px;
text-align: center;
}
.cell-index {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.cell-value {
width: 70px;
height: 70px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand-soft);
border: 2px solid var(--vp-c-brand);
border-radius: 6px;
font-weight: 600;
font-size: 1rem;
}
.nodes-chain {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.linked-node {
display: flex;
align-items: center;
gap: 0.5rem;
}
.node-data {
width: 60px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand-soft);
border: 2px solid var(--vp-c-brand);
border-radius: 50%;
font-weight: 600;
font-size: 1rem;
}
.node-pointer {
font-size: 1.5rem;
color: var(--vp-c-brand);
}
.linked-node.null .node-data {
background: var(--vp-c-divider);
border-color: var(--vp-c-text-2);
}
.stack-container,
.queue-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.stack-top,
.queue-front {
font-size: 0.9rem;
color: var(--vp-c-brand);
font-weight: 600;
}
.stack-items,
.queue-items {
display: flex;
flex-direction: column;
gap: 0.5rem;
min-height: 150px;
}
.stack-item,
.queue-item {
width: 150px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand-soft);
border: 2px solid var(--vp-c-brand);
border-radius: 6px;
font-size: 0.9rem;
font-weight: 500;
}
.queue-items {
flex-direction: row;
}
.queue-item {
width: 80px;
}
.stack-bottom,
.queue-rear {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.stack-operations,
.queue-operations {
display: flex;
gap: 1rem;
justify-content: center;
margin-bottom: 1.5rem;
}
.op-btn {
padding: 0.6rem 1.25rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.op-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.visual-note {
text-align: center;
font-size: 0.85rem;
color: var(--vp-c-text-2);
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.comparison-table {
margin-bottom: 2rem;
}
.table-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
td {
padding: 0.75rem;
text-align: center;
border-bottom: 1px solid var(--vp-c-divider);
font-size: 0.85rem;
}
tr.highlighted {
background: var(--vp-c-brand-soft);
}
.applications {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.app-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.app-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.app-card {
display: flex;
gap: 0.75rem;
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.app-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.app-content {
flex: 1;
}
.app-name {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.app-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
</style>
@@ -0,0 +1,474 @@
<template>
<div class="network-overview-demo">
<div class="demo-header">
<span class="icon">🌐</span>
<span class="title">网络是怎么连接的</span>
<span class="subtitle">从发送到接收的完整过程</span>
</div>
<div class="network-scene">
<div class="scene-devices">
<!-- 发送方 -->
<div class="device sender">
<div class="device-icon">💻</div>
<div class="device-name">发送方</div>
<div class="device-ip">192.168.1.100</div>
<div class="app-layer">
<div class="app-icon">📧</div>
<div class="app-name">邮件应用</div>
</div>
</div>
<!-- 网络路径 -->
<div class="network-path">
<div class="path-steps">
<div
v-for="(step, index) in pathSteps"
:key="index"
:class="['path-step', { active: activeStep === index }]"
@click="activeStep = index"
>
<div class="step-icon">{{ step.icon }}</div>
<div class="step-name">{{ step.name }}</div>
<div class="step-desc">{{ step.desc }}</div>
</div>
</div>
<div class="data-flow">
<div v-if="activeStep !== null" class="flow-animation">
<div class="flow-packet">📦 数据包</div>
</div>
</div>
</div>
<!-- 接收方 -->
<div class="device receiver">
<div class="device-icon">🖥</div>
<div class="device-name">接收方</div>
<div class="device-ip">192.168.1.200</div>
<div class="app-layer">
<div class="app-icon">📧</div>
<div class="app-name">邮件应用</div>
</div>
</div>
</div>
</div>
<!-- 封装过程 -->
<div class="encapsulation-process">
<div class="process-title">数据封装过程</div>
<div class="encapsulation-layers">
<div
v-for="(layer, index) in encapsulationLayers"
:key="index"
:class="['encap-layer', { active: activeStep === index }]"
>
<div class="layer-header">
<span class="layer-num">{{ layer.num }}</span>
<span class="layer-name">{{ layer.name }}</span>
</div>
<div class="layer-content">
<div class="layer-data">{{ layer.data }}</div>
</div>
</div>
</div>
</div>
<!-- 协议栈 -->
<div class="protocol-stack">
<div class="stack-title">网络协议栈 (OSI 模型)</div>
<div class="stack-container">
<div class="stack-column sender-stack">
<div class="stack-header">发送方</div>
<div
v-for="(layer, index) in protocolLayers"
:key="'sender-' + index"
:class="['stack-layer', { highlighted: activeStep === index }]"
>
{{ layer }}
</div>
</div>
<div class="stack-arrow"></div>
<div class="stack-column receiver-stack">
<div class="stack-header">接收方</div>
<div
v-for="(layer, index) in protocolLayers"
:key="'receiver-' + index"
:class="['stack-layer', { highlighted: activeStep === index }]"
>
{{ layer }}
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeStep = ref(null)
const pathSteps = [
{
icon: '📧',
name: '应用层',
desc: '邮件软件创建邮件内容'
},
{
icon: '🔐',
name: '传输层',
desc: 'TCP 添加端口号和序号'
},
{
icon: '🌐',
name: '网络层',
desc: 'IP 添加源地址和目标地址'
},
{
icon: '🔌',
name: '数据链路层',
desc: '以太网添加 MAC 地址'
},
{
icon: '⚡',
name: '物理层',
desc: '转换成电信号发送'
}
]
const encapsulationLayers = [
{
num: '7',
name: '应用层',
data: '邮件内容: "Hello!"'
},
{
num: '6',
name: '表示层',
data: '数据编码: UTF-8'
},
{
num: '5',
name: '会话层',
data: '会话ID: sess_123'
},
{
num: '4',
name: '传输层',
data: 'TCP 头: 端口 25'
},
{
num: '3',
name: '网络层',
data: 'IP 头: 192.168.1.100 → 192.168.1.200'
},
{
num: '2',
name: '数据链路层',
data: '以太网帧: MAC 地址'
},
{
num: '1',
name: '物理层',
data: '比特流: 01010101...'
}
]
const protocolLayers = [
'应用层 (HTTP, SMTP)',
'传输层 (TCP, UDP)',
'网络层 (IP)',
'数据链路层 (Ethernet)',
'物理层 (电信号)'
]
</script>
<style scoped>
.network-overview-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.network-scene {
margin-bottom: 2rem;
}
.scene-devices {
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
}
.device {
flex: 1;
max-width: 200px;
text-align: center;
padding: 1.5rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
}
.device-icon {
font-size: 3rem;
margin-bottom: 0.75rem;
}
.device-name {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.5rem;
}
.device-ip {
font-family: 'Courier New', monospace;
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 1rem;
}
.app-layer {
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
padding: 0.75rem;
background: var(--vp-c-brand-soft);
border-radius: 6px;
}
.app-icon { font-size: 1.5rem; }
.app-name { font-size: 0.8rem; font-weight: 600; color: var(--vp-c-brand); }
.network-path {
flex: 1;
display: flex;
flex-direction: column;
gap: 1rem;
}
.path-steps {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.path-step {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.path-step:hover {
border-color: var(--vp-c-brand);
}
.path-step.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.step-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.step-name {
font-weight: 600;
font-size: 0.9rem;
flex-shrink: 0;
}
.step-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.data-flow {
text-align: center;
padding: 0.5rem;
}
.flow-animation {
animation: flowMove 2s ease-in-out infinite;
}
@keyframes flowMove {
0%, 100% { transform: translateX(-20px); opacity: 0; }
50% { transform: translateX(20px); opacity: 1; }
}
.flow-packet {
display: inline-block;
padding: 0.5rem 1rem;
background: var(--vp-c-brand);
color: white;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 600;
}
.encapsulation-process {
margin-bottom: 2rem;
}
.process-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.encapsulation-layers {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.encap-layer {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.encap-layer.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.layer-header {
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 150px;
}
.layer-num {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
}
.layer-name {
font-weight: 600;
font-size: 0.85rem;
}
.layer-content {
flex: 1;
}
.layer-data {
font-family: 'Courier New', monospace;
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.protocol-stack {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.stack-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.stack-container {
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
}
.stack-column {
flex: 1;
max-width: 250px;
}
.stack-header {
text-align: center;
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.stack-layer {
padding: 0.6rem;
margin-bottom: 0.5rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
font-size: 0.8rem;
text-align: center;
transition: all 0.3s;
}
.stack-layer.highlighted {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
font-weight: 600;
}
.stack-arrow {
font-size: 2rem;
color: var(--vp-c-brand);
}
@media (max-width: 968px) {
.scene-devices {
flex-direction: column;
}
.network-path {
width: 100%;
}
.stack-container {
flex-direction: column;
gap: 1rem;
}
.stack-arrow {
transform: rotate(90deg);
}
}
</style>
@@ -0,0 +1,236 @@
<template>
<div class="network-principle-demo">
<div class="demo-header">
<span class="icon">🌐</span>
<span class="title">网络基本原理</span>
<span class="subtitle">数据如何在网络中传输</span>
</div>
<div class="principle-cards">
<div
v-for="(principle, index) in principles"
:key="index"
class="principle-card"
>
<div class="card-icon">{{ principle.icon }}</div>
<div class="card-title">{{ principle.title }}</div>
<div class="card-desc">{{ principle.desc }}</div>
</div>
</div>
<div class="data-flow">
<div class="flow-title">数据传输流程</div>
<div class="flow-diagram">
<div class="flow-step">
<div class="step-icon">📤</div>
<div class="step-text">发送方</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="step-icon">📦</div>
<div class="step-text">封装数据包</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="step-icon">🌐</div>
<div class="step-text">网络传输</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="step-icon">📥</div>
<div class="step-text">接收方</div>
</div>
</div>
</div>
<div class="key-concepts">
<div class="concepts-title">核心概念</div>
<div class="concepts-list">
<div class="concept-item">
<div class="concept-name">IP 地址</div>
<div class="concept-value">192.168.1.100</div>
<div class="concept-desc">设备的网络地址</div>
</div>
<div class="concept-item">
<div class="concept-name">端口</div>
<div class="concept-value">80, 443, 22</div>
<div class="concept-desc">应用程序的标识</div>
</div>
<div class="concept-item">
<div class="concept-name">协议</div>
<div class="concept-value">HTTP, TCP/IP</div>
<div class="concept-desc">通信的规则</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const principles = [
{
icon: '📡',
title: '分组交换',
desc: '数据被分成小块独立传输,然后重组'
},
{
icon: '🔄',
title: '路由转发',
desc: '路由器根据地址决定数据包的转发路径'
},
{
icon: '📋',
title: '协议分层',
desc: '不同层次负责不同的通信功能'
},
{
icon: '🔐',
title: '可靠传输',
desc: 'TCP 确保数据完整、有序地到达目的地'
}
]
</script>
<style scoped>
.network-principle-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.principle-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.principle-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.card-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.data-flow {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.flow-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
text-align: center;
color: var(--vp-c-brand);
}
.flow-diagram {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
flex-wrap: wrap;
}
.flow-step {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.step-icon {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.step-text {
font-size: 0.85rem;
font-weight: 600;
}
.flow-arrow {
font-size: 1.5rem;
color: var(--vp-c-brand);
}
.key-concepts {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.concepts-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
color: var(--vp-c-brand);
}
.concepts-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.concept-item {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
text-align: center;
}
.concept-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.concept-value {
font-family: 'Courier New', monospace;
font-size: 0.9rem;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.concept-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
</style>
@@ -0,0 +1,324 @@
<template>
<div class="os-overview-demo">
<div class="demo-header">
<span class="icon">🎛</span>
<span class="title">操作系统计算机的"大管家"</span>
<span class="subtitle">让多个程序和谐共处的艺术</span>
</div>
<div class="demo-content">
<div class="os-layers">
<div class="layer user-apps">
<div class="layer-title">
应用程序层
</div>
<div class="layer-content">
<div
v-for="app in applications"
:key="app.id"
class="app-icon"
:class="{ active: activeApp === app.id }"
@click="activeApp = app.id"
:title="app.name"
>
{{ app.icon }}
</div>
</div>
<div class="layer-desc">
用户直接使用的程序浏览器IDE游戏等
</div>
</div>
<div class="layer kernel">
<div class="layer-title">
操作系统内核
</div>
<div class="layer-content">
<div class="kernel-components">
<div
v-for="component in kernelComponents"
:key="component.id"
class="kernel-component"
:class="{ active: activeComponent === component.id }"
@click="activeComponent = component.id"
>
{{ component.icon }} {{ component.name }}
</div>
</div>
</div>
<div class="layer-desc">
进程管理内存管理文件系统设备管理
</div>
</div>
<div class="layer hardware">
<div class="layer-title">
硬件层
</div>
<div class="layer-content">
<div class="hardware-icons">
<span>💻 CPU</span>
<span>🧠 RAM</span>
<span>💾 硬盘</span>
<span>🖥 GPU</span>
</div>
</div>
</div>
</div>
<div class="resource-flow">
<div class="flow-title">资源流向</div>
<div class="flow-content">
<div class="flow-item" :class="{ active: showFlow }">
<div class="flow-arrow"></div>
<div class="flow-desc">
应用程序请求资源内存CPU文件
</div>
</div>
<div class="flow-item" :class="{ active: showFlow }">
<div class="flow-arrow"></div>
<div class="flow-desc">
操作系统内核统一分配和调度
</div>
</div>
<div class="flow-item" :class="{ active: showFlow }">
<div class="flow-arrow"></div>
<div class="flow-desc">
硬件执行实际操作
</div>
</div>
</div>
<button
class="flow-btn"
@click="showFlow = !showFlow"
>
{{ showFlow ? '隐藏' : '显示' }}资源流
</button>
</div>
<div class="demo-details">
<div class="detail-item">
<div class="detail-title">
当前选中{{ activeAppName || '请选择应用程序' }}
</div>
<div class="detail-desc">
{{ getActiveAppDesc() }}
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeApp = ref('browser')
const activeComponent = ref('process')
const showFlow = ref(false)
const applications = [
{ id: 'browser', name: '浏览器', icon: '🌐' },
{ id: 'ide', name: '代码编辑器', icon: '💻' },
{ id: 'music', name: '音乐播放器', icon: '🎵' },
{ id: 'video', name: '视频播放器', icon: '🎬' },
{ id: 'game', name: '游戏', icon: '🎮' }
]
const kernelComponents = [
{ id: 'process', name: '进程管理', icon: '🔄' },
{ id: 'memory', name: '内存管理', icon: '🧠' },
{ id: 'filesystem', name: '文件系统', icon: '📁' },
{ id: 'device', name: '设备管理', icon: '🔧' }
]
const activeAppName = computed(() => {
const app = applications.find(a => a.id === activeApp.value)
return app?.name || ''
})
const getActiveAppDesc = () => {
const component = kernelComponents.find(c => c.id === activeComponent.value)
const app = applications.find(a => a.id === activeApp.value)
if (!app || !component) return '请选择应用程序和内核组件'
return `${app.name} 需要使用 ${component.name} 的功能`
}
</script>
<style scoped>
.os-overview-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.os-layers {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
}
.layer {
padding: 1rem;
border-radius: 8px;
border: 2px solid var(--vp-c-divider);
transition: all 0.3s;
}
.layer.user-apps {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.layer.kernel {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
}
.layer.hardware {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
}
.layer-title {
font-weight: 600;
margin-bottom: 0.75rem;
font-size: 1rem;
}
.layer-content {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.app-icon {
font-size: 1.8rem;
padding: 0.5rem;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.app-icon:hover, .app-icon.active {
transform: scale(1.1);
background: rgba(255, 255, 255, 0.2);
}
.kernel-component {
padding: 0.4rem 0.6rem;
border-radius: 4px;
background: rgba(255, 255, 255, 0.15);
cursor: pointer;
font-size: 0.85rem;
transition: all 0.3s;
}
.kernel-component:hover, .kernel-component.active {
background: rgba(255, 255, 255, 0.3);
font-weight: 600;
}
.hardware-icons {
display: flex;
gap: 1rem;
font-size: 1.2rem;
flex-wrap: wrap;
}
.layer-desc {
font-size: 0.85rem;
margin-top: 0.5rem;
opacity: 0.9;
}
.resource-flow {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
margin-bottom: 1.5rem;
}
.flow-title {
font-weight: 600;
margin-bottom: 0.75rem;
font-size: 0.9rem;
}
.flow-content {
display: flex;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.flow-item {
text-align: center;
font-size: 0.85rem;
padding: 0.5rem;
opacity: 0.6;
transition: all 0.3s;
}
.flow-item.active {
opacity: 1;
color: var(--vp-c-brand);
}
.flow-arrow {
font-size: 1.2rem;
}
.flow-btn {
width: 100%;
padding: 0.5rem;
margin-top: 0.75rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
transition: all 0.3s;
}
.flow-btn:hover {
background: var(--vp-c-brand-dark);
}
.demo-details {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
}
.detail-title {
font-weight: 600;
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: var(--vp-c-brand);
}
.detail-desc {
font-size: 0.85rem;
color: var(--vP-c-text-2);
line-height: 1.5;
}
</style>
@@ -0,0 +1,397 @@
<template>
<div class="physical-layer-demo">
<div class="demo-header">
<span class="icon"></span>
<span class="title">物理层电信号的传递</span>
<span class="subtitle">比特如何通过物理介质传输</span>
</div>
<div class="media-selector">
<div class="selector-label">选择传输介质</div>
<div class="media-buttons">
<button
v-for="media in mediaTypes"
:key="media.id"
:class="['media-btn', { active: activeMedia === media.id }]"
@click="activeMedia = media.id"
>
{{ media.icon }} {{ media.name }}
</button>
</div>
</div>
<!-- 信号可视化 -->
<div class="signal-visualization">
<div class="signal-header">
<span class="signal-title">{{ currentMedia.signalName }}</span>
<span class="signal-desc">{{ currentMedia.signalDesc }}</span>
</div>
<div class="signal-canvas">
<div class="signal-wave">
<svg viewBox="0 0 800 150" class="wave-svg">
<!-- 坐标轴 -->
<line x1="50" y1="75" x2="750" y2="75" stroke="var(--vp-c-divider)" stroke-width="2" />
<!-- 信号波形 -->
<path
:d="currentMedia.wavePath"
fill="none"
:stroke="activeMedia === 'fiber' ? '#ff6b6b' : 'var(--vp-c-brand)'"
stroke-width="3"
class="signal-path"
/>
<!-- 数据标记 -->
<g v-if="activeMedia === 'copper'">
<text x="100" y="40" fill="var(--vp-c-text-2)" font-size="12">1</text>
<text x="180" y="110" fill="var(--vp-c-text-2)" font-size="12">0</text>
<text x="260" y="40" fill="var(--vp-c-text-2)" font-size="12">1</text>
<text x="340" y="40" fill="var(--vp-c-text-2)" font-size="12">1</text>
<text x="420" y="110" fill="var(--vp-c-text-2)" font-size="12">0</text>
</g>
<g v-if="activeMedia === 'fiber'">
<text x="100" y="40" fill="#ff6b6b" font-size="12"></text>
<text x="180" y="110" fill="var(--vp-c-text-2)" font-size="12"></text>
<text x="260" y="40" fill="#ff6b6b" font-size="12"></text>
<text x="340" y="40" fill="#ff6b6b" font-size="12"></text>
<text x="420" y="110" fill="var(--vp-c-text-2)" font-size="12"></text>
</g>
</svg>
</div>
<div class="signal-legend">
<div class="legend-item">
<div class="legend-color high"></div>
<span class="legend-label">高电平/ (1)</span>
</div>
<div class="legend-item">
<div class="legend-color low"></div>
<span class="legend-label">低电平/ (0)</span>
</div>
</div>
</div>
</div>
<!-- 介质特性 -->
<div class="media-specs">
<div class="specs-grid">
<div class="spec-card">
<div class="spec-icon">🚀</div>
<div class="spec-content">
<div class="spec-label">传输速度</div>
<div class="spec-value">{{ currentMedia.speed }}</div>
</div>
</div>
<div class="spec-card">
<div class="spec-icon">📏</div>
<div class="spec-content">
<div class="spec-label">最大距离</div>
<div class="spec-value">{{ currentMedia.distance }}</div>
</div>
</div>
<div class="spec-card">
<div class="spec-icon">🛡</div>
<div class="spec-content">
<div class="spec-label">抗干扰能力</div>
<div class="spec-value">{{ currentMedia.immunity }}</div>
</div>
</div>
<div class="spec-card">
<div class="spec-icon">💰</div>
<div class="spec-content">
<div class="spec-label">成本</div>
<div class="spec-value">{{ currentMedia.cost }}</div>
</div>
</div>
</div>
</div>
<!-- 应用场景 -->
<div class="applications">
<div class="app-title">典型应用场景</div>
<div class="app-list">
<div v-for="(app, index) in currentMedia.applications" :key="index" class="app-item">
<span class="app-icon">{{ app.icon }}</span>
<span class="app-text">{{ app.text }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeMedia = ref('copper')
const mediaTypes = [
{ id: 'copper', name: '双绞线', icon: '🔌' },
{ id: 'fiber', name: '光纤', icon: '💡' },
{ id: 'wireless', name: '无线', icon: '📡' }
]
const mediaData = {
copper: {
signalName: '电信号(电压高低)',
signalDesc: '用高低电压表示 0 和 1',
wavePath: 'M 50 75 L 100 75 L 100 25 L 150 25 L 150 125 L 200 125 L 200 25 L 250 25 L 250 25 L 300 25 L 300 125 L 350 125 L 350 25 L 400 25',
speed: '最高 10 Gbps',
distance: '100 米',
immunity: '较差(易受电磁干扰)',
cost: '低',
applications: [
{ icon: '🏠', text: '家庭局域网(网线连接)' },
{ icon: '🏢', text: '办公室网络布线' },
{ icon: '🖥️', text: '电脑连接路由器' }
]
},
fiber: {
signalName: '光信号(光的开关)',
signalDesc: '用光脉冲表示 0 和 1',
wavePath: 'M 50 75 L 100 75 L 100 25 L 150 25 L 150 125 L 200 125 L 200 25 L 250 25 L 250 25 L 300 25 L 300 125 L 350 125 L 350 25 L 400 25',
speed: '最高 100+ Tbps',
distance: '几十公里',
immunity: '极强(不受电磁干扰)',
cost: '高',
applications: [
{ icon: '🌐', text: '互联网骨干网' },
{ icon: '🏢', text: '跨楼宇网络连接' },
{ icon: '📺', text: '光纤入户(FTTH' }
]
},
wireless: {
signalName: '电磁波(无线电波)',
signalDesc: '用不同频率的电磁波表示数据',
wavePath: 'M 50 75 Q 87.5 25 125 75 T 200 75 T 275 75 T 350 75 T 425 75',
speed: '最高 10+ Gbps (WiFi 6E)',
distance: '几十米到几公里',
immunity: '一般(易受障碍物影响)',
cost: '中等',
applications: [
{ icon: '📱', text: '手机连接移动网络' },
{ icon: '💻', text: '笔记本 WiFi 上网' },
{ icon: '🎮', text: '蓝牙设备连接' }
]
}
}
const currentMedia = computed(() => mediaData[activeMedia.value])
</script>
<style scoped>
.physical-layer-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.media-selector {
margin-bottom: 2rem;
}
.selector-label {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.media-buttons {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
}
.media-btn {
padding: 0.6rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.media-btn:hover {
border-color: var(--vp-c-brand);
}
.media-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.signal-visualization {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.25rem;
margin-bottom: 1.5rem;
}
.signal-header {
margin-bottom: 1rem;
}
.signal-title {
font-weight: 600;
font-size: 1rem;
color: var(--vp-c-brand);
display: block;
margin-bottom: 0.35rem;
}
.signal-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.signal-canvas {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 1rem;
}
.signal-wave {
margin-bottom: 1rem;
}
.wave-svg {
width: 100%;
height: auto;
display: block;
}
.signal-path {
animation: drawSignal 2s ease-in-out infinite;
}
@keyframes drawSignal {
0% { stroke-dashoffset: 1000; }
100% { stroke-dashoffset: 0; }
}
.signal-legend {
display: flex;
gap: 1.5rem;
justify-content: center;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
}
.legend-color {
width: 20px;
height: 20px;
border-radius: 3px;
}
.legend-color.high {
background: var(--vp-c-brand);
}
.legend-color.low {
background: var(--vp-c-divider);
}
.media-specs {
margin-bottom: 1.5rem;
}
.specs-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.spec-card {
display: flex;
gap: 0.75rem;
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.spec-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.spec-content {
flex: 1;
}
.spec-label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.25rem;
}
.spec-value {
font-size: 0.9rem;
font-weight: 600;
color: var(--vp-c-text-1);
}
.applications {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.app-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.app-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 0.75rem;
}
.app-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.app-icon {
font-size: 1.3rem;
flex-shrink: 0;
}
.app-text {
font-size: 0.85rem;
color: var(--vp-c-text-1);
}
</style>
@@ -0,0 +1,429 @@
<template>
<div class="pmf-collab-demo">
<div class="demo-header">
<span class="icon">🤝</span>
<span class="title">进程内存文件系统的协作</span>
<span class="subtitle">三大管理模块如何协同工作</span>
</div>
<div class="demo-content">
<div class="collab-scene">
<div class="scene-title">
场景选择
</div>
<div class="scene-buttons">
<button
v-for="scene in scenes"
:key="scene.id"
:class="['scene-btn', { active: activeScene === scene.id }]"
@click="activeScene = scene.id"
>
{{ scene.icon }} {{ scene.name }}
</button>
</div>
</div>
<div class="collab-visualization">
<div class="vis-container">
<!-- 进程区域 -->
<div class="zone process-zone">
<div class="zone-header">
<span class="zone-icon">🔄</span>
<span class="zone-name">进程管理</span>
</div>
<div class="zone-content">
<div class="process-list">
<div
v-for="proc in processes"
:key="proc.id"
class="process-item"
:class="{ active: proc.id === currentProcessId }"
>
<span class="proc-name">{{ proc.name }}</span>
<span class="proc-pid">PID: {{ proc.pid }}</span>
<span class="proc-state">{{ proc.state }}</span>
</div>
</div>
</div>
</div>
<!-- 内存区域 -->
<div class="zone memory-zone">
<div class="zone-header">
<span class="zone-icon">🧠</span>
<span class="zone-name">内存管理</span>
</div>
<div class="zone-content">
<div class="memory-grid">
<div
v-for="(block, index) in memoryBlocks"
:key="index"
class="memory-block"
:class="{
allocated: block.allocated,
process: block.processId
}"
:title="`地址: ${block.address}, 大小: ${block.size}KB`"
>
<div v-if="block.allocated" class="block-info">
{{ getProcessName(block.processId) }}
</div>
</div>
</div>
</div>
</div>
<!-- 文件系统区域 -->
<div class="zone filesystem-zone">
<div class="zone-header">
<span class="zone-icon">📁</span>
<span class="zone-name">文件系统</span>
</div>
<div class="zone-content">
<div class="file-tree">
<div
v-for="file in files"
:key="file.id"
class="file-item"
:class="{ active: file.id === currentFileId }"
>
<span class="file-icon">{{ getIcon(file.type) }}</span>
<span class="file-name">{{ file.name }}</span>
<span v-if="file.size" class="file-size">{{ file.size }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="explanation">
<div class="exp-title">
{{ currentSceneData.title }}
</div>
<div class="exp-content">
<div
v-for="(step, index) in currentSceneData.steps"
:key="index"
class="exp-step"
>
<span class="step-number">{{ index + 1 }}</span>
<span class="step-text">{{ step }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeScene = ref('launch')
const currentProcessId = ref(null)
const currentFileId = ref(null)
const scenes = [
{
id: 'launch',
name: '启动程序',
icon: '🚀'
},
{
id: 'memory-access',
name: '内存访问',
icon: '💾'
},
{
id: 'file-access',
name: '文件读写',
icon: '📄'
},
{
id: 'context-switch',
name: '进程切换',
icon: '🔄'
}
]
const processes = ref([
{ id: 1, name: '浏览器', pid: 1001, state: '运行中' },
{ id: 2, name: '音乐播放器', pid: 1002, state: '等待中' },
{ id: 3, name: '代码编辑器', pid: 1003, state: '运行中' }
])
const memoryBlocks = ref([
{ address: '0x1000', size: 256, allocated: true, processId: 1 },
{ address: '0x2000', size: 128, allocated: true, processId: 2 },
{ address: '0x3000', size: 512, allocated: true, processId: 3 },
{ address: '0x4000', size: 1024, allocated: false, processId: null },
{ address: '0x5000', size: 512, allocated: false, processId: null },
{ address: '0x6000', size: 256, allocated: false, processId: null },
{ address: '0x7000', size: 128, allocated: false, processId: null }
])
const files = ref([
{ id: 1, name: 'config.json', type: 'json', size: '2KB' },
{ id: 2, name: 'user_data.db', type: 'db', size: '50MB' },
{ id: 3, name: 'cache', type: 'folder', size: '' },
{ id: 4, name: 'song.mp3', type: 'audio', size: '5MB' }
])
const sceneData = {
launch: {
title: '场景1:启动程序(浏览器)',
steps: [
'1. 用户双击浏览器图标',
'2. 进程管理创建新进程(PID: 1004',
'3. 内存管理分配内存空间(代码段、数据段、堆、栈)',
'4. 文件系统读取配置文件和缓存数据'
]
},
'memory-access': {
title: '场景2:程序运行时申请内存',
steps: [
'1. 浏览器加载大图片,需要更多内存',
'2. 进程通过系统调用请求内存(malloc)',
'3. 内存管理查找可用内存块(如:0x4000)',
'4. 将内存块标记为"已分配",返回地址给程序'
]
},
'file-access': {
title: '场景3:保存文件',
steps: [
'1. 用户在浏览器点击"保存图片"',
'2. 进程发起文件写入系统调用',
'3. 文件系统查找空闲磁盘空间',
'4. 将数据写入磁盘,更新文件分配表'
]
},
'context-switch': {
title: '场景4:切换到音乐播放器',
steps: [
'1. 用户点击音乐播放器窗口',
'2. 操作系统暂停浏览器进程',
'3. 调度器加载音乐播放器进程上下文',
'4. CPU开始执行音乐播放器代码'
]
}
}
const currentSceneData = computed(() => sceneData[activeScene.value] || sceneData.launch)
const getProcessName = (id) => {
const proc = processes.value.find(p => p.id === id)
return proc?.name || '系统'
}
const getIcon = (type) => {
const icons = {
'json': '📋',
'db': '🗄️',
'folder': '📁',
'audio': '🎵'
}
return icons[type] || '📄'
}
</script>
<style scoped>
.pmf-collab-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.scene-buttons {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
margin-bottom: 1.5rem;
}
.scene-btn {
padding: 0.6rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.scene-btn:hover {
border-color: var(--vp-c-brand);
}
.scene-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.collab-visualization {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-bottom: 1.5rem;
}
@media (max-width: 768px) {
.collab-visualization {
grid-template-columns: 1fr;
}
}
.zone {
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
background: var(--vp-c-bg);
}
.zone-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
font-weight: 600;
font-size: 0.9rem;
}
.zone-icon { font-size: 1.2rem; }
.zone-name { font-size: 0.85rem; }
.process-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.process-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border-radius: 4px;
font-size: 0.8rem;
}
.process-item.active {
border: 2px solid var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.proc-name, .proc-pid, .proc-state {
flex: 1;
}
.proc-state {
color: var(--vp-c-text-2);
font-size: 0.75rem;
}
.memory-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
}
.memory-block {
aspect-ratio: 2;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
position: relative;
background: var(--vp-c-bg-soft);
transition: all 0.3s;
}
.memory-block.allocated {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
}
.memory-block.process {
border: 2px solid var(--vp-c-brand);
}
.block-info {
font-weight: 600;
color: var(--vp-c-brand);
font-size: 0.7rem;
text-align: center;
}
.file-tree {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.file-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border-radius: 4px;
font-size: 0.8rem;
}
.file-item.active {
border: 2px solid var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.file-name { flex: 1; }
.file-size { color: var(--vp-c-text-2); font-size: 0.7rem; }
.explanation {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
}
.exp-title {
font-weight: 600;
margin-bottom: 0.75rem;
font-size: 0.95rem;
color: var(--vp-c-brand);
}
.exp-content {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.exp-step {
display: flex;
gap: 0.5rem;
font-size: 0.85rem;
line-height: 1.5;
}
.step-number {
color: var(--vp-c-brand);
font-weight: 600;
flex-shrink: 0;
}
</style>
@@ -0,0 +1,441 @@
<template>
<div class="programming-language-comparison-demo">
<div class="demo-header">
<span class="icon"></span>
<span class="title">编程语言对比</span>
<span class="subtitle">不同语言的特点和适用场景</span>
</div>
<div class="comparison-grid">
<div
v-for="lang in languages"
:key="lang.name"
:class="['lang-card', { active: activeLang === lang.name }]"
@click="activeLang = lang.name"
>
<div class="card-header">
<span class="card-icon">{{ lang.icon }}</span>
<span class="card-name">{{ lang.name }}</span>
</div>
<div class="card-year">{{ lang.year }}</div>
<div class="card-paradigm">{{ lang.paradigm }}</div>
</div>
</div>
<!-- 详细对比 -->
<div v-if="activeLang" class="detail-comparison">
<div class="detail-header">
<span class="detail-icon">{{ currentLang.icon }}</span>
<span class="detail-name">{{ currentLang.name }}</span>
</div>
<div class="detail-content">
<div class="info-grid">
<div class="info-item">
<div class="info-label">诞生年份</div>
<div class="info-value">{{ currentLang.year }}</div>
</div>
<div class="info-item">
<div class="info-label">编程范式</div>
<div class="info-value">{{ currentLang.paradigm }}</div>
</div>
<div class="info-item">
<div class="info-label">类型系统</div>
<div class="info-value">{{ currentLang.typeSystem }}</div>
</div>
<div class="info-item">
<div class="info-label">性能</div>
<div class="info-value">{{ currentLang.performance }}</div>
</div>
</div>
<div class="use-cases">
<div class="cases-title">主要用途</div>
<div class="cases-list">
<span
v-for="(use, index) in currentLang.uses"
:key="index"
class="case-tag"
>
{{ use }}
</span>
</div>
</div>
<div class="pros-cons">
<div class="pros">
<div class="list-title"> 优点</div>
<ul>
<li v-for="(pro, index) in currentLang.pros" :key="index">{{ pro }}</li>
</ul>
</div>
<div class="cons">
<div class="list-title"> 缺点</div>
<ul>
<li v-for="(con, index) in currentLang.cons" :key="index">{{ con }}</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 快速对比表 -->
<div class="quick-comparison">
<div class="comparison-title">快速对比</div>
<table class="comparison-table">
<thead>
<tr>
<th>语言</th>
<th>学习难度</th>
<th>开发效率</th>
<th>执行性能</th>
<th>主要领域</th>
</tr>
</thead>
<tbody>
<tr v-for="(lang, index) in languages" :key="index" :class="{ highlighted: lang.name === activeLang }">
<td>{{ lang.icon }} {{ lang.name }}</td>
<td>{{ lang.difficulty }}</td>
<td>{{ lang.efficiency }}</td>
<td>{{ lang.performance }}</td>
<td>{{ lang.mainField }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeLang = ref('Python')
const languages = [
{
name: 'Python',
icon: '🐍',
year: '1991',
paradigm: '多范式',
typeSystem: '动态强类型',
performance: '中等',
difficulty: '⭐',
efficiency: '⭐⭐⭐⭐⭐',
mainField: 'AI/数据/后端',
uses: ['人工智能', '数据分析', 'Web 后端', '自动化脚本'],
pros: ['语法简洁优雅', '生态丰富', '学习曲线平缓', '社区活跃'],
cons: ['执行速度较慢', '移动端支持弱', 'GIL 限制并发']
},
{
name: 'JavaScript',
icon: '📜',
year: '1995',
paradigm: '多范式',
typeSystem: '动态弱类型',
performance: '中等',
difficulty: '⭐⭐',
efficiency: '⭐⭐⭐⭐',
mainField: 'Web 开发',
uses: ['前端开发', 'Node.js 后端', '跨平台应用', '小程序'],
pros: ['无处不在', '生态庞大', '异步编程优秀', '跨平台'],
cons: ['类型不安全', '标准混乱', '性能不如编译语言']
},
{
name: 'Java',
icon: '☕',
year: '1995',
paradigm: '面向对象',
typeSystem: '静态强类型',
performance: '高',
difficulty: '⭐⭐⭐',
efficiency: '⭐⭐⭐',
mainField: '企业级应用',
uses: ['企业后端', 'Android 应用', '大数据', '桌面应用'],
pros: ['跨平台', '稳定可靠', '生态系统完善', '类型安全'],
cons: ['语法繁琐', '内存占用大', '启动慢']
},
{
name: 'C/C++',
icon: '⚙️',
year: '1972/1983',
paradigm: '多范式',
typeSystem: '静态强类型',
performance: '极高',
difficulty: '⭐⭐⭐⭐⭐',
efficiency: '⭐⭐',
mainField: '系统编程',
uses: ['操作系统', '游戏引擎', '嵌入式', '高性能计算'],
pros: ['性能极致', '底层控制力强', '效率高'],
cons: ['学习困难', '内存管理复杂', '开发效率低', '容易出错']
},
{
name: 'Go',
icon: '🐹',
year: '2009',
paradigm: '多范式',
typeSystem: '静态强类型',
performance: '高',
difficulty: '⭐⭐',
efficiency: '⭐⭐⭐⭐',
mainField: '云原生/后端',
uses: ['云原生', '微服务', 'DevOps', '网络服务'],
pros: ['简洁高效', '并发优秀', '编译快', '部署简单'],
cons: ['生态较新', '缺少泛型(旧版)', '错误处理繁琐']
},
{
name: 'Rust',
icon: '🦀',
year: '2010',
paradigm: '多范式',
typeSystem: '静态强类型',
performance: '极高',
difficulty: '⭐⭐⭐⭐',
efficiency: '⭐⭐⭐',
mainField: '系统/WebAssembly',
uses: ['系统编程', 'WebAssembly', '区块链', 'CLI 工具'],
pros: ['内存安全', '性能极高', '现代工具链'],
cons: ['学习曲线陡', '编译速度慢', '生态尚在发展']
}
]
const currentLang = computed(() => languages.find(l => l.name === activeLang.value))
</script>
<style scoped>
.programming-language-comparison-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.comparison-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.lang-card {
padding: 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.lang-card:hover {
border-color: var(--vp-c-brand);
}
.lang-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-header {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
}
.card-icon {
font-size: 1.5rem;
}
.card-name {
font-weight: 600;
font-size: 0.95rem;
}
.card-year {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.card-paradigm {
font-size: 0.8rem;
color: var(--vp-c-brand);
}
.detail-comparison {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-name {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.info-item {
text-align: center;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.info-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.info-value {
font-size: 0.9rem;
font-weight: 600;
}
.use-cases {
text-align: center;
}
.cases-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.cases-list {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
justify-content: center;
}
.case-tag {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 20px;
font-size: 0.85rem;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
@media (max-width: 768px) {
.pros-cons {
grid-template-columns: 1fr;
}
}
.pros,
.cons {
padding: 1rem;
border-radius: 6px;
}
.pros {
background: rgba(16, 185, 129, 0.1);
border: 1px solid #10b981;
}
.cons {
background: rgba(239, 68, 68, 0.1);
border: 1px solid #ef4444;
}
.list-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.75rem;
}
.pros ul,
.cons ul {
margin: 0;
padding-left: 1.25rem;
}
.pros li,
.cons li {
font-size: 0.85rem;
line-height: 1.8;
}
.quick-comparison {
margin-top: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.comparison-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
text-align: center;
font-size: 0.85rem;
}
tr.highlighted {
background: var(--vp-c-brand-soft);
}
</style>
@@ -0,0 +1,418 @@
<template>
<div class="programming-paradigm-demo">
<div class="demo-header">
<span class="icon">🎨</span>
<span class="title">编程范式</span>
<span class="subtitle">不同的编程思维方式</span>
</div>
<div class="paradigm-intro">
编程范式是编程的<strong>思维方式</strong>决定了如何组织和编写代码
</div>
<div class="paradigm-cards">
<div
v-for="paradigm in paradigms"
:key="paradigm.id"
:class="['paradigm-card', { active: activeParadigm === paradigm.id }]"
@click="activeParadigm = paradigm.id"
>
<div class="card-icon">{{ paradigm.icon }}</div>
<div class="card-name">{{ paradigm.name }}</div>
<div class="card-desc">{{ paradigm.desc }}</div>
</div>
</div>
<!-- 详细说明 -->
<div v-if="activeParadigm" class="paradigm-detail">
<div class="detail-header">
<span class="detail-icon">{{ currentParadigm.icon }}</span>
<span class="detail-title">{{ currentParadigm.name }}</span>
</div>
<div class="detail-content">
<div class="detail-section">
<div class="section-title">核心思想</div>
<div class="section-text">{{ currentParadigm.idea }}</div>
</div>
<div class="detail-section">
<div class="section-title">代码示例</div>
<div class="code-box">
<pre><code>{{ currentParadigm.example }}</code></pre>
</div>
</div>
<div class="detail-section">
<div class="section-title">特点</div>
<div class="feature-tags">
<span
v-for="(feature, index) in currentParadigm.features"
:key="index"
class="feature-tag"
>
{{ feature }}
</span>
</div>
</div>
<div class="detail-section">
<div class="section-title">代表语言</div>
<div class="lang-list">
<span
v-for="(lang, index) in currentParadigm.languages"
:key="index"
class="lang-item"
>
{{ lang }}
</span>
</div>
</div>
</div>
</div>
<!-- 范式对比 -->
<div class="paradigm-comparison">
<div class="comparison-title">范式对比</div>
<table class="comparison-table">
<thead>
<tr>
<th>特点</th>
<th>命令式</th>
<th>面向对象</th>
<th>函数式</th>
</tr>
</thead>
<tbody>
<tr>
<td>关注点</td>
<td>怎么做</td>
<td>谁来做</td>
<td>做什么</td>
</tr>
<tr>
<td>数据管理</td>
<td>变量和状态</td>
<td>对象封装</td>
<td>不可变数据</td>
</tr>
<tr>
<td>代码组织</td>
<td>语句和函数</td>
<td>类和对象</td>
<td>纯函数</td>
</tr>
<tr>
<td>适用场景</td>
<td>系统编程</td>
<td>大型应用</td>
<td>数据处理</td>
</tr>
</tbody>
</table>
</div>
<!-- 多范式 -->
<div class="multi-paradigm">
<div class="multi-title">现代多范式语言</div>
<div class="multi-desc">
大多数现代语言支持多种范式开发者可以根据需求灵活选择
</div>
<div class="lang-grid">
<div class="multi-lang-card">
<div class="lang-name">Python</div>
<div class="lang-paradigms">命令式 + 面向对象 + 函数式</div>
</div>
<div class="multi-lang-card">
<div class="lang-name">JavaScript</div>
<div class="lang-paradigms">命令式 + 面向对象 + 函数式</div>
</div>
<div class="multi-lang-card">
<div class="lang-name">Rust</div>
<div class="lang-paradigms">命令式 + 面向对象 + 函数式</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeParadigm = ref('imperative')
const paradigms = [
{
id: 'imperative',
name: '命令式编程',
icon: '📋',
desc: '告诉计算机怎么做',
idea: '通过一系列命令(语句)来改变程序状态,关注"怎么做"',
example: '// 计算1-10的和\nlet sum = 0;\nfor (let i = 1; i <= 10; i++) {\n sum += i;\n}',
features: ['变量', '循环', '条件判断', '语句'],
languages: ['C', 'Python', 'JavaScript']
},
{
id: 'oop',
name: '面向对象编程',
icon: '🎯',
desc: '用对象来组织代码',
idea: '将数据和操作数据的方法封装成对象,通过对象间交互来完成任务',
example: 'class Calculator {\n add(a, b) { return a + b; }\n}\nconst calc = new Calculator();',
features: ['封装', '继承', '多态', '类'],
languages: ['Java', 'C++', 'Python', 'Ruby']
},
{
id: 'functional',
name: '函数式编程',
icon: 'λ',
desc: '函数是核心',
idea: '强调纯函数、不可变数据,避免副作用,关注"做什么"',
example: '// 计算1-10的和\nconst sum = Array.from(\n {length: 10}, (_, i) => i + 1\n).reduce((a, b) => a + b, 0);',
features: ['纯函数', '不可变性', '高阶函数', '无副作用'],
languages: ['Haskell', 'F#', 'Erlang', 'Clojure']
}
]
const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadigm.value))
</script>
<style scoped>
.programming-paradigm-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.paradigm-intro {
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
margin-bottom: 2rem;
font-size: 0.95rem;
line-height: 1.6;
}
.paradigm-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.paradigm-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.paradigm-card:hover {
border-color: var(--vp-c-brand);
transform: translateY(-3px);
}
.paradigm-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-icon {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.card-name {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.5rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.paradigm-detail {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.detail-icon {
font-size: 1.5rem;
}
.detail-title {
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.detail-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.detail-section {}
.section-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.section-text {
font-size: 0.9rem;
line-height: 1.6;
}
.code-box {
background: #1e1e1e;
border-radius: 6px;
padding: 1rem;
}
.code-box pre {
margin: 0;
color: #d4d4d4;
font-size: 0.8rem;
line-height: 1.6;
}
.feature-tags {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.feature-tag {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 20px;
font-size: 0.85rem;
}
.lang-list {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.lang-item {
padding: 0.5rem 1rem;
background: var(--vp-c-brand-soft);
border: 1px solid var(--vp-c-brand);
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
}
.paradigm-comparison {
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.comparison-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
text-align: center;
font-size: 0.85rem;
}
.multi-paradigm {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.multi-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.multi-desc {
font-size: 0.9rem;
color: var(--vp-c-text-2);
margin-bottom: 1rem;
line-height: 1.6;
}
.lang-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.multi-lang-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
text-align: center;
}
.lang-name {
font-weight: 700;
font-size: 1rem;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.lang-paradigms {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
</style>
@@ -0,0 +1,531 @@
<template>
<div class="recursive-thinking-demo">
<div class="demo-header">
<span class="icon">🔄</span>
<span class="title">递归思维自己调用自己</span>
<span class="subtitle">把大问题分解成相同的小问题</span>
</div>
<div class="analogy-section">
<div class="analogy-box">
<div class="analogy-icon">🪆</div>
<div class="analogy-content">
<div class="analogy-title">俄罗斯套娃</div>
<div class="analogy-desc">
打开一个大娃娃里面有个小一点的娃娃<br>
再打开还有更小的...直到最小的一个<br>
<strong>这就是递归</strong>
</div>
</div>
</div>
</div>
<div class="example-selector">
<div class="selector-title">递归示例</div>
<div class="selector-buttons">
<button
v-for="example in examples"
:key="example.id"
:class="['example-btn', { active: activeExample === example.id }]"
@click="activeExample = example.id"
>
{{ example.icon }} {{ example.name }}
</button>
</div>
</div>
<!-- 阶乘示例 -->
<div v-if="activeExample === 'factorial'" class="example-content">
<div class="example-title">阶乘n! = n × (n-1)!</div>
<div class="factorial-visual">
<div class="factorial-call">
<div class="call-box">5! = 5 × 4!</div>
<div class="call-arrow"></div>
<div class="call-box">4! = 4 × 3!</div>
<div class="call-arrow"></div>
<div class="call-box">3! = 3 × 2!</div>
<div class="call-arrow"></div>
<div class="call-box">2! = 2 × 1!</div>
<div class="call-arrow"></div>
<div class="call-box base">1! = 1 (基准情况)</div>
</div>
<div class="factorial-return">
<div class="return-arrow"> 返回 1</div>
<div class="return-arrow"> 返回 2 × 1 = 2</div>
<div class="return-arrow"> 返回 3 × 2 = 6</div>
<div class="return-arrow"> 返回 4 × 6 = 24</div>
<div class="return-arrow"> 返回 5 × 24 = 120</div>
</div>
</div>
</div>
<!-- 斐波那契示例 -->
<div v-if="activeExample === 'fibonacci'" class="example-content">
<div class="example-title">斐波那契数列</div>
<div class="fibonacci-visual">
<div class="fib-rule">F(n) = F(n-1) + F(n-2)</div>
<div class="fib-tree">
<div class="tree-node">F(5)</div>
<div class="tree-level">
<div class="tree-node">F(4)</div>
<div class="tree-node">F(3)</div>
</div>
<div class="tree-level">
<div class="tree-node">F(3)</div>
<div class="tree-node">F(2)</div>
<div class="tree-node">F(2)</div>
<div class="tree-node">F(1)=1</div>
</div>
</div>
<div class="fib-result">F(5) = 5</div>
</div>
</div>
<!-- 目录遍历示例 -->
<div v-if="activeExample === 'directory'" class="example-content">
<div class="example-title">遍历文件目录</div>
<div class="directory-visual">
<div class="dir-tree">
<div class="dir-node root">📁 /home</div>
<div class="dir-children">
<div class="dir-node">📄 file1.txt</div>
<div class="dir-node">📁 documents</div>
<div class="dir-children">
<div class="dir-node">📄 report.doc</div>
<div class="dir-node">📁 photos</div>
<div class="dir-children">
<div class="dir-node">🖼 pic1.jpg</div>
</div>
</div>
<div class="dir-node">📄 file2.txt</div>
</div>
</div>
<div class="dir-pseudocode">
<div class="pseudo-title">伪代码</div>
<pre>function traverse(folder) {
for each item in folder {
if item is file {
print(item)
} else if item is folder {
traverse(item) //
}
}
}</pre>
</div>
</div>
</div>
<!-- 递归三要素 -->
<div class="recursive-elements">
<div class="elements-title">递归的三要素</div>
<div class="elements-grid">
<div class="element-card">
<div class="element-number">1</div>
<div class="element-title">基准情况</div>
<div class="element-desc">什么时候停止递归必须有一个终止条件</div>
<div class="element-example">n! 1! = 1</div>
</div>
<div class="element-card">
<div class="element-number">2</div>
<div class="element-title">递归调用</div>
<div class="element-desc">如何让问题规模变小调用自己处理更小的规模</div>
<div class="element-example">n! 转换成 (n-1)!</div>
</div>
<div class="element-card">
<div class="element-number">3</div>
<div class="element-title">返回结果</div>
<div class="element-desc">如何利用子问题的结果解决当前问题</div>
<div class="element-example">n × (n-1)! 的结果</div>
</div>
</div>
</div>
<!-- 优缺点 -->
<div class="pros-cons">
<div class="pros-column">
<div class="column-title"> 优点</div>
<ul class="column-list">
<li>代码简洁优雅</li>
<li>自然表达递归结构</li>
<li>适合树和图的遍历</li>
</ul>
</div>
<div class="cons-column">
<div class="column-title"> 缺点</div>
<ul class="column-list">
<li>可能重复计算</li>
<li>栈空间消耗大</li>
<li>调试较困难</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeExample = ref('factorial')
const examples = [
{ id: 'factorial', name: '阶乘', icon: '🔢' },
{ id: 'fibonacci', name: '斐波那契', icon: '🐚' },
{ id: 'directory', name: '目录遍历', icon: '📁' }
]
</script>
<style scoped>
.recursive-thinking-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.analogy-section {
margin-bottom: 2rem;
}
.analogy-box {
display: flex;
gap: 1.5rem;
padding: 1.5rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
}
.analogy-icon {
font-size: 3rem;
flex-shrink: 0;
}
.analogy-content {
flex: 1;
}
.analogy-title {
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.analogy-desc {
font-size: 0.9rem;
line-height: 1.8;
}
.example-selector {
margin-bottom: 2rem;
}
.selector-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.75rem;
color: var(--vp-c-brand);
}
.selector-buttons {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
}
.example-btn {
padding: 0.6rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.example-btn:hover {
border-color: var(--vp-c-brand);
}
.example-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.example-content {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.example-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
text-align: center;
color: var(--vp-c-brand);
}
.factorial-visual {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
@media (max-width: 768px) {
.factorial-visual {
grid-template-columns: 1fr;
}
}
.call-box {
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
}
.call-box.base {
background: #10b981;
color: white;
border-color: #10b981;
font-weight: 600;
}
.call-arrow {
text-align: center;
font-size: 1.5rem;
color: var(--vp-c-brand);
margin: 0.5rem 0;
}
.return-arrow {
padding: 0.5rem;
background: rgba(59, 130, 246, 0.1);
border: 1px solid #3b82f6;
border-radius: 4px;
text-align: center;
font-size: 0.85rem;
color: #3b82f6;
margin-bottom: 0.5rem;
}
.fibonacci-visual {
text-align: center;
}
.fib-rule {
font-family: 'Courier New', monospace;
font-size: 1.1rem;
font-weight: 600;
color: var(--vp-c-brand);
margin-bottom: 1.5rem;
}
.fib-tree {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-bottom: 1.5rem;
}
.tree-level {
display: flex;
justify-content: center;
gap: 1rem;
}
.tree-node {
padding: 0.5rem 1rem;
background: var(--vp-c-brand-soft);
border: 1px solid var(--vp-c-brand);
border-radius: 6px;
font-family: 'Courier New', monospace;
font-weight: 600;
}
.fib-result {
font-size: 1.2rem;
font-weight: 700;
color: #10b981;
}
.directory-visual {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
@media (max-width: 768px) {
.directory-visual {
grid-template-columns: 1fr;
}
}
.dir-tree {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dir-node {
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
font-size: 0.85rem;
}
.dir-node.root {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
font-weight: 600;
}
.dir-children {
margin-left: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dir-pseudocode {
background: #1e1e1e;
border-radius: 6px;
padding: 1rem;
}
.pseudo-title {
color: white;
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.75rem;
}
.dir-pseudocode pre {
color: #d4d4d4;
font-size: 0.8rem;
line-height: 1.6;
margin: 0;
}
.recursive-elements {
margin-bottom: 2rem;
}
.elements-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.elements-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.element-card {
padding: 1.25rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
}
.element-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.75rem;
}
.element-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.element-desc {
font-size: 0.85rem;
color: var(--vp-c-text-1);
line-height: 1.5;
margin-bottom: 0.5rem;
}
.element-example {
font-size: 0.8rem;
color: var(--vp-c-text-2);
font-style: italic;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
@media (max-width: 768px) {
.pros-cons {
grid-template-columns: 1fr;
}
}
.pros-column,
.cons-column {
padding: 1.25rem;
border-radius: 8px;
}
.pros-column {
background: rgba(16, 185, 129, 0.1);
border: 1px solid #10b981;
}
.cons-column {
background: rgba(239, 68, 68, 0.1);
border: 1px solid #ef4444;
}
.column-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
}
.column-list {
margin: 0;
padding-left: 1.25rem;
}
.column-list li {
font-size: 0.9rem;
line-height: 1.8;
color: var(--vp-c-text-1);
}
</style>
@@ -0,0 +1,368 @@
<template>
<div class="search-algorithm-demo">
<div class="demo-header">
<span class="icon">🔍</span>
<span class="title">查找算法</span>
<span class="subtitle">如何在数据中找到目标</span>
</div>
<div class="algorithm-selector">
<button
:class="['algo-btn', { active: activeAlgo === 'linear' }]"
@click="activeAlgo = 'linear'"
>
顺序查找
</button>
<button
:class="['algo-btn', { active: activeAlgo === 'binary' }]"
@click="activeAlgo = 'binary'"
>
二分查找
</button>
</div>
<!-- 顺序查找 -->
<div v-if="activeAlgo === 'linear'" class="algo-content">
<div class="content-title">顺序查找一个一个找</div>
<div class="linear-demo">
<div class="search-array">
<div
v-for="(num, index) in numbers"
:key="index"
:class="['array-cell', { found: index === foundIndex, searching: index <= searchStep && searching }]"
>
{{ num }}
</div>
</div>
<div class="search-controls">
<button @click="startLinearSearch" class="search-btn">开始查找</button>
<button @click="reset" class="reset-btn">重置</button>
</div>
<div class="search-info">
目标数字<input v-model="targetNumber" type="number" class="target-input" />
</div>
</div>
<div class="algo-stats">
<div class="stat-item">时间复杂度O(n)</div>
<div class="stat-item">适用无序数组</div>
</div>
</div>
<!-- 二分查找 -->
<div v-if="activeAlgo === 'binary'" class="algo-content">
<div class="content-title">二分查找每次排除一半</div>
<div class="binary-demo">
<div class="sorted-array">
<div
v-for="(num, index) in sortedNumbers"
:key="index"
:class="['array-cell', {
found: index === binaryFoundIndex,
left: index >= binaryLeft && index <= binaryRight,
eliminated: index < binaryLeft || index > binaryRight
}]"
>
{{ num }}
</div>
</div>
<div class="binary-info">
<div class="info-step">查找范围[{{ binaryLeft }}, {{ binaryRight }}]</div>
<div class="info-mid">中间位置{{ binaryMid }}</div>
<div class="info-comparison">{{ sortedNumbers[binaryMid] }} vs {{ binaryTarget }}</div>
</div>
<div class="search-controls">
<button @click="binaryStep" class="search-btn">下一步</button>
<button @click="resetBinary" class="reset-btn">重置</button>
</div>
</div>
<div class="algo-stats">
<div class="stat-item">时间复杂度O(log n)</div>
<div class="stat-item">适用有序数组</div>
</div>
</div>
<!-- 对比 -->
<div class="comparison">
<div class="comparison-title">性能对比</div>
<table class="comparison-table">
<thead>
<tr>
<th>数据量</th>
<th>顺序查找</th>
<th>二分查找</th>
</tr>
</thead>
<tbody>
<tr v-for="n in [10, 100, 1000, 10000]" :key="n">
<td>{{ n }}</td>
<td>最多 {{ n }} </td>
<td>最多 {{ Math.ceil(Math.log2(n)) }} </td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeAlgo = ref('linear')
const targetNumber = ref(7)
const foundIndex = ref(-1)
const searchStep = ref(-1)
const searching = ref(false)
const numbers = ref([3, 7, 2, 9, 5, 1, 8, 4, 6, 10])
const sortedNumbers = ref([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
const binaryTarget = ref(7)
const binaryLeft = ref(0)
const binaryRight = ref(9)
const binaryMid = ref(4)
const binaryFoundIndex = ref(-1)
const startLinearSearch = () => {
searching.value = true
searchStep.value = -1
foundIndex.value = -1
let step = 0
const interval = setInterval(() => {
if (step < numbers.value.length) {
searchStep.value = step
if (numbers.value[step] === targetNumber.value) {
foundIndex.value = step
searching.value = false
clearInterval(interval)
}
step++
} else {
searching.value = false
clearInterval(interval)
}
}, 500)
}
const reset = () => {
searchStep.value = -1
foundIndex.value = -1
searching.value = false
}
const binaryStep = () => {
binaryMid.value = Math.floor((binaryLeft.value + binaryRight.value) / 2)
if (sortedNumbers.value[binaryMid.value] === binaryTarget.value) {
binaryFoundIndex.value = binaryMid.value
} else if (sortedNumbers.value[binaryMid.value] < binaryTarget.value) {
binaryLeft.value = binaryMid.value + 1
} else {
binaryRight.value = binaryMid.value - 1
}
}
const resetBinary = () => {
binaryLeft.value = 0
binaryRight.value = 9
binaryMid.value = 4
binaryFoundIndex.value = -1
}
</script>
<style scoped>
.search-algorithm-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.algorithm-selector {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
}
.algo-btn {
flex: 1;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s;
}
.algo-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.algo-content {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.content-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1.5rem;
text-align: center;
color: var(--vp-c-brand);
}
.search-array,
.sorted-array {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.array-cell {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-bg-soft);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-weight: 600;
font-size: 1rem;
}
.array-cell.searching {
border-color: #f59e0b;
background: rgba(245, 158, 11, 0.1);
}
.array-cell.found {
border-color: #10b981;
background: #10b981;
color: white;
}
.array-cell.left {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.array-cell.eliminated {
opacity: 0.3;
}
.search-controls {
display: flex;
gap: 1rem;
justify-content: center;
margin-bottom: 1.5rem;
}
.search-btn {
padding: 0.6rem 1.25rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
}
.reset-btn {
padding: 0.6rem 1.25rem;
background: var(--vp-c-divider);
border: none;
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
}
.search-info {
text-align: center;
margin-bottom: 1rem;
}
.target-input {
width: 60px;
padding: 0.5rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
text-align: center;
font-size: 0.9rem;
}
.binary-info {
text-align: center;
margin-bottom: 1.5rem;
}
.info-step,
.info-mid,
.info-comparison {
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.algo-stats {
display: flex;
gap: 1rem;
justify-content: center;
padding-top: 1rem;
border-top: 1px solid var(--vp-c-divider);
}
.stat-item {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.comparison {
margin-top: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.comparison-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
text-align: center;
font-size: 0.85rem;
}
</style>
@@ -0,0 +1,319 @@
<template>
<div class="sorting-algorithm-demo">
<div class="demo-header">
<span class="icon">📊</span>
<span class="title">排序算法</span>
<span class="subtitle">把数据按顺序排列</span>
</div>
<div class="visual-array">
<div
v-for="(item, index) in array"
:key="index"
class="array-bar"
:class="{
comparing: comparingIndices.includes(index),
swapping: swappingIndices.includes(index),
sorted: index < sortedCount
}"
:style="{ height: item * 3 + 'px' }"
>
{{ item }}
</div>
</div>
<div class="controls">
<button @click="generateArray" class="control-btn">生成新数组</button>
<button @click="startBubbleSort" class="control-btn">冒泡排序</button>
<button @click="startQuickSort" class="control-btn">快速排序</button>
</div>
<div class="algorithm-info">
<div class="info-title">{{ currentAlgo }}</div>
<div class="info-desc">{{ currentAlgoDesc }}</div>
<div class="info-complexity">时间复杂度{{ complexity }}</div>
</div>
<div class="comparison">
<div class="comparison-title">算法对比</div>
<table class="comparison-table">
<thead>
<tr>
<th>算法</th>
<th>平均时间</th>
<th>最坏时间</th>
<th>空间</th>
<th>稳定</th>
</tr>
</thead>
<tbody>
<tr>
<td>冒泡排序</td>
<td>O()</td>
<td>O()</td>
<td>O(1)</td>
<td></td>
</tr>
<tr>
<td>快速排序</td>
<td>O(n log n)</td>
<td>O()</td>
<td>O(log n)</td>
<td></td>
</tr>
<tr>
<td>归并排序</td>
<td>O(n log n)</td>
<td>O(n log n)</td>
<td>O(n)</td>
<td></td>
</tr>
<tr>
<td>插入排序</td>
<td>O()</td>
<td>O()</td>
<td>O(1)</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const array = ref([50, 30, 70, 40, 90, 20, 60, 80, 10, 55])
const comparingIndices = ref([])
const swappingIndices = ref([])
const sortedCount = ref(0)
const currentAlgo = ref('请选择排序算法')
const currentAlgoDesc = ref('选择一个排序算法开始演示')
const complexity = ref('')
const generateArray = () => {
array.value = Array.from({ length: 10 }, () => Math.floor(Math.random() * 90) + 10)
sortedCount.value = 0
comparingIndices.value = []
swappingIndices.value = []
}
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))
const startBubbleSort = async () => {
currentAlgo.value = '冒泡排序'
currentAlgoDesc.value = '重复遍历数组,比较相邻元素并交换'
complexity.value = 'O(n²)'
sortedCount.value = 0
const arr = [...array.value]
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
comparingIndices.value = [j, j + 1]
await sleep(300)
if (arr[j] > arr[j + 1]) {
swappingIndices.value = [j, j + 1]
await sleep(300)
;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
array.value = [...arr]
await sleep(300)
swappingIndices.value = []
}
}
sortedCount.value++
}
comparingIndices.value = []
sortedCount.value = arr.length
}
const startQuickSort = async () => {
currentAlgo.value = '快速排序'
currentAlgoDesc.value = '选择基准,将数组分成小于和大于基准的两部分'
complexity.value = 'O(n log n)'
sortedCount.value = 0
const arr = [...array.value]
await quickSort(arr, 0, arr.length - 1)
array.value = arr
sortedCount.value = arr.length
comparingIndices.value = []
}
const quickSort = async (arr, low, high) => {
if (low < high) {
const pi = await partition(arr, low, high)
await quickSort(arr, low, pi - 1)
await quickSort(arr, pi + 1, high)
}
}
const partition = async (arr, low, high) => {
const pivot = arr[high]
let i = low - 1
for (let j = low; j < high; j++) {
comparingIndices.value = [j, high]
await sleep(300)
if (arr[j] < pivot) {
i++
swappingIndices.value = [i, j]
await sleep(300)
;[arr[i], arr[j]] = [arr[j], arr[i]]
array.value = [...arr]
await sleep(300)
}
}
swappingIndices.value = [i + 1, high]
await sleep(300)
;[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]
array.value = [...arr]
await sleep(300)
swappingIndices.value = []
return i + 1
}
</script>
<style scoped>
.sorting-algorithm-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.visual-array {
display: flex;
align-items: flex-end;
justify-content: center;
gap: 0.5rem;
height: 300px;
margin-bottom: 2rem;
padding: 1rem;
background: var(--vp-c-bg);
border-radius: 8px;
}
.array-bar {
flex: 1;
max-width: 50px;
background: var(--vp-c-brand);
border-radius: 4px 4px 0 0;
display: flex;
align-items: flex-end;
justify-content: center;
padding-bottom: 0.5rem;
font-size: 0.75rem;
font-weight: 600;
color: white;
transition: all 0.3s;
}
.array-bar.comparing {
background: #f59e0b;
}
.array-bar.swapping {
background: #ef4444;
}
.array-bar.sorted {
background: #10b981;
}
.controls {
display: flex;
gap: 1rem;
justify-content: center;
margin-bottom: 2rem;
}
.control-btn {
padding: 0.6rem 1.25rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s;
}
.control-btn:hover {
transform: translateY(-2px);
}
.algorithm-info {
text-align: center;
padding: 1.5rem;
background: var(--vp-c-bg);
border-radius: 8px;
margin-bottom: 2rem;
}
.info-title {
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.info-desc {
font-size: 0.9rem;
margin-bottom: 0.5rem;
color: var(--vp-c-text-2);
}
.info-complexity {
font-family: 'Courier New', monospace;
font-size: 0.9rem;
color: var(--vp-c-brand);
font-weight: 600;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.comparison-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
text-align: center;
font-size: 0.85rem;
}
</style>
@@ -0,0 +1,246 @@
<template>
<div class="storage-hierarchy-demo">
<div class="demo-header">
<span class="icon">💾</span>
<span class="title">存储层次结构</span>
<span class="subtitle">从快到慢从小到大</span>
</div>
<div class="hierarchy-pyramid">
<div class="pyramid-level register">
<div class="level-name">寄存器</div>
<div class="level-speed">最快</div>
<div class="level-size">最小 (KB)</div>
</div>
<div class="pyramid-level cache">
<div class="level-name">缓存</div>
<div class="level-speed">很快</div>
<div class="level-size"> (MB)</div>
</div>
<div class="pyramid-level ram">
<div class="level-name">内存</div>
<div class="level-speed"></div>
<div class="level-size">中等 (GB)</div>
</div>
<div class="pyramid-level disk">
<div class="level-name">硬盘</div>
<div class="level-speed"></div>
<div class="level-size"> (TB)</div>
</div>
<div class="pyramid-level network">
<div class="level-name">网络/</div>
<div class="level-speed">最慢</div>
<div class="level-size">无限</div>
</div>
</div>
<div class="comparison-table">
<div class="table-title">详细对比</div>
<table class="hierarchy-table">
<thead>
<tr>
<th>存储层次</th>
<th>访问时间</th>
<th>典型容量</th>
<th>成本</th>
</tr>
</thead>
<tbody>
<tr>
<td>寄存器</td>
<td>&lt; 1 ns</td>
<td> KB</td>
<td>最高</td>
</tr>
<tr>
<td>L1 缓存</td>
<td>~1 ns</td>
<td>64 KB</td>
<td>很高</td>
</tr>
<tr>
<td>L2 缓存</td>
<td>~3 ns</td>
<td>256 KB</td>
<td></td>
</tr>
<tr>
<td>L3 缓存</td>
<td>~10 ns</td>
<td>8 MB</td>
<td>中等</td>
</tr>
<tr>
<td>内存</td>
<td>~100 ns</td>
<td>8-32 GB</td>
<td>中低</td>
</tr>
<tr>
<td>SSD</td>
<td>~100 μs</td>
<td>256 GB-2 TB</td>
<td></td>
</tr>
<tr>
<td>HDD</td>
<td>~10 ms</td>
<td>1-10 TB</td>
<td>最低</td>
</tr>
</tbody>
</table>
</div>
<div class="principle">
<div class="principle-title">局部性原理</div>
<div class="principle-content">
<div class="principle-text">
程序倾向于访问<strong>最近访问过的位置</strong>时间局部性
<strong>邻近的位置</strong>空间局部性
</div>
<div class="principle-example">
利用局部性原理缓存可以显著提高性能
</div>
</div>
</div>
</div>
</template>
<script setup>
</script>
<style scoped>
.storage-hierarchy-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.hierarchy-pyramid {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 2rem;
}
.pyramid-level {
padding: 1rem;
border-radius: 6px;
text-align: center;
color: white;
}
.pyramid-level.register {
background: linear-gradient(135deg, #ef4444, #dc2626);
}
.pyramid-level.cache {
background: linear-gradient(135deg, #f59e0b, #d97706);
}
.pyramid-level.ram {
background: linear-gradient(135deg, #10b981, #059669);
}
.pyramid-level.disk {
background: linear-gradient(135deg, #3b82f6, #2563eb);
}
.pyramid-level.network {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
}
.level-name {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.35rem;
}
.level-speed {
font-size: 0.8rem;
margin-bottom: 0.35rem;
}
.level-size {
font-size: 0.8rem;
}
.comparison-table {
margin-bottom: 2rem;
}
.table-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.hierarchy-table {
width: 100%;
border-collapse: collapse;
}
.hierarchy-table th {
background: var(--vp-c-brand);
color: white;
padding: 0.75rem;
text-align: center;
font-size: 0.85rem;
}
.hierarchy-table td {
padding: 0.75rem;
border-bottom: 1px solid var(--vp-c-divider);
text-align: center;
font-size: 0.85rem;
font-family: 'Courier New', monospace;
}
.principle {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.principle-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.principle-content {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.principle-text {
font-size: 0.95rem;
line-height: 1.6;
}
.principle-example {
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
</style>
@@ -0,0 +1,567 @@
<template>
<div class="transport-layer-demo">
<div class="demo-header">
<span class="icon">🚚</span>
<span class="title">传输层端到端的可靠传输</span>
<span class="subtitle">TCP UDP 如何传输数据</span>
</div>
<div class="protocol-tabs">
<button
:class="['tab-btn', { active: activeProtocol === 'tcp' }]"
@click="activeProtocol = 'tcp'"
>
TCP 📦
</button>
<button
:class="['tab-btn', { active: activeProtocol === 'udp' }]"
@click="activeProtocol = 'udp'"
>
UDP
</button>
</div>
<!-- 可视化演示 -->
<div class="protocol-visual">
<div class="visual-header">
<span class="protocol-title">{{ currentProtocol.name }}</span>
<span class="protocol-slogan">{{ currentProtocol.slogan }}</span>
</div>
<div class="visual-content">
<!-- TCP 可靠传输 -->
<div v-if="activeProtocol === 'tcp'" class="tcp-demo">
<div class="connection-stages">
<div
v-for="(stage, index) in tcpStages"
:key="index"
:class="['stage-item', { active: activeTcpStage === index }]"
@click="activeTcpStage = index"
>
<div class="stage-number">{{ index + 1 }}</div>
<div class="stage-text">{{ stage }}</div>
</div>
</div>
<div class="tcp-reliability">
<div class="reliability-title">TCP 可靠性机制</div>
<div class="mechanism-grid">
<div
v-for="(mech, index) in tcpMechanisms"
:key="index"
class="mechanism-card"
>
<div class="mech-icon">{{ mech.icon }}</div>
<div class="mech-title">{{ mech.title }}</div>
<div class="mech-desc">{{ mech.desc }}</div>
</div>
</div>
</div>
</div>
<!-- UDP 快速传输 -->
<div v-if="activeProtocol === 'udp'" class="udp-demo">
<div class="udp-comparison">
<div class="comparison-side tcp-side">
<div class="side-header">TCP</div>
<div class="side-animation">
<div class="packet" v-for="i in 3" :key="'tcp-' + i">
📦 {{ i }}
</div>
</div>
<div class="side-desc">三次握手 + 确认应答</div>
</div>
<div class="vs-badge">VS</div>
<div class="comparison-side udp-side">
<div class="side-header">UDP</div>
<div class="side-animation">
<div class="packet fast" v-for="i in 5" :key="'udp-' + i">
{{ i }}
</div>
</div>
<div class="side-desc">直接发送无等待</div>
</div>
</div>
<div class="udp-use-cases">
<div class="use-cases-title">UDP 适用场景</div>
<div class="use-cases-grid">
<div
v-for="(use, index) in udpUseCases"
:key="index"
class="use-case-card"
>
<div class="use-icon">{{ use.icon }}</div>
<div class="use-title">{{ use.title }}</div>
<div class="use-reason">{{ use.reason }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 端口说明 -->
<div class="port-section">
<div class="port-title">端口号应用程序的标识</div>
<div class="port-examples">
<div class="port-intro">
端口号就像公寓房间号IP 地址是公寓楼地址合起来才能找到具体的应用程序
</div>
<div class="port-list">
<div
v-for="(port, index) in commonPorts"
:key="index"
class="port-item"
>
<div class="port-number">{{ port.number }}</div>
<div class="port-service">{{ port.service }}</div>
<div class="port-desc">{{ port.desc }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeProtocol = ref('tcp')
const activeTcpStage = ref(0)
const protocolData = {
tcp: {
name: 'TCP:可靠传输协议',
slogan: '像快递服务,确保每个包裹都送达'
},
udp: {
name: 'UDP:快速传输协议',
slogan: '像明信片,发送出去就不管了'
}
}
const tcpStages = [
'建立连接(三次握手)',
'数据传输(带序号和确认)',
'连接关闭(四次挥手)'
]
const tcpMechanisms = [
{
icon: '🤝',
title: '三次握手',
desc: '建立可靠连接,确保双方都准备好'
},
{
icon: '🔢',
title: '序号和确认',
desc: '每个数据包都有编号,收到需要确认'
},
{
icon: '🔁',
title: '超时重传',
desc: '未收到确认则自动重传丢失的数据'
},
{
icon: '🚦',
title: '流量控制',
desc: '根据接收方能力调整发送速度'
}
]
const udpUseCases = [
{
icon: '🎮',
title: '在线游戏',
reason: '速度优先,偶尔丢包可接受'
},
{
icon: '📞',
title: '视频通话',
reason: '实时性要求高,延迟比质量更重要'
},
{
icon: '📺',
title: '直播流',
reason: '持续的数据流,丢帧比卡顿好'
},
{
icon: '🔍',
title: 'DNS 查询',
reason: '请求数据小,快速响应比可靠传输重要'
}
]
const commonPorts = [
{ number: '80', service: 'HTTP', desc: '网页浏览' },
{ number: '443', service: 'HTTPS', desc: '加密网页浏览' },
{ number: '22', service: 'SSH', desc: '远程登录' },
{ number: '25', service: 'SMTP', desc: '发送邮件' },
{ number: '53', service: 'DNS', desc: '域名解析' },
{ number: '3306', service: 'MySQL', desc: '数据库连接' }
]
const currentProtocol = computed(() => protocolData[activeProtocol.value])
</script>
<style scoped>
.transport-layer-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.protocol-tabs {
display: flex;
gap: 1rem;
margin-bottom: 1.5rem;
}
.tab-btn {
flex: 1;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.tab-btn:hover {
border-color: var(--vp-c-brand);
}
.tab-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.protocol-visual {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.visual-header {
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.protocol-title {
display: block;
font-weight: 600;
font-size: 1.1rem;
color: var(--vp-c-brand);
margin-bottom: 0.35rem;
}
.protocol-slogan {
font-size: 0.9rem;
color: var(--vp-c-text-2);
}
.tcp-demo {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.connection-stages {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.stage-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.stage-item:hover {
border-color: var(--vp-c-brand);
}
.stage-item.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.stage-number {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.85rem;
font-weight: 600;
flex-shrink: 0;
}
.stage-text {
font-size: 0.9rem;
}
.tcp-reliability {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.reliability-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.mechanism-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.mechanism-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.mech-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.mech-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.mech-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.udp-demo {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.udp-comparison {
display: flex;
align-items: center;
justify-content: center;
gap: 1.5rem;
}
.comparison-side {
flex: 1;
text-align: center;
}
.side-header {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
}
.side-animation {
min-height: 80px;
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.packet {
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
font-size: 0.85rem;
animation: slideRight 2s ease-in-out infinite;
}
.packet.fast {
background: rgba(59, 130, 246, 0.1);
border-color: #3b82f6;
animation: slideRight 0.5s ease-in-out infinite;
}
@keyframes slideRight {
0% { transform: translateX(-100%); opacity: 0; }
50% { opacity: 1; }
100% { transform: translateX(100%); opacity: 0; }
}
.side-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.vs-badge {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-weight: 700;
font-size: 0.9rem;
flex-shrink: 0;
}
.udp-use-cases {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.use-cases-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.use-cases-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.use-case-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
text-align: center;
}
.use-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.use-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.use-reason {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.port-section {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.port-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.port-intro {
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.5;
margin-bottom: 1rem;
padding: 0.75rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.port-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 0.75rem;
}
.port-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.port-number {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
background: var(--vp-c-brand);
color: white;
border-radius: 6px;
font-family: 'Courier New', monospace;
font-weight: 700;
font-size: 0.9rem;
flex-shrink: 0;
}
.port-service {
font-weight: 600;
font-size: 0.9rem;
flex-shrink: 0;
}
.port-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
@media (max-width: 768px) {
.udp-comparison {
flex-direction: column;
}
.vs-badge {
transform: rotate(90deg);
}
}
</style>
@@ -0,0 +1,530 @@
<template>
<div class="tree-structure-demo">
<div class="demo-header">
<span class="icon">🌳</span>
<span class="title">树形结构层级关系的表示</span>
<span class="subtitle">像家谱一样的组织方式</span>
</div>
<div class="tree-selector">
<div class="selector-label">选择树的类型</div>
<div class="selector-buttons">
<button
v-for="type in treeTypes"
:key="type.id"
:class="['type-btn', { active: activeTreeType === type.id }]"
@click="activeTreeType = type.id"
>
{{ type.icon }} {{ type.name }}
</button>
</div>
</div>
<!-- 二叉搜索树 -->
<div v-if="activeTreeType === 'binary'" class="tree-display">
<div class="tree-canvas">
<svg viewBox="0 0 600 350" class="tree-svg">
<!-- 连接线 -->
<line v-for="line in binaryTreeLines" :key="line.id"
:x1="line.x1" :y1="line.y1"
:x2="line.x2" :y2="line.y2"
stroke="var(--vp-c-divider)"
stroke-width="2"
/>
<!-- 节点 -->
<g v-for="node in binaryTreeNodes" :key="node.id"
:class="['tree-node', { root: node.isRoot, leaf: node.isLeaf }]"
:style="{ transform: `translate(${node.x}px, ${node.y}px)` }"
>
<circle cx="0" cy="0" r="25" fill="var(--vp-c-brand-soft)" stroke="var(--vp-c-brand)" stroke-width="2" />
<text x="0" y="0" text-anchor="middle" dominant-baseline="middle" fill="var(--vp-c-brand)" font-size="14" font-weight="600">{{ node.value }}</text>
</g>
</svg>
</div>
</div>
<!-- 文件系统树 -->
<div v-if="activeTreeType === 'filesystem'" class="filesystem-tree">
<div class="fs-root">
<div class="fs-node root">📁 根目录 /</div>
<div class="fs-children">
<div class="fs-branch">
<div class="fs-node">📁 home</div>
<div class="fs-children">
<div class="fs-node">👤 user</div>
<div class="fs-children">
<div class="fs-node">📄 document.txt</div>
<div class="fs-node">🖼 photo.jpg</div>
</div>
</div>
</div>
<div class="fs-branch">
<div class="fs-node">📁 var</div>
<div class="fs-children">
<div class="fs-node">📁 www</div>
<div class="fs-children">
<div class="fs-node">📄 index.html</div>
<div class="fs-node">📄 style.css</div>
</div>
</div>
</div>
<div class="fs-branch">
<div class="fs-node">📁 etc</div>
<div class="fs-children">
<div class="fs-node">📄 config.conf</div>
</div>
</div>
</div>
</div>
</div>
<!-- DOM -->
<div v-if="activeTreeType === 'dom'" class="dom-tree">
<div class="dom-preview">
<div class="preview-title">HTML 结构</div>
<div class="preview-html">
&lt;html&gt;
&lt;body&gt;
&lt;div class="container"&gt;
&lt;h1&gt;标题&lt;/h1&gt;
&lt;p&gt;段落&lt;/p&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</div>
</div>
<div class="dom-structure">
<div class="structure-title">DOM 树结构</div>
<div class="tree-nested">
<div class="dom-node root">
<span class="node-tag">html</span>
<div class="dom-children">
<div class="dom-node">
<span class="node-tag">body</span>
<div class="dom-children">
<div class="dom-node">
<span class="node-tag">div</span>
<span class="node-class">.container</span>
<div class="dom-children">
<div class="dom-node">
<span class="node-tag">h1</span>
<span class="node-text">"标题"</span>
</div>
<div class="dom-node">
<span class="node-tag">p</span>
<span class="node-text">"段落"</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 树的特点 -->
<div class="tree-features">
<div class="features-title">树形结构的特点</div>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">🌲</div>
<div class="feature-title">层级关系</div>
<div class="feature-desc">节点之间是一对多的父子关系</div>
</div>
<div class="feature-card">
<div class="feature-icon">🎯</div>
<div class="feature-title">单一根节点</div>
<div class="feature-desc">除根节点外每个节点只有一个父节点</div>
</div>
<div class="feature-card">
<div class="feature-icon">🔍</div>
<div class="feature-title">高效查找</div>
<div class="feature-desc">二叉搜索树的查找时间是 O(log n)</div>
</div>
<div class="feature-card">
<div class="feature-icon">🔄</div>
<div class="feature-title">多种遍历</div>
<div class="feature-desc">前序中序后序层序遍历</div>
</div>
</div>
</div>
<!-- 应用场景 -->
<div class="applications">
<div class="app-title">应用场景</div>
<div class="app-list">
<div class="app-item">
<span class="app-icon">📁</span>
<div class="app-content">
<div class="app-name">文件系统</div>
<div class="app-desc">文件夹和文件的层级组织</div>
</div>
</div>
<div class="app-item">
<span class="app-icon">🌐</span>
<div class="app-content">
<div class="app-name">HTML DOM</div>
<div class="app-desc">网页元素的嵌套结构</div>
</div>
</div>
<div class="app-item">
<span class="app-icon">🏢</span>
<div class="app-content">
<div class="app-name">组织架构</div>
<div class="app-desc">公司的管理层级关系</div>
</div>
</div>
<div class="app-item">
<span class="app-icon">🌲</span>
<div class="app-content">
<div class="app-name">决策树</div>
<div class="app-desc">机器学习的分类算法</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeTreeType = ref('binary')
const treeTypes = [
{ id: 'binary', name: '二叉搜索树', icon: '🌳' },
{ id: 'filesystem', name: '文件系统', icon: '📁' },
{ id: 'dom', name: 'DOM 树', icon: '🌐' }
]
const binaryTreeNodes = [
{ id: 1, value: 50, x: 300, y: 40, isRoot: true },
{ id: 2, value: 30, x: 180, y: 120 },
{ id: 3, value: 70, x: 420, y: 120 },
{ id: 4, value: 20, x: 100, y: 200, isLeaf: true },
{ id: 5, value: 40, x: 260, y: 200, isLeaf: true },
{ id: 6, value: 60, x: 340, y: 200, isLeaf: true },
{ id: 7, value: 80, x: 500, y: 200, isLeaf: true }
]
const binaryTreeLines = [
{ id: 1, x1: 300, y1: 65, x2: 180, y2: 95 },
{ id: 2, x1: 300, y1: 65, x2: 420, y2: 95 },
{ id: 3, x1: 180, y1: 145, x2: 100, y2: 175 },
{ id: 4, x1: 180, y1: 145, x2: 260, y2: 175 },
{ id: 5, x1: 420, y1: 145, x2: 340, y2: 175 },
{ id: 6, x1: 420, y1: 145, x2: 500, y2: 175 }
]
</script>
<style scoped>
.tree-structure-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .icon { font-size: 1.5rem; }
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.tree-selector {
margin-bottom: 2rem;
}
.selector-label {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.selector-buttons {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
}
.type-btn {
padding: 0.6rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.type-btn:hover {
border-color: var(--vp-c-brand);
}
.type-btn.active {
background: var(--vp-c-brand);
border-color: var(--vp-c-brand);
color: white;
}
.tree-display {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.tree-canvas {
width: 100%;
max-width: 600px;
margin: 0 auto;
}
.tree-svg {
width: 100%;
height: auto;
}
.tree-node circle {
transition: all 0.3s;
}
.tree-node:hover circle {
fill: var(--vp-c-brand);
stroke-width: 3;
}
.filesystem-tree {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.fs-root {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.fs-node {
padding: 0.5rem 0.75rem;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
font-size: 0.9rem;
}
.fs-node.root {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
font-weight: 600;
}
.fs-children {
margin-left: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dom-tree {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
@media (max-width: 768px) {
.dom-tree {
grid-template-columns: 1fr;
}
}
.dom-preview {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.preview-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.preview-html {
font-family: 'Courier New', monospace;
font-size: 0.8rem;
line-height: 1.8;
color: var(--vp-c-text-2);
background: var(--vp-c-bg-soft);
padding: 1rem;
border-radius: 6px;
}
.dom-structure {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
}
.structure-title {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.tree-nested {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dom-node {
display: flex;
gap: 0.5rem;
align-items: center;
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border-radius: 4px;
}
.dom-children {
margin-left: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.node-tag {
padding: 0.25rem 0.5rem;
background: var(--vp-c-brand);
color: white;
border-radius: 4px;
font-size: 0.8rem;
font-weight: 600;
}
.node-class {
padding: 0.25rem 0.5rem;
background: #f59e0b;
color: white;
border-radius: 4px;
font-size: 0.75rem;
}
.node-text {
color: var(--vp-c-text-2);
font-size: 0.8rem;
font-style: italic;
}
.tree-features {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.features-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.feature-card {
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
text-align: center;
}
.feature-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.feature-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.feature-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.applications {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.app-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.app-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.app-item {
display: flex;
gap: 0.75rem;
padding: 1rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.app-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.app-content {
flex: 1;
}
.app-name {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 0.35rem;
}
.app-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
</style>