refactor: 重构 api-intro、api-design、transistor-to-cpu 组件为紧凑布局

- 重构 api-intro 7 个 Vue 组件为更紧凑的左右布局
- 重构 api-design 相关组件
- 重构 transistor-to-cpu 相关组件
- 统一使用 demo-root -> demo-header -> demo-layout -> info-box 结构
- 扩写文章内容为 MIT 讲义风格
This commit is contained in:
sanbuphy
2026-02-23 01:50:43 +08:00
parent 2a0fdd3392
commit 1062e2e16f
68 changed files with 4455 additions and 3469 deletions
@@ -1,16 +1,30 @@
<template>
<div class="adder-demo">
<div class="demo-label">二进制加法器 输入 015 的两个数观察逐位计算过程</div>
<div class="demo-label">
二进制加法器 输入 015 的两个数观察逐位计算过程
</div>
<div class="control-row">
<label class="input-group">
<span class="input-label">A</span>
<input v-model.number="inputA" type="number" min="0" max="15" class="num-input" />
<input
v-model.number="inputA"
type="number"
min="0"
max="15"
class="num-input"
/>
</label>
<span class="op-sign">+</span>
<label class="input-group">
<span class="input-label">B</span>
<input v-model.number="inputB" type="number" min="0" max="15" class="num-input" />
<input
v-model.number="inputB"
type="number"
min="0"
max="15"
class="num-input"
/>
</label>
<span class="op-sign">=</span>
<span class="result-num">{{ resultDec }}</span>
@@ -20,21 +34,39 @@
<div class="binary-row">
<span class="binary-label">A</span>
<span class="binary-bits">
<span v-for="(b, i) in bitsA" :key="'a'+i" class="bit" :class="{ hl: activeBit === (3 - i) }">{{ b }}</span>
<span
v-for="(b, i) in bitsA"
:key="'a' + i"
class="bit"
:class="{ hl: activeBit === 3 - i }"
>{{ b }}</span
>
</span>
<span class="binary-dec">= {{ clampedA }}</span>
</div>
<div class="binary-row">
<span class="binary-label">B</span>
<span class="binary-bits">
<span v-for="(b, i) in bitsB" :key="'b'+i" class="bit" :class="{ hl: activeBit === (3 - i) }">{{ b }}</span>
<span
v-for="(b, i) in bitsB"
:key="'b' + i"
class="bit"
:class="{ hl: activeBit === 3 - i }"
>{{ b }}</span
>
</span>
<span class="binary-dec">= {{ clampedB }}</span>
</div>
<div class="binary-row sum-row">
<span class="binary-label">结果</span>
<span class="binary-bits">
<span v-for="(b, i) in bitsSum" :key="'s'+i" class="bit" :class="{ hl: activeBit === (3 - i) }">{{ b }}</span>
<span
v-for="(b, i) in bitsSum"
:key="'s' + i"
class="bit"
:class="{ hl: activeBit === 3 - i }"
>{{ b }}</span
>
</span>
<span class="binary-dec">= {{ fourBitResult }}</span>
</div>
@@ -45,7 +77,8 @@
<div class="stages-row">
<div
v-for="(stage, idx) in stages" :key="idx"
v-for="(stage, idx) in stages"
:key="idx"
class="stage-card"
:class="{ active: activeBit === stage.bitPos }"
@mouseenter="activeBit = stage.bitPos"
@@ -53,24 +86,40 @@
>
<div class="stage-head">
<span class="stage-pos">{{ stage.bitPos }}</span>
<span class="stage-type" :class="stage.carryIn !== null ? 'full' : 'half'">
<span
class="stage-type"
:class="stage.carryIn !== null ? 'full' : 'half'"
>
{{ stage.carryIn !== null ? '全加器' : '半加器' }}
</span>
</div>
<div class="stage-io">
<span class="io-item"><span class="io-tag a">A</span>{{ stage.a }}</span>
<span class="io-item"><span class="io-tag b">B</span>{{ stage.b }}</span>
<span v-if="stage.carryIn !== null" class="io-item"><span class="io-tag cin">Cin</span>{{ stage.carryIn }}</span>
<span class="io-item"
><span class="io-tag a">A</span>{{ stage.a }}</span
>
<span class="io-item"
><span class="io-tag b">B</span>{{ stage.b }}</span
>
<span v-if="stage.carryIn !== null" class="io-item"
><span class="io-tag cin">Cin</span>{{ stage.carryIn }}</span
>
</div>
<div class="stage-divider"></div>
<div class="stage-io">
<span class="io-item"><span class="io-tag s">S</span><strong>{{ stage.sum }}</strong></span>
<span class="io-item"><span class="io-tag cout">C</span>{{ stage.carryOut }}</span>
<span class="io-item"
><span class="io-tag s">S</span
><strong>{{ stage.sum }}</strong></span
>
<span class="io-item"
><span class="io-tag cout">C</span>{{ stage.carryOut }}</span
>
</div>
</div>
</div>
<div class="demo-caption">鼠标悬停某一位查看该位加法器的输入 / 输出 · 就像手算竖式"逢二进一"</div>
<div class="demo-caption">
鼠标悬停某一位查看该位加法器的输入 / 输出 · 就像手算竖式"逢二进一"
</div>
</div>
</template>
@@ -90,8 +139,12 @@ function clamp(n) {
const clampedA = computed(() => clamp(inputA.value))
const clampedB = computed(() => clamp(inputB.value))
const bitsA = computed(() => (clampedA.value >>> 0).toString(2).padStart(4, '0').split(''))
const bitsB = computed(() => (clampedB.value >>> 0).toString(2).padStart(4, '0').split(''))
const bitsA = computed(() =>
(clampedA.value >>> 0).toString(2).padStart(4, '0').split('')
)
const bitsB = computed(() =>
(clampedB.value >>> 0).toString(2).padStart(4, '0').split('')
)
const stages = computed(() => {
const A = clampedA.value
@@ -106,10 +159,17 @@ const stages = computed(() => {
sum = a ^ b
carryOut = a & b
} else {
sum = (a ^ b) ^ carryIn
sum = a ^ b ^ carryIn
carryOut = (a & b) | (carryIn & (a ^ b))
}
result.push({ bitPos: i, a, b, carryIn: carryIn === null ? null : carryIn, sum, carryOut })
result.push({
bitPos: i,
a,
b,
carryIn: carryIn === null ? null : carryIn,
sum,
carryOut
})
carryIn = carryOut
}
return result
@@ -126,7 +186,9 @@ const fourBitResult = computed(() =>
const overflow = computed(() => clampedA.value + clampedB.value > 15)
const resultDec = computed(() =>
overflow.value ? `${fourBitResult.value}(溢出)` : String(fourBitResult.value)
overflow.value
? `${fourBitResult.value}(溢出)`
: String(fourBitResult.value)
)
</script>
@@ -334,11 +396,21 @@ const resultDec = computed(() =>
font-family: system-ui;
}
.io-tag.a { background: var(--vp-c-brand-1); }
.io-tag.b { background: #8b5cf6; }
.io-tag.cin { background: #d97706; }
.io-tag.s { background: var(--vp-c-green-1, #16a34a); }
.io-tag.cout { background: #d97706; }
.io-tag.a {
background: var(--vp-c-brand-1);
}
.io-tag.b {
background: #8b5cf6;
}
.io-tag.cin {
background: #d97706;
}
.io-tag.s {
background: var(--vp-c-green-1, #16a34a);
}
.io-tag.cout {
background: #d97706;
}
.stage-divider {
height: 1px;
@@ -7,8 +7,8 @@
<div class="demo-content">
<div class="algorithm-tabs">
<button
v-for="algo in algorithms"
<button
v-for="algo in algorithms"
:key="algo.name"
:class="['tab-btn', { active: activeAlgo === algo.name }]"
@click="activeAlgo = algo.name"
@@ -24,10 +24,7 @@
</div>
<div class="visual-content">
<div
v-if="activeAlgo === '二分查找'"
class="binary-search"
>
<div v-if="activeAlgo === '二分查找'" class="binary-search">
<div class="search-input">
<span>在有序数组中查找</span>
<input
@@ -35,20 +32,15 @@
type="number"
class="num-input"
placeholder="输入数字"
>
<button
class="search-btn"
@click="runBinarySearch"
>
查找
</button>
/>
<button class="search-btn" @click="runBinarySearch">查找</button>
</div>
<div class="array-display">
<div
v-for="(num, i) in sortedArray"
<div
v-for="(num, i) in sortedArray"
:key="i"
class="array-cell"
:class="{
:class="{
highlight: i >= searchRange.left && i <= searchRange.right,
found: i === foundIndex,
mid: i === midIndex
@@ -57,44 +49,27 @@
{{ num }}
</div>
</div>
<div
v-if="searchSteps.length"
class="search-info"
>
<div
v-for="(step, i) in searchSteps"
:key="i"
class="step"
>
<div v-if="searchSteps.length" class="search-info">
<div v-for="(step, i) in searchSteps" :key="i" class="step">
{{ step }}
</div>
</div>
</div>
<div
v-else-if="activeAlgo === '排序'"
class="sorting"
>
<div v-else-if="activeAlgo === '排序'" class="sorting">
<div class="sort-controls">
<button
class="sort-btn"
@click="resetArray"
>
重置数组
</button>
<button
class="sort-btn"
@click="runSort"
>
开始排序
</button>
<button class="sort-btn" @click="resetArray">重置数组</button>
<button class="sort-btn" @click="runSort">开始排序</button>
</div>
<div class="array-display">
<div
v-for="(num, i) in sortArray"
<div
v-for="(num, i) in sortArray"
:key="i"
class="array-cell"
:class="{ comparing: comparingIndices.includes(i), sorted: sortedIndices.includes(i) }"
:class="{
comparing: comparingIndices.includes(i),
sorted: sortedIndices.includes(i)
}"
>
{{ num }}
</div>
@@ -104,10 +79,7 @@
</div>
</div>
<div
v-else-if="activeAlgo === '递归'"
class="recursion"
>
<div v-else-if="activeAlgo === '递归'" class="recursion">
<div class="recursion-input">
<span>计算斐波那契数列第</span>
<input
@@ -116,28 +88,15 @@
min="1"
max="15"
class="num-input"
>
/>
<span></span>
<button
class="calc-btn"
@click="calcFib"
>
计算
</button>
<button class="calc-btn" @click="calcFib">计算</button>
</div>
<div
v-if="fibResult !== null"
class="fib-result"
>
<div v-if="fibResult !== null" class="fib-result">
<span class="result-value">F({{ fibN }}) = {{ fibResult }}</span>
</div>
<div
v-if="fibSteps.length"
class="recursion-tree"
>
<div class="tree-title">
递归调用过程
</div>
<div v-if="fibSteps.length" class="recursion-tree">
<div class="tree-title">递归调用过程</div>
<div class="tree-content">
<div
v-for="(step, i) in fibSteps.slice(0, 8)"
@@ -146,20 +105,14 @@
>
{{ step }}
</div>
<div
v-if="fibSteps.length > 8"
class="tree-more"
>
<div v-if="fibSteps.length > 8" class="tree-more">
... {{ fibSteps.length }} 次调用
</div>
</div>
</div>
</div>
<div
v-else-if="activeAlgo === '贪心'"
class="greedy"
>
<div v-else-if="activeAlgo === '贪心'" class="greedy">
<div class="greedy-desc">
硬币找零问题用最少的硬币凑出指定金额
</div>
@@ -170,30 +123,18 @@
type="number"
min="1"
class="num-input"
>
<button
class="calc-btn"
@click="calcCoins"
>
计算
</button>
/>
<button class="calc-btn" @click="calcCoins">计算</button>
</div>
<div class="coins-available">
可用硬币{{ coins.join(', ') }}
</div>
<div
v-if="coinResult.length"
class="coin-result"
>
<div class="result-title">
找零方案
</div>
<div v-if="coinResult.length" class="coin-result">
<div class="result-title">找零方案</div>
<div class="coin-list">
<span
v-for="(c, i) in coinResult"
:key="i"
class="coin"
>{{ c }}</span>
<span v-for="(c, i) in coinResult" :key="i" class="coin"
>{{ c }}</span
>
</div>
<div class="result-summary">
{{ coinResult.length }} 枚硬币
@@ -204,20 +145,11 @@
</div>
<div class="complexity-info">
<div class="info-title">
时间复杂度速查
</div>
<div class="info-title">时间复杂度速查</div>
<div class="complexity-list">
<div
v-for="c in complexities"
:key="c.name"
class="complexity-item"
>
<div v-for="c in complexities" :key="c.name" class="complexity-item">
<span class="c-name">{{ c.name }}</span>
<span
class="c-value"
:class="c.class"
>{{ c.value }}</span>
<span class="c-value" :class="c.class">{{ c.value }}</span>
<span class="c-desc">{{ c.desc }}</span>
</div>
</div>
@@ -225,7 +157,8 @@
</div>
<div class="info-box">
<strong>核心思想</strong>算法是解决问题的方法好的算法能让程序效率提升几个数量级理解算法思维比记住具体算法更重要
<strong>核心思想</strong
>算法是解决问题的方法好的算法能让程序效率提升几个数量级理解算法思维比记住具体算法更重要
</div>
</div>
</template>
@@ -243,7 +176,7 @@ const algorithms = [
]
const currentAlgo = computed(() => {
return algorithms.find(a => a.name === activeAlgo.value)
return algorithms.find((a) => a.name === activeAlgo.value)
})
const sortedArray = ref([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25])
@@ -259,25 +192,31 @@ const runBinarySearch = () => {
midIndex.value = -1
let left = 0
let right = sortedArray.value.length - 1
while (left <= right) {
const mid = Math.floor((left + right) / 2)
midIndex.value = mid
searchRange.left = left
searchRange.right = right
searchSteps.value.push(`查找范围 [${left}, ${right}],中间位置 ${mid},值 ${sortedArray.value[mid]}`)
searchSteps.value.push(
`查找范围 [${left}, ${right}],中间位置 ${mid},值 ${sortedArray.value[mid]}`
)
if (sortedArray.value[mid] === searchTarget.value) {
foundIndex.value = mid
searchSteps.value.push(`找到目标 ${searchTarget.value} 在位置 ${mid}`)
return
} else if (sortedArray.value[mid] < searchTarget.value) {
left = mid + 1
searchSteps.value.push(`${sortedArray.value[mid]} < ${searchTarget.value},在右半部分继续查找`)
searchSteps.value.push(
`${sortedArray.value[mid]} < ${searchTarget.value},在右半部分继续查找`
)
} else {
right = mid - 1
searchSteps.value.push(`${sortedArray.value[mid]} > ${searchTarget.value},在左半部分继续查找`)
searchSteps.value.push(
`${sortedArray.value[mid]} > ${searchTarget.value},在左半部分继续查找`
)
}
}
searchSteps.value.push(`未找到目标 ${searchTarget.value}`)
@@ -299,18 +238,18 @@ const runSort = async () => {
sortedIndices.value = []
const arr = [...sortArray.value]
const n = arr.length
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
comparingIndices.value = [j, j + 1]
sortStatus.value = `比较 ${arr[j]}${arr[j + 1]}`
await new Promise(r => setTimeout(r, 300))
await new Promise((r) => setTimeout(r, 300))
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
sortArray.value = [...arr]
sortStatus.value = `交换 ${arr[j + 1]}${arr[j]}`
await new Promise(r => setTimeout(r, 200))
await new Promise((r) => setTimeout(r, 200))
}
}
sortedIndices.value.push(n - i - 1)
@@ -353,7 +292,12 @@ const complexities = [
{ name: 'O(1)', value: '常数', desc: '最优,如数组访问', class: 'good' },
{ name: 'O(log n)', value: '对数', desc: '很好,如二分查找', class: 'good' },
{ name: 'O(n)', value: '线性', desc: '一般,如遍历', class: 'mid' },
{ name: 'O(n log n)', value: '线性对数', desc: '可接受,如快速排序', class: 'mid' },
{
name: 'O(n log n)',
value: '线性对数',
desc: '可接受,如快速排序',
class: 'mid'
},
{ name: 'O(n²)', value: '平方', desc: '较慢,如冒泡排序', class: 'bad' },
{ name: 'O(2ⁿ)', value: '指数', desc: '很慢,如暴力递归', class: 'bad' }
]
@@ -375,8 +319,15 @@ const complexities = [
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.algorithm-tabs {
display: flex;
@@ -422,7 +373,9 @@ const complexities = [
margin-left: 0.5rem;
}
.search-input, .greedy-input, .recursion-input {
.search-input,
.greedy-input,
.recursion-input {
display: flex;
align-items: center;
gap: 0.5rem;
@@ -438,7 +391,9 @@ const complexities = [
background: var(--vp-c-bg-alt);
}
.search-btn, .sort-btn, .calc-btn {
.search-btn,
.sort-btn,
.calc-btn {
padding: 0.25rem 0.75rem;
background: var(--vp-c-brand);
color: white;
@@ -487,7 +442,8 @@ const complexities = [
background: var(--vp-c-success-soft);
}
.search-info, .sort-info {
.search-info,
.sort-info {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
@@ -614,9 +570,15 @@ const complexities = [
min-width: 50px;
}
.c-value.good { color: var(--vp-c-success); }
.c-value.mid { color: var(--vp-c-warning); }
.c-value.bad { color: var(--vp-c-danger); }
.c-value.good {
color: var(--vp-c-success);
}
.c-value.mid {
color: var(--vp-c-warning);
}
.c-value.bad {
color: var(--vp-c-danger);
}
.c-desc {
color: var(--vp-c-text-2);
@@ -632,5 +594,4 @@ const complexities = [
display: flex;
gap: 0.25rem;
}
</style>
@@ -9,9 +9,9 @@
<div class="analogy-content">
<div class="analogy-icon">📖</div>
<div class="analogy-text">
<strong>算法就像菜谱</strong><br>
食材 = 数据<br>
烹饪步骤 = 算法<br>
<strong>算法就像菜谱</strong><br />
食材 = 数据<br />
烹饪步骤 = 算法<br />
美味菜肴 = 结果
</div>
</div>
@@ -49,8 +49,12 @@
<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 class="analogy-scenario">
{{ currentCategory.analogy.scenario }}
</div>
<div class="analogy-explanation">
{{ currentCategory.analogy.explanation }}
</div>
</div>
</div>
@@ -58,7 +62,9 @@
<div class="section-title">时间复杂度</div>
<div class="complexity-display">
<div class="complexity-bigO">{{ currentCategory.complexity }}</div>
<div class="complexity-desc">{{ currentCategory.complexityDesc }}</div>
<div class="complexity-desc">
{{ currentCategory.complexityDesc }}
</div>
</div>
</div>
@@ -140,7 +146,8 @@ const categories = [
idea: '从数据集合中找到特定元素的过程',
analogy: {
scenario: '在字典里查单词',
explanation: '顺序查找 = 从第一页翻到最后一页;二分查找 = 直接翻到中间,判断在前半还是后半'
explanation:
'顺序查找 = 从第一页翻到最后一页;二分查找 = 直接翻到中间,判断在前半还是后半'
},
complexity: 'O(log n)',
complexityDesc: '二分查找非常快,每次排除一半数据',
@@ -154,7 +161,8 @@ const categories = [
idea: '将无序数据重新排列成有序序列',
analogy: {
scenario: '整理扑克牌',
explanation: '插入排序 = 每次拿一张牌插到正确的位置;快速排序 = 把牌分成大小两堆,递归整理'
explanation:
'插入排序 = 每次拿一张牌插到正确的位置;快速排序 = 把牌分成大小两堆,递归整理'
},
complexity: 'O(n log n)',
complexityDesc: '快速排序、归并排序是最高效的通用排序算法',
@@ -168,7 +176,8 @@ const categories = [
idea: '将大问题分解为相同类型的小问题',
analogy: {
scenario: '俄罗斯套娃',
explanation: '打开一个大娃娃,里面有个小一点的娃娃,再打开还有更小的...直到最小的一个'
explanation:
'打开一个大娃娃,里面有个小一点的娃娃,再打开还有更小的...直到最小的一个'
},
complexity: 'O(log n) 到 O(2ⁿ)',
complexityDesc: '取决于问题类型,二分查找递归很快,斐波那契递归较慢',
@@ -182,7 +191,8 @@ const categories = [
idea: '在每一步选择中都采取当前状态下最优的选择',
analogy: {
scenario: '找零钱',
explanation: '找 37 元零钱:先拿一张 20(最大可能),再拿 10、5、1、1,每次都选最大的面值'
explanation:
'找 37 元零钱:先拿一张 20(最大可能),再拿 10、5、1、1,每次都选最大的面值'
},
complexity: 'O(n) 或 O(n log n)',
complexityDesc: '通常很快,但可能得不到全局最优解',
@@ -196,7 +206,8 @@ const categories = [
idea: '将复杂问题分解为子问题,保存子问题的解',
analogy: {
scenario: '爬楼梯',
explanation: '要爬到第 n 级,可以从 n-1 级跨 1 步,或从 n-2 级跨 2 步,记住之前的结果避免重复计算'
explanation:
'要爬到第 n 级,可以从 n-1 级跨 1 步,或从 n-2 级跨 2 步,记住之前的结果避免重复计算'
},
complexity: 'O(n²) 或 O(n³)',
complexityDesc: '用空间换时间,比递归快很多',
@@ -206,12 +217,19 @@ const categories = [
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 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))
const currentCategory = computed(() =>
categories.find((c) => c.id === activeCategory.value)
)
</script>
<style scoped>
@@ -230,8 +248,14 @@ const currentCategory = computed(() => categories.find(c => c.id === activeCateg
margin-bottom: 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; }
.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);
@@ -344,7 +368,8 @@ const currentCategory = computed(() => categories.find(c => c.id === activeCateg
gap: 1.5rem;
}
.detail-section {}
.detail-section {
}
.section-title {
font-weight: 600;
@@ -66,7 +66,9 @@
<div class="section-title">时间复杂度</div>
<div class="complexity-box">
<div class="complexity-value">{{ currentParadigm.complexity }}</div>
<div class="complexity-note">{{ currentParadigm.complexityNote }}</div>
<div class="complexity-note">
{{ currentParadigm.complexityNote }}
</div>
</div>
</div>
</div>
@@ -216,7 +218,9 @@ const comparisonData = [
}
]
const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadigm.value))
const currentParadigm = computed(() =>
paradigms.find((p) => p.id === activeParadigm.value)
)
</script>
<style scoped>
@@ -235,8 +239,14 @@ const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadi
margin-bottom: 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; }
.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;
@@ -324,7 +334,8 @@ const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadi
gap: 1.5rem;
}
.detail-section {}
.detail-section {
}
.section-title {
font-weight: 600;
@@ -34,7 +34,11 @@
<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">
<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>
@@ -44,7 +48,11 @@
<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">
<div
v-for="(app, index) in currentProtocol.apps"
:key="index"
class="app-tag"
>
{{ app.icon }} {{ app.name }}
</div>
</div>
@@ -268,8 +276,14 @@ const currentProtocol = computed(() => protocolDetails[activeProtocol.value])
margin-bottom: 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; }
.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;
@@ -7,8 +7,8 @@
<div class="code-input">
<div class="input-title">输入代码</div>
<textarea
v-model="sourceCode"
<textarea
v-model="sourceCode"
class="code-textarea"
placeholder="输入 C 语言代码..."
></textarea>
@@ -17,11 +17,7 @@
<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 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>
@@ -35,11 +31,7 @@
<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 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>
@@ -147,8 +139,14 @@ const outputFiles = [
margin-bottom: 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; }
.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;
@@ -28,7 +28,9 @@
<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 v-if="index < translationSteps.length - 1" class="step-arrow">
</div>
</div>
</div>
</div>
@@ -42,11 +44,7 @@
</div>
<div class="token-arrow"></div>
<div class="tokens-list">
<div
v-for="(token, index) in tokens"
:key="index"
class="token-item"
>
<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>
@@ -127,9 +125,7 @@
<div class="opt-code">x = 10</div>
</div>
</div>
<div class="opt-note">
编译器会自动优化代码提高运行效率
</div>
<div class="opt-note">编译器会自动优化代码提高运行效率</div>
</div>
</div>
</div>
@@ -196,8 +192,14 @@ const tokens = [
margin-bottom: 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; }
.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;
@@ -105,8 +105,7 @@
</div>
</template>
<script setup>
</script>
<script setup></script>
<style scoped>
.data-encoding-basics-demo {
@@ -124,8 +123,14 @@
margin-bottom: 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; }
.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;
@@ -22,7 +22,11 @@
<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">
<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>
@@ -44,7 +48,11 @@
<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
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>
@@ -67,7 +75,8 @@ const stages = [
name: '数据输入',
icon: '⌨️',
title: '阶段 1:数据输入',
description: '用户通过各种输入设备(键盘、鼠标、触摸屏、麦克风等)将信息输入到计算机系统中。',
description:
'用户通过各种输入设备(键盘、鼠标、触摸屏、麦克风等)将信息输入到计算机系统中。',
example: {
label: '用户输入文字',
items: [
@@ -83,7 +92,8 @@ const stages = [
name: '数据处理',
icon: '🔄',
title: '阶段 2:数据处理',
description: 'CPU 对输入的数据进行计算、转换、格式化等操作,应用程序根据业务逻辑处理数据。',
description:
'CPU 对输入的数据进行计算、转换、格式化等操作,应用程序根据业务逻辑处理数据。',
example: {
label: '文本编辑器处理',
items: [
@@ -99,7 +109,8 @@ const stages = [
name: '数据存储',
icon: '💾',
title: '阶段 3:数据存储',
description: '处理后的数据被保存到存储设备中(内存、硬盘、SSD、云存储等),以便后续使用。',
description:
'处理后的数据被保存到存储设备中(内存、硬盘、SSD、云存储等),以便后续使用。',
example: {
label: '保存文档',
items: [
@@ -115,7 +126,8 @@ const stages = [
name: '数据传输',
icon: '📡',
title: '阶段 4:数据传输',
description: '数据通过网络(局域网、互联网)或内部总线从一个位置传输到另一个位置。',
description:
'数据通过网络(局域网、互联网)或内部总线从一个位置传输到另一个位置。',
example: {
label: '上传文件',
items: [
@@ -131,7 +143,8 @@ const stages = [
name: '数据输出',
icon: '🖥️',
title: '阶段 5:数据输出',
description: '数据通过输出设备(显示器、打印机、扬声器等)呈现给用户,或传输给其他系统。',
description:
'数据通过输出设备(显示器、打印机、扬声器等)呈现给用户,或传输给其他系统。',
example: {
label: '显示网页',
items: [
@@ -184,8 +197,14 @@ const keyPoints = [
margin-bottom: 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; }
.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;
@@ -11,13 +11,22 @@
<div
v-for="device in devices"
:key="device.id"
:class="['lan-device', { active: activeDevice === device.id, sender: device.role === 'sender', receiver: device.role === 'receiver' }]"
: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 v-if="device.role" class="device-role">
{{ device.roleText }}
</div>
</div>
</div>
@@ -77,7 +86,9 @@
<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>
<span class="answer-text"
>我是我的 MAC 地址是 00:11:22:33:44:66</span
>
</div>
</div>
</div>
@@ -194,8 +205,14 @@ const transferSteps = [
margin-bottom: 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; }
.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);
@@ -7,8 +7,8 @@
<div class="demo-content">
<div class="structure-tabs">
<button
v-for="s in structures"
<button
v-for="s in structures"
:key="s.name"
:class="['tab-btn', { active: activeStructure === s.name }]"
@click="activeStructure = s.name"
@@ -24,16 +24,9 @@
</div>
<div class="visual-content">
<div
v-if="activeStructure === '数组'"
class="array-visual"
>
<div v-if="activeStructure === '数组'" class="array-visual">
<div class="array-container">
<div
v-for="(item, i) in arrayData"
:key="i"
class="array-item"
>
<div v-for="(item, i) in arrayData" :key="i" class="array-item">
<span class="index">{{ i }}</span>
<span class="value">{{ item }}</span>
</div>
@@ -43,21 +36,13 @@
</div>
</div>
<div
v-else-if="activeStructure === '链表'"
class="linked-visual"
>
<div v-else-if="activeStructure === '链表'" class="linked-visual">
<div class="linked-container">
<div
v-for="(item, i) in linkedData"
:key="i"
class="linked-node"
>
<div v-for="(item, i) in linkedData" :key="i" class="linked-node">
<span class="node-value">{{ item.value }}</span>
<span
v-if="i < linkedData.length - 1"
class="node-arrow"
></span>
<span v-if="i < linkedData.length - 1" class="node-arrow"
></span
>
</div>
</div>
<div class="operation-hint">
@@ -65,104 +50,53 @@
</div>
</div>
<div
v-else-if="activeStructure === '栈'"
class="stack-visual"
>
<div v-else-if="activeStructure === '栈'" class="stack-visual">
<div class="stack-container">
<div
v-for="(item, i) in stackData"
:key="i"
class="stack-item"
>
<div v-for="(item, i) in stackData" :key="i" class="stack-item">
{{ item }}
</div>
<div class="stack-bottom">
栈底
</div>
<div class="stack-bottom">栈底</div>
</div>
<div class="stack-ops">
<button
class="op-btn"
@click="pushStack"
>
入栈 Push
</button>
<button
class="op-btn"
@click="popStack"
>
出栈 Pop
</button>
</div>
<div class="operation-hint">
后进先出 (LIFO)操作都是 O(1)
<button class="op-btn" @click="pushStack">入栈 Push</button>
<button class="op-btn" @click="popStack">出栈 Pop</button>
</div>
<div class="operation-hint">后进先出 (LIFO)操作都是 O(1)</div>
</div>
<div
v-else-if="activeStructure === '队列'"
class="queue-visual"
>
<div v-else-if="activeStructure === '队列'" class="queue-visual">
<div class="queue-container">
<span class="queue-label"> </span>
<div
v-for="(item, i) in queueData"
:key="i"
class="queue-item"
>
<div v-for="(item, i) in queueData" :key="i" class="queue-item">
{{ item }}
</div>
<span class="queue-label"> </span>
</div>
<div class="queue-ops">
<button
class="op-btn"
@click="enqueue"
>
入队
</button>
<button
class="op-btn"
@click="dequeue"
>
出队
</button>
</div>
<div class="operation-hint">
先进先出 (FIFO)操作都是 O(1)
<button class="op-btn" @click="enqueue">入队</button>
<button class="op-btn" @click="dequeue">出队</button>
</div>
<div class="operation-hint">先进先出 (FIFO)操作都是 O(1)</div>
</div>
<div
v-else-if="activeStructure === '哈希表'"
class="hash-visual"
>
<div v-else-if="activeStructure === '哈希表'" class="hash-visual">
<div class="hash-container">
<div
v-for="(bucket, i) in hashData"
:key="i"
class="hash-bucket"
>
<div v-for="(bucket, i) in hashData" :key="i" class="hash-bucket">
<span class="bucket-index">{{ i }}</span>
<div class="bucket-items">
<span
v-for="(item, j) in bucket"
:key="j"
class="bucket-item"
>{{ item }}</span>
>{{ item }}</span
>
</div>
</div>
</div>
<div class="operation-hint">
查找/插入/删除平均 O(1)最坏 O(n)
</div>
<div class="operation-hint">查找/插入/删除平均 O(1)最坏 O(n)</div>
</div>
<div
v-else-if="activeStructure === '树'"
class="tree-visual"
>
<div v-else-if="activeStructure === '树'" class="tree-visual">
<div class="tree-container">
<div class="tree-level">
<div class="tree-node root">
@@ -192,17 +126,13 @@
</div>
</div>
</div>
<div class="operation-hint">
查找/插入/删除 O(log n)遍历 O(n)
</div>
<div class="operation-hint">查找/插入/删除 O(log n)遍历 O(n)</div>
</div>
</div>
</div>
<div class="complexity-table">
<div class="table-title">
时间复杂度对比
</div>
<div class="table-title">时间复杂度对比</div>
<table>
<thead>
<tr>
@@ -216,63 +146,31 @@
<tbody>
<tr>
<td>访问</td>
<td class="good">
O(1)
</td>
<td class="bad">
O(n)
</td>
<td class="good">
O(1)
</td>
<td class="mid">
O(log n)
</td>
<td class="good">O(1)</td>
<td class="bad">O(n)</td>
<td class="good">O(1)</td>
<td class="mid">O(log n)</td>
</tr>
<tr>
<td>查找</td>
<td class="bad">
O(n)
</td>
<td class="bad">
O(n)
</td>
<td class="good">
O(1)
</td>
<td class="mid">
O(log n)
</td>
<td class="bad">O(n)</td>
<td class="bad">O(n)</td>
<td class="good">O(1)</td>
<td class="mid">O(log n)</td>
</tr>
<tr>
<td>插入</td>
<td class="bad">
O(n)
</td>
<td class="good">
O(1)
</td>
<td class="good">
O(1)
</td>
<td class="mid">
O(log n)
</td>
<td class="bad">O(n)</td>
<td class="good">O(1)</td>
<td class="good">O(1)</td>
<td class="mid">O(log n)</td>
</tr>
<tr>
<td>删除</td>
<td class="bad">
O(n)
</td>
<td class="good">
O(1)
</td>
<td class="good">
O(1)
</td>
<td class="mid">
O(log n)
</td>
<td class="bad">O(n)</td>
<td class="good">O(1)</td>
<td class="good">O(1)</td>
<td class="mid">O(log n)</td>
</tr>
</tbody>
</table>
@@ -280,7 +178,8 @@
</div>
<div class="info-box">
<strong>核心思想</strong>数据结构是数据的"容器"不同的容器有不同的特点选择合适的数据结构能让程序效率提升几个数量级
<strong>核心思想</strong
>数据结构是数据的"容器"不同的容器有不同的特点选择合适的数据结构能让程序效率提升几个数量级
</div>
</div>
</template>
@@ -300,7 +199,7 @@ const structures = [
]
const currentStructure = computed(() => {
return structures.find(s => s.name === activeStructure.value)
return structures.find((s) => s.name === activeStructure.value)
})
const arrayData = ref([10, 20, 30, 40, 50, 60, 70, 80])
@@ -382,8 +281,15 @@ const treeData = ref({
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.structure-tabs {
display: flex;
@@ -500,7 +406,8 @@ const treeData = ref({
margin-top: 0.25rem;
}
.stack-ops, .queue-ops {
.stack-ops,
.queue-ops {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
@@ -626,7 +533,8 @@ table {
font-size: 0.8rem;
}
th, td {
th,
td {
border: 1px solid var(--vp-c-divider);
padding: 0.35rem;
text-align: center;
@@ -636,9 +544,16 @@ th {
background: var(--vp-c-bg);
}
.good { color: var(--vp-c-success); font-weight: bold; }
.mid { color: var(--vp-c-warning); }
.bad { color: var(--vp-c-danger); }
.good {
color: var(--vp-c-success);
font-weight: bold;
}
.mid {
color: var(--vp-c-warning);
}
.bad {
color: var(--vp-c-danger);
}
.info-box {
background: var(--vp-c-bg-alt);
@@ -650,5 +565,4 @@ th {
display: flex;
gap: 0.25rem;
}
</style>
@@ -152,11 +152,7 @@ const categories = [
icon: '🗂️',
desc: '通过关键词快速查找',
examples: ['哈希表', '字典', '集合'],
features: [
'通过键值对存储数据',
'查找速度极快',
'数据之间没有顺序关系'
],
features: ['通过键值对存储数据', '查找速度极快', '数据之间没有顺序关系'],
scenarios: [
{
icon: '📖',
@@ -189,11 +185,7 @@ const categories = [
icon: '🌳',
desc: '层级关系,像家谱',
examples: ['二叉树', 'B 树', '堆'],
features: [
'一对多的层级关系',
'有明确的根节点',
'适合表示分类和层级'
],
features: ['一对多的层级关系', '有明确的根节点', '适合表示分类和层级'],
scenarios: [
{
icon: '📁',
@@ -226,11 +218,7 @@ const categories = [
icon: '🕸️',
desc: '复杂关系网络',
examples: ['有向图', '无向图', '网络图'],
features: [
'多对多的复杂关系',
'节点之间可以任意连接',
'可以表示复杂网络'
],
features: ['多对多的复杂关系', '节点之间可以任意连接', '可以表示复杂网络'],
scenarios: [
{
icon: '🗺️',
@@ -259,7 +247,9 @@ const categories = [
}
]
const currentCategory = computed(() => categories.find(c => c.id === activeCategory.value))
const currentCategory = computed(() =>
categories.find((c) => c.id === activeCategory.value)
)
</script>
<style scoped>
@@ -278,8 +268,14 @@ const currentCategory = computed(() => categories.find(c => c.id === activeCateg
margin-bottom: 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; }
.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;
@@ -383,7 +379,8 @@ const currentCategory = computed(() => categories.find(c => c.id === activeCateg
gap: 1.5rem;
}
.detail-section {}
.detail-section {
}
.section-title {
font-weight: 600;
@@ -24,7 +24,9 @@
<!-- 推荐结果 -->
<div v-if="activeScenario" class="recommendation">
<div class="rec-header">
<span class="rec-title">推荐使用{{ currentScenario.recommendation }}</span>
<span class="rec-title"
>推荐使用{{ currentScenario.recommendation }}</span
>
</div>
<div class="rec-reason">
@@ -153,11 +155,7 @@ const scenarios = [
name: '后进先出',
desc: '最后进入的最先处理',
recommendation: '栈',
reasons: [
'只能在栈顶操作',
'入栈出栈都是 O(1)',
'适合回溯和撤销操作'
],
reasons: ['只能在栈顶操作', '入栈出栈都是 O(1)', '适合回溯和撤销操作'],
example: '浏览器后退、编辑器撤销、函数调用栈'
},
{
@@ -166,11 +164,7 @@ const scenarios = [
name: '先进先出',
desc: '先来的先处理',
recommendation: '队列',
reasons: [
'一端入队,另一端出队',
'入队出队都是 O(1)',
'公平的调度方式'
],
reasons: ['一端入队,另一端出队', '入队出队都是 O(1)', '公平的调度方式'],
example: '打印队列、任务调度、消息队列'
},
{
@@ -179,11 +173,7 @@ const scenarios = [
name: '层级关系',
desc: '数据之间有父子层级关系',
recommendation: '树',
reasons: [
'清晰表达层级结构',
'查找效率 O(log n)',
'支持多种遍历方式'
],
reasons: ['清晰表达层级结构', '查找效率 O(log n)', '支持多种遍历方式'],
example: '文件系统、组织架构、HTML DOM'
},
{
@@ -192,11 +182,7 @@ const scenarios = [
name: '复杂关系',
desc: '数据之间有多对多的复杂连接',
recommendation: '图',
reasons: [
'可以表示任意关系',
'支持路径搜索算法',
'适合网络和社交关系'
],
reasons: ['可以表示任意关系', '支持路径搜索算法', '适合网络和社交关系'],
example: '社交网络、地图导航、网页链接'
}
]
@@ -211,7 +197,7 @@ const referenceTable = [
]
const currentScenario = computed(() => {
return scenarios.find(s => s.id === activeScenario.value)
return scenarios.find((s) => s.id === activeScenario.value)
})
</script>
@@ -231,8 +217,14 @@ const currentScenario = computed(() => {
margin-bottom: 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; }
.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;
@@ -298,8 +290,14 @@ const currentScenario = computed(() => {
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.rec-header {
@@ -7,8 +7,8 @@
<div class="demo-content">
<div class="encoding-tabs">
<button
v-for="tab in tabs"
<button
v-for="tab in tabs"
:key="tab.name"
:class="['tab-btn', { active: activeTab === tab.name }]"
@click="activeTab = tab.name"
@@ -20,24 +20,19 @@
<div class="encoding-area">
<div class="input-section">
<label>输入内容</label>
<input
v-model="inputValue"
<input
v-model="inputValue"
class="input-field"
:placeholder="currentTab.placeholder"
>
/>
</div>
<div class="output-section">
<div class="output-label">
编码结果
</div>
<div class="output-label">编码结果</div>
<div class="output-box">
<code>{{ encodedResult }}</code>
</div>
<div
v-if="currentTab.name === 'text'"
class="output-info"
>
<div v-if="currentTab.name === 'text'" class="output-info">
<span>字符数: {{ inputValue.length }}</span>
<span>字节数: {{ byteCount }}</span>
</div>
@@ -47,18 +42,22 @@
v-if="currentTab.name === 'text' && inputValue"
class="encoding-table"
>
<div class="table-title">
字符编码详情
</div>
<div class="table-title">字符编码详情</div>
<div class="char-list">
<div
v-for="(char, i) in inputValue.slice(0, 10)"
<div
v-for="(char, i) in inputValue.slice(0, 10)"
:key="i"
class="char-item"
>
<span class="char-display">{{ char }}</span>
<span class="char-unicode">U+{{ char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0') }}</span>
<span class="char-binary">{{ char.charCodeAt(0).toString(2).padStart(8, '0') }}</span>
<span class="char-unicode"
>U+{{
char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
}}</span
>
<span class="char-binary">{{
char.charCodeAt(0).toString(2).padStart(8, '0')
}}</span>
</div>
</div>
</div>
@@ -66,7 +65,9 @@
</div>
<div class="info-box">
<strong>核心思想</strong>所有数据最终都要变成 0 1不同类型的数据用不同的编码规则字符用 ASCII/Unicode数字用二进制图像用像素值
<strong>核心思想</strong>所有数据最终都要变成 0
1不同类型的数据用不同的编码规则字符用
ASCII/Unicode数字用二进制图像用像素值
</div>
</div>
</template>
@@ -84,21 +85,25 @@ const tabs = [
]
const currentTab = computed(() => {
const tab = tabs.find(t => t.name === activeTab.value)
const tab = tabs.find((t) => t.name === activeTab.value)
return {
...tab,
placeholder: tab.name === 'text' ? '输入文字...' :
tab.name === 'number' ? '输入数字...' : '输入颜色值(如 #FF5733)'
placeholder:
tab.name === 'text'
? '输入文字...'
: tab.name === 'number'
? '输入数字...'
: '输入颜色值(如 #FF5733)'
}
})
const encodedResult = computed(() => {
if (!inputValue.value) return ''
switch (activeTab.value) {
case 'text':
return Array.from(inputValue.value)
.map(c => c.charCodeAt(0).toString(2).padStart(8, '0'))
.map((c) => c.charCodeAt(0).toString(2).padStart(8, '0'))
.join(' ')
case 'number':
const num = parseInt(inputValue.value)
@@ -137,8 +142,15 @@ const byteCount = computed(() => {
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.encoding-tabs {
display: flex;
@@ -269,5 +281,4 @@ const byteCount = computed(() => {
display: flex;
gap: 0.25rem;
}
</style>
@@ -35,7 +35,9 @@
<div class="arrow"></div>
<div class="output-box">
<div class="box-label">编码后</div>
<div class="box-value code">{{ currentScenario.encoding.output }}</div>
<div class="box-value code">
{{ currentScenario.encoding.output }}
</div>
</div>
</div>
</div>
@@ -62,11 +64,15 @@
<div class="storage-info">
<div class="info-item">
<span class="info-label">位置:</span>
<span class="info-value">{{ currentScenario.storage.location }}</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>
<span class="info-value">{{
currentScenario.storage.size
}}</span>
</div>
</div>
</div>
@@ -83,7 +89,12 @@
<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">
<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>
@@ -93,11 +104,15 @@
<div class="transmission-info">
<div class="info-item">
<span class="info-label">协议:</span>
<span class="info-value">{{ currentScenario.transmission.protocol }}</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>
<span class="info-value">{{
currentScenario.transmission.path
}}</span>
</div>
</div>
</div>
@@ -107,11 +122,15 @@
<!-- 协作关系 -->
<div class="collab-relationships">
<div class="relationship-arrow encoding-to-storage">
<span class="arrow-text">{{ currentScenario.relationships.encodingToStorage }}</span>
<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-text">{{
currentScenario.relationships.storageToTransmission
}}</span>
<span class="arrow-icon">→</span>
</div>
</div>
@@ -121,7 +140,11 @@
<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
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>
@@ -347,8 +370,14 @@ const currentScenario = computed(() => scenarioData[activeScenario.value])
margin-bottom: 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; }
.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;
@@ -420,8 +449,13 @@ const currentScenario = computed(() => scenarioData[activeScenario.value])
border-bottom: 1px solid var(--vp-c-divider);
}
.stage-icon { font-size: 1.3rem; }
.stage-title { font-weight: 600; font-size: 0.95rem; }
.stage-icon {
font-size: 1.3rem;
}
.stage-title {
font-weight: 600;
font-size: 0.95rem;
}
.stage-content {
display: flex;
@@ -1,34 +1,32 @@
<template>
<div class="filesystem-demo">
<div class="demo-wrapper">
<!-- 文件树逻辑视角 -->
<div class="logical-view">
<div class="view-title">
<span>📁 你的视角 (文件系统)</span>
<span class="subtitle">漂亮整洁的目录树</span>
</div>
<div class="file-tree">
<div class="tree-node folder expanded">
<span class="icon">💾</span> D盘 (根目录)
</div>
<div class="tree-children">
<div class="tree-node folder expanded">
<span class="icon">📂</span> 照片
</div>
<div class="tree-children">
<div
class="tree-node file"
<div
class="tree-node file"
:class="{ active: activeFile === 'pet' }"
@click="selectFile('pet')"
>
<span class="icon">🖼</span> 宠物.jpg
<span class="size-badge">3 </span>
</div>
<div
class="tree-node file"
<div
class="tree-node file"
:class="{ active: activeFile === 'vacation' }"
@click="selectFile('vacation')"
>
@@ -41,8 +39,8 @@
<span class="icon">📂</span> 工作
</div>
<div class="tree-children">
<div
class="tree-node file"
<div
class="tree-node file"
:class="{ active: activeFile === 'doc' }"
@click="selectFile('doc')"
>
@@ -50,7 +48,6 @@
<span class="size-badge">4 </span>
</div>
</div>
</div>
</div>
</div>
@@ -58,7 +55,7 @@
<!-- 翻译官动画 -->
<div class="translator">
<div class="arrow"></div>
<div class="badge">文件系统账本<br/>(inode表)</div>
<div class="badge">文件系统账本<br />(inode表)</div>
<div class="arrow"></div>
</div>
@@ -68,39 +65,36 @@
<span>🖨 硬盘的视角 (物理存储)</span>
<span class="subtitle">无序零散的数据块</span>
</div>
<div class="disk-grid">
<div
v-for="block in 24"
<div
v-for="block in 24"
:key="block"
class="disk-block"
:class="[
getBlockOwner(block),
{ active: isBlockActive(block) }
]"
:class="[getBlockOwner(block), { active: isBlockActive(block) }]"
>
{{ block }}
</div>
</div>
</div>
</div>
<div class="explanation-box" v-if="activeFile">
<span v-if="activeFile === 'pet'">
💡 宠物.jpg 其实被切碎分别放在了第 3814 文件系统帮你做好了翻译你只需双击它
💡 宠物.jpg 其实被切碎分别放在了第 3814
文件系统帮你做好了翻译你只需双击它
</span>
<span v-if="activeFile === 'vacation'">
💡 旅游.png 放在了第 56
</span>
<span v-if="activeFile === 'doc'">
💡 总结.docx 被分散存放在 10111822 如果没有文件系统你得自己背下这些数字才能打开文件
💡 总结.docx 被分散存放在 10111822
如果没有文件系统你得自己背下这些数字才能打开文件
</span>
</div>
<div class="explanation-box default" v-else>
试着点击左侧的文件看看它们在硬盘里到底长什么样
</div>
</div>
</template>
@@ -160,7 +154,8 @@ const isBlockActive = (block) => {
}
}
.logical-view, .physical-view {
.logical-view,
.physical-view {
flex: 1;
background: var(--vp-c-bg-alt);
border-radius: 10px;
@@ -278,20 +273,38 @@ const isBlockActive = (block) => {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.disk-block.owner-pet { background: rgba(16, 185, 129, 0.1); border-color: rgba(16, 185, 129, 0.3); }
.disk-block.owner-vacation { background: rgba(59, 130, 246, 0.1); border-color: rgba(59, 130, 246, 0.3); }
.disk-block.owner-doc { background: rgba(245, 158, 11, 0.1); border-color: rgba(245, 158, 11, 0.3); }
.disk-block.owner-pet {
background: rgba(16, 185, 129, 0.1);
border-color: rgba(16, 185, 129, 0.3);
}
.disk-block.owner-vacation {
background: rgba(59, 130, 246, 0.1);
border-color: rgba(59, 130, 246, 0.3);
}
.disk-block.owner-doc {
background: rgba(245, 158, 11, 0.1);
border-color: rgba(245, 158, 11, 0.3);
}
.disk-block.active {
transform: scale(1.1);
color: white;
font-weight: bold;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
z-index: 2;
}
.disk-block.owner-pet.active { background: var(--vp-c-success-1); border-color: var(--vp-c-success-1); }
.disk-block.owner-vacation.active { background: var(--vp-c-brand-1); border-color: var(--vp-c-brand-1); }
.disk-block.owner-doc.active { background: var(--vp-c-warning-1); border-color: var(--vp-c-warning-1); }
.disk-block.owner-pet.active {
background: var(--vp-c-success-1);
border-color: var(--vp-c-success-1);
}
.disk-block.owner-vacation.active {
background: var(--vp-c-brand-1);
border-color: var(--vp-c-brand-1);
}
.disk-block.owner-doc.active {
background: var(--vp-c-warning-1);
border-color: var(--vp-c-warning-1);
}
.explanation-box {
padding: 1rem;
@@ -308,7 +321,13 @@ const isBlockActive = (block) => {
}
@keyframes fadeIn {
from { opacity: 0; transform: translateX(-10px); }
to { opacity: 1; transform: translateX(0); }
from {
opacity: 0;
transform: translateX(-10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
</style>
@@ -20,7 +20,8 @@
<!-- MUX Demo -->
<div v-if="currentTab === 'mux'" class="demo-panel">
<div class="panel-desc">
<strong>多路选择器 (MUX)</strong>像铁路道岔一样根据"选择信号"决定让哪一路数据通过
<strong>多路选择器 (MUX)</strong
>像铁路道岔一样根据"选择信号"决定让哪一路数据通过
</div>
<div class="mux-container">
<div class="inputs">
@@ -80,7 +81,8 @@
<!-- Decoder Demo -->
<div v-if="currentTab === 'decoder'" class="demo-panel">
<div class="panel-desc">
<strong>译码器 (Decoder)</strong>将二进制输入转换为特定输出线的激活信号例如 2位输入可以激活
<strong>译码器 (Decoder)</strong
>将二进制输入转换为特定输出线的激活信号例如 2位输入可以激活
4根输出线中的一根
</div>
<div class="decoder-container">
@@ -69,7 +69,11 @@
:cx="node.x"
:cy="node.y"
r="20"
:fill="selectedNode === index ? 'var(--vp-c-brand)' : 'var(--vp-c-brand-soft)'"
:fill="
selectedNode === index
? 'var(--vp-c-brand)'
: 'var(--vp-c-brand-soft)'
"
stroke="var(--vp-c-brand)"
stroke-width="2"
/>
@@ -154,7 +158,7 @@ const edges = ref([
])
const averageDegree = computed(() => {
return (edges.value.length * 2 / nodes.length).toFixed(1)
return ((edges.value.length * 2) / nodes.length).toFixed(1)
})
</script>
@@ -174,8 +178,14 @@ const averageDegree = computed(() => {
margin-bottom: 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; }
.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;
@@ -8,7 +8,7 @@
<div class="core-idea">
<div class="idea-box">
<div class="idea-text">
贪心算法在每一步选择中都采取当前状态下<strong>最优</strong>的选择<br>
贪心算法在每一步选择中都采取当前状态下<strong>最优</strong>的选择<br />
希望通过一系列局部最优选择达到<strong>全局最优</strong>
</div>
</div>
@@ -36,7 +36,11 @@
需要找零<span class="amount">{{ changeAmount }}</span>
</div>
<div class="change-process">
<div class="process-step" v-for="(step, index) in changeSteps" :key="index">
<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>
@@ -46,7 +50,7 @@
</div>
</div>
<div class="scenario-note">
贪心策略每次选择面值最大的硬币<br>
贪心策略每次选择面值最大的硬币<br />
适用于人民币美元等货币系统
</div>
</div>
@@ -59,9 +63,14 @@
<div
v-for="(activity, index) in activities"
:key="index"
:class="['activity-item', { selected: activity.selected, conflicting: activity.conflicting }]"
:class="[
'activity-item',
{ selected: activity.selected, conflicting: activity.conflicting }
]"
>
<div class="activity-time">{{ activity.start }} - {{ activity.end }}</div>
<div class="activity-time">
{{ activity.start }} - {{ activity.end }}
</div>
<div class="activity-name">{{ activity.name }}</div>
</div>
</div>
@@ -183,17 +192,51 @@ const changeSteps = [
{ coin: '1元', count: 2, value: 2 }
]
const totalCoins = computed(() => changeSteps.reduce((sum, step) => sum + step.count, 0))
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 }
{
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)
const selectedCount = computed(
() => activities.filter((a) => a.selected).length
)
</script>
<style scoped>
@@ -212,8 +255,14 @@ const selectedCount = computed(() => activities.filter(a => a.selected).length)
margin-bottom: 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; }
.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;
@@ -0,0 +1,333 @@
<template>
<div class="half-adder-demo">
<div class="demo-label">
半加器 (Half Adder) 内部构造 尝试组合 A B观察 XOR异或门
AND与门的分工
</div>
<div class="circuit-container">
<!-- 输入端 -->
<div class="inputs">
<div class="input-line">
<button
class="toggle-btn"
:class="{ on: inputA }"
@click="inputA = !inputA"
>
{{ inputA ? '1' : '0' }}
</button>
<span class="label">输入 A</span>
</div>
<div class="input-line">
<button
class="toggle-btn"
:class="{ on: inputB }"
@click="inputB = !inputB"
>
{{ inputB ? '1' : '0' }}
</button>
<span class="label">输入 B</span>
</div>
</div>
<!-- 连线区域 -->
<div class="wires">
<!-- Path visualization can be complex, using simple SVG lines -->
<svg class="wire-svg" viewBox="0 0 100 150" preserveAspectRatio="none">
<!-- A to XOR -->
<path
d="M 0,30 C 50,30 50,40 100,40"
fill="none"
:stroke="inputA ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<!-- B to XOR -->
<path
d="M 0,120 C 50,120 50,60 100,60"
fill="none"
:stroke="inputB ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<!-- A to AND -->
<path
d="M 20,30 L 20,90 C 20,90 50,90 100,90"
fill="none"
:stroke="inputA ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<!-- B to AND -->
<path
d="M 40,120 L 40,110 C 40,110 50,110 100,110"
fill="none"
:stroke="inputB ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<!-- Nodes -->
<circle
cx="20"
cy="30"
r="3"
:fill="inputA ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
/>
<circle
cx="40"
cy="120"
r="3"
:fill="inputB ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
/>
</svg>
</div>
<!-- 逻辑门 -->
<div class="gates">
<div class="gate-box xor-gate" :class="{ active: sumOut }">
<div class="gate-name">XOR </div>
<div class="gate-desc">计算"本位" (相加结果)</div>
</div>
<div class="gate-box and-gate" :class="{ active: carryOut }">
<div class="gate-name">AND </div>
<div class="gate-desc">计算"进位" (满2进1)</div>
</div>
</div>
<!-- 线 -->
<div class="wires outputs-wires">
<svg class="wire-svg" viewBox="0 0 50 150" preserveAspectRatio="none">
<line
x1="0"
y1="50"
x2="50"
y2="50"
:stroke="
sumOut ? 'var(--vp-c-green-1, #16a34a)' : 'var(--vp-c-text-3)'
"
stroke-width="2"
/>
<line
x1="0"
y1="100"
x2="50"
y2="100"
:stroke="carryOut ? '#d97706' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
</svg>
</div>
<!-- 输出端 -->
<div class="outputs">
<div class="output-line" :class="{ active: sumOut }">
<span class="label">本位 (Sum)</span>
<span class="out-val s-val">{{ sumOut ? '1' : '0' }}</span>
</div>
<div class="output-line" :class="{ active: carryOut }">
<span class="label">向前进位 (Carry)</span>
<span class="out-val c-val">{{ carryOut ? '1' : '0' }}</span>
</div>
</div>
</div>
<div class="logic-explain">
<p>
你的输入是 {{ inputA ? '1' : '0' }} {{ inputB ? '1' : '0' }}<br />
<strong>XOR </strong>判断它们不仅要"相加"还看是否"不同"{{
inputA !== inputB ? '不同,出1' : '相同,出0'
}}
> 核心本位 <strong>{{ sumOut ? '1' : '0' }}</strong
><br />
<strong>AND </strong>暗中观察是否"全为真"{{
inputA && inputB ? '全为 1,产生进位!' : '没有全为 1,不进位'
}}
> 进位信号 <strong>{{ carryOut ? '1' : '0' }}</strong
>
</p>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const inputA = ref(false)
const inputB = ref(true)
const sumOut = computed(() => inputA.value !== inputB.value)
const carryOut = computed(() => inputA.value && inputB.value)
</script>
<style scoped>
.half-adder-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem 1.2rem;
margin: 1rem 0;
}
.demo-label {
font-size: 0.78rem;
font-weight: bold;
color: var(--vp-c-text-2);
margin-bottom: 1rem;
letter-spacing: 0.2px;
}
.circuit-container {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
padding: 1rem;
overflow-x: auto;
}
.inputs,
.outputs {
display: flex;
flex-direction: column;
gap: 3.5rem;
min-width: 6rem;
z-index: 2;
}
.outputs {
min-width: 8rem;
}
.input-line,
.output-line {
display: flex;
align-items: center;
gap: 0.5rem;
}
.label {
font-size: 0.8rem;
color: var(--vp-c-text-1);
}
.toggle-btn {
width: 2.2rem;
height: 2.2rem;
border-radius: 4px;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
font-weight: bold;
font-family: monospace;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
}
.toggle-btn.on {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand-1);
border-color: var(--vp-c-brand-1);
}
.out-val {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.2rem;
height: 2.2rem;
border-radius: 4px;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
font-weight: bold;
font-family: monospace;
font-size: 1rem;
transition: all 0.2s;
}
.s-val {
color: var(--vp-c-text-3);
}
.c-val {
color: var(--vp-c-text-3);
}
.output-line.active .s-val {
background: #dcfce7;
color: #16a34a;
border-color: #16a34a;
}
.output-line.active .c-val {
background: #fef3c7;
color: #d97706;
border-color: #d97706;
}
.wires {
width: 80px;
height: 150px;
position: relative;
}
.outputs-wires {
width: 40px;
}
.wire-svg {
width: 100%;
height: 100%;
}
.gates {
display: flex;
flex-direction: column;
gap: 1.5rem;
z-index: 2;
margin-top: 5px;
}
.gate-box {
width: 7.5rem;
height: 4rem;
background: var(--vp-c-bg-alt);
border: 2px solid var(--vp-c-divider);
border-radius: 4px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.2s;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.gate-box.active {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 8px var(--vp-c-brand-soft);
}
.gate-name {
font-weight: bold;
font-size: 0.9rem;
color: var(--vp-c-text-1);
}
.gate-desc {
font-size: 0.65rem;
color: var(--vp-c-text-3);
margin-top: 0.2rem;
}
.logic-explain {
margin-top: 1.5rem;
padding: 0.8rem;
background: var(--vp-c-bg);
border-radius: 6px;
font-size: 0.85rem;
text-align: center;
color: var(--vp-c-text-2);
line-height: 1.5;
}
@media (max-width: 600px) {
.circuit-container {
transform: scale(0.85);
transform-origin: left top;
padding-bottom: 0;
}
}
</style>
@@ -28,9 +28,7 @@
placeholder="值 (如: 苹果)"
class="hash-input"
/>
<button @click="addData" class="add-btn">
添加
</button>
<button @click="addData" class="add-btn">添加</button>
</div>
</div>
@@ -60,7 +58,10 @@
<div
v-for="(slot, index) in hashTable"
:key="index"
:class="['table-slot', { occupied: slot !== null, highlighted: index === exampleIndex }]"
:class="[
'table-slot',
{ occupied: slot !== null, highlighted: index === exampleIndex }
]"
>
<div class="slot-index">{{ index }}</div>
<div class="slot-value">{{ slot || '空' }}</div>
@@ -121,7 +122,18 @@ const newKey = ref('')
const newValue = ref('')
const exampleKey = ref('apple')
const hashTable = ref([null, null, null, null, null, null, null, null, null, null])
const hashTable = ref([
null,
null,
null,
null,
null,
null,
null,
null,
null,
null
])
// 初始化一些数据
const initData = () => {
@@ -130,7 +142,7 @@ const initData = () => {
{ key: 'banana', value: '香蕉' },
{ key: 'orange', value: '橙子' }
]
data.forEach(item => {
data.forEach((item) => {
const index = simpleHash(item.key)
hashTable.value[index] = `${item.key}: ${item.value}`
})
@@ -174,8 +186,14 @@ initData()
margin-bottom: 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; }
.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;
@@ -55,13 +55,17 @@
<div class="pros">
<div class="list-title"> 优点</div>
<ul>
<li v-for="(pro, index) in currentEra.pros" :key="index">{{ pro }}</li>
<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>
<li v-for="(con, index) in currentEra.cons" :key="index">
{{ con }}
</li>
</ul>
</div>
</div>
@@ -99,11 +103,7 @@
<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 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">
@@ -134,11 +134,7 @@ const eras = [
icon: '0️⃣',
position: '5%',
example: '10110000 11000000\n(add two numbers)',
features: [
'直接用二进制代码',
'机器可以直接执行',
'完全依赖硬件'
],
features: ['直接用二进制代码', '机器可以直接执行', '完全依赖硬件'],
pros: ['执行速度最快', '直接控制硬件'],
cons: ['极难编写', '容易出错', '不可移植']
},
@@ -149,11 +145,7 @@ const eras = [
icon: '🔧',
position: '25%',
example: 'MOV AX, 5\nADD AX, 3\n(add 5 and 3)',
features: [
'用助记符代替二进制',
'需要汇编器翻译',
'仍然依赖硬件'
],
features: ['用助记符代替二进制', '需要汇编器翻译', '仍然依赖硬件'],
pros: ['比机器语言好懂', '效率仍然很高'],
cons: ['代码冗长', '不可移植', '需要了解硬件']
},
@@ -164,11 +156,7 @@ const eras = [
icon: '📋',
position: '50%',
example: 'int add(int a, int b) {\n return a + b;\n}',
features: [
'函数、变量等抽象',
'结构化编程',
'可移植性好'
],
features: ['函数、变量等抽象', '结构化编程', '可移植性好'],
pros: ['易读易写', '可移植', '效率较高'],
cons: ['大型项目难以维护', '代码重用性差']
},
@@ -179,11 +167,7 @@ const eras = [
icon: '🎯',
position: '75%',
example: 'class Calculator {\n add(a, b) { return a + b; }\n}',
features: [
'类、对象、封装、继承',
'模块化设计',
'代码复用性强'
],
features: ['类、对象、封装、继承', '模块化设计', '代码复用性强'],
pros: ['适合大型项目', '易维护', '可扩展'],
cons: ['学习曲线陡', '代码量较大']
},
@@ -194,11 +178,7 @@ const eras = [
icon: '🚀',
position: '95%',
example: 'const add = (a, b) => a + b;\n(add arrow function)',
features: [
'简洁优雅的语法',
'多范式支持',
'强大的标准库'
],
features: ['简洁优雅的语法', '多范式支持', '强大的标准库'],
pros: ['开发效率高', '生态丰富', '社区活跃'],
cons: ['抽象层多', '性能可能不如底层语言']
}
@@ -232,8 +212,14 @@ const currentEra = computed(() => eras[activeEra.value])
margin-bottom: 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; }
.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);
@@ -321,7 +307,8 @@ const currentEra = computed(() => eras[activeEra.value])
gap: 1.5rem;
}
.content-section {}
.content-section {
}
.section-title {
font-weight: 600;
@@ -120,9 +120,7 @@
<div class="evo-name">现代语言</div>
<div class="evo-arrow"></div>
</div>
<div class="evo-result">
越来越接近<br>人类思维
</div>
<div class="evo-result">越来越接近<br />人类思维</div>
</div>
</div>
</div>
@@ -139,7 +137,8 @@ const scenarios = [
icon: '🌐',
title: '开发网站',
desc: '创建交互式网页',
fullDesc: '你需要创建一个在线购物网站,用户可以浏览商品、加入购物车、下单支付',
fullDesc:
'你需要创建一个在线购物网站,用户可以浏览商品、加入购物车、下单支付',
reasons: [
'HTML 定义网页结构',
'CSS 实现美观样式',
@@ -211,7 +210,9 @@ const scenarios = [
}
]
const currentScenario = computed(() => scenarios.find(s => s.id === activeScenario.value))
const currentScenario = computed(() =>
scenarios.find((s) => s.id === activeScenario.value)
)
</script>
<style scoped>
@@ -230,8 +231,14 @@ const currentScenario = computed(() => scenarios.find(s => s.id === activeScenar
margin-bottom: 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; }
.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;
@@ -319,7 +326,8 @@ const currentScenario = computed(() => scenarios.find(s => s.id === activeScenar
gap: 1.5rem;
}
.detail-section {}
.detail-section {
}
.section-title {
font-weight: 600;
@@ -6,18 +6,10 @@
</div>
<div class="dimension-grid">
<div
v-for="dim in dimensions"
:key="dim.id"
class="dimension-card"
>
<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 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>
@@ -111,8 +103,14 @@ const dimensions = [
margin-bottom: 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; }
.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;
@@ -76,12 +76,8 @@
<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>
<button class="op-btn" @click="pushStack">入栈 (PUSH)</button>
<button class="op-btn" @click="popStack">出栈 (POP)</button>
</div>
<div class="visual-note">
后进先出 (LIFO) | 应用撤销操作函数调用
@@ -104,12 +100,8 @@
<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>
<button class="op-btn" @click="enqueue">入队 (ENQUEUE)</button>
<button class="op-btn" @click="dequeue">出队 (DEQUEUE)</button>
</div>
<div class="visual-note">
先进先出 (FIFO) | 应用任务队列打印队列
@@ -239,7 +231,9 @@ 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 currentStructure = computed(() =>
structures.find((s) => s.id === activeStructure.value)
)
const pushStack = () => {
const newItem = `${stackData.value.length + 1}`
@@ -280,8 +274,14 @@ const dequeue = () => {
margin-bottom: 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; }
.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;
@@ -18,7 +18,12 @@
<tr v-for="(row, i) in gate.rows" :key="i">
<td>{{ row[0] }}</td>
<td v-if="gate.name !== 'NOT'">{{ row[1] }}</td>
<td class="result-cell" :class="{ one: row[row.length - 1] === 1 }">{{ row[row.length - 1] }}</td>
<td
class="result-cell"
:class="{ one: row[row.length - 1] === 1 }"
>
{{ row[row.length - 1] }}
</td>
</tr>
</tbody>
</table>
@@ -34,22 +39,40 @@ const gates = [
{
name: 'AND',
rule: '都为 1 才得 1',
rows: [[0,0,0],[0,1,0],[1,0,0],[1,1,1]]
rows: [
[0, 0, 0],
[0, 1, 0],
[1, 0, 0],
[1, 1, 1]
]
},
{
name: 'OR',
rule: '有一个 1 就得 1',
rows: [[0,0,0],[0,1,1],[1,0,1],[1,1,1]]
rows: [
[0, 0, 0],
[0, 1, 1],
[1, 0, 1],
[1, 1, 1]
]
},
{
name: 'NOT',
rule: '取反',
rows: [[0,1],[1,0]]
rows: [
[0, 1],
[1, 0]
]
},
{
name: 'XOR',
rule: '不同才得 1',
rows: [[0,0,0],[0,1,1],[1,0,1],[1,1,0]]
rows: [
[0, 0, 0],
[0, 1, 1],
[1, 0, 1],
[1, 1, 0]
]
}
]
</script>
@@ -1,33 +1,51 @@
<template>
<div class="memory-demo">
<div class="demo-controls">
<button class="allocate-btn wechat" @click="allocate('wechat')" :disabled="!hasFreeSpace">
<button
class="allocate-btn wechat"
@click="allocate('wechat')"
:disabled="!hasFreeSpace"
>
+ 给微信分配数据
</button>
<button class="allocate-btn game" @click="allocate('game')" :disabled="!hasFreeSpace">
<button
class="allocate-btn game"
@click="allocate('game')"
:disabled="!hasFreeSpace"
>
+ 给游戏分配数据
</button>
<button class="reset-btn" @click="reset">
重置
</button>
<button class="reset-btn" @click="reset"> 重置</button>
</div>
<div class="system-view">
<!-- 虚拟内存试图 -->
<div class="virtual-cluster">
<div class="process-vm wechat">
<div class="title">💬 微信的虚拟内存<br/>(它认为自己独占了空间)</div>
<div class="title">💬 微信的虚拟内存<br />(它认为自己独占了空间)</div>
<div class="vm-blocks">
<div v-for="i in 4" :key="'w'+i" class="block" :class="{ filled: wechatBlocks >= i }">
<div
v-for="i in 4"
:key="'w' + i"
class="block"
:class="{ filled: wechatBlocks >= i }"
>
{{ wechatBlocks >= i ? '数据 ' + i : '虚拟空闲' }}
</div>
</div>
</div>
<div class="process-vm game">
<div class="title">🎮 游戏的虚拟内存<br/>(它也认为自己独占了空间)</div>
<div class="title">
🎮 游戏的虚拟内存<br />(它也认为自己独占了空间)
</div>
<div class="vm-blocks">
<div v-for="i in 4" :key="'g'+i" class="block" :class="{ filled: gameBlocks >= i }">
<div
v-for="i in 4"
:key="'g' + i"
class="block"
:class="{ filled: gameBlocks >= i }"
>
{{ gameBlocks >= i ? '数据 ' + i : '虚拟空闲' }}
</div>
</div>
@@ -38,17 +56,17 @@
<div class="os-page-table">
<div class="title">保安大叔 (OS 页表)</div>
<div class="table-info">
当程序存数据时<br/>由我暗中转移到真正的物理缝隙里
当程序存数据时<br />由我暗中转移到真正的物理缝隙里
</div>
</div>
<!-- 物理内存 -->
<div class="physical-memory">
<div class="title">🗄 真实的物理内存条<br/>(其实像个大杂烩一样乱)</div>
<div class="title">🗄 真实的物理内存条<br />(其实像个大杂烩一样乱)</div>
<div class="pm-blocks">
<div
v-for="(block, idx) in physicalBlocks"
:key="'p'+idx"
<div
v-for="(block, idx) in physicalBlocks"
:key="'p' + idx"
class="block"
:class="[block.type, { occupied: block.type !== 'empty' }]"
>
@@ -57,9 +75,10 @@
</div>
</div>
</div>
<div class="explanation-box" v-if="wechatBlocks > 0 || gameBlocks > 0">
💡 发现了没尽管右侧真正的物理内存已经被塞得像个狗皮膏药但在左侧的微信和游戏眼里自己的内存条永远是连续且干净的更重要的是微信绝对访问不到橘色的物理块保证了安全
💡
发现了没尽管右侧真正的物理内存已经被塞得像个狗皮膏药但在左侧的微信和游戏眼里自己的内存条永远是连续且干净的更重要的是微信绝对访问不到橘色的物理块保证了安全
</div>
</div>
</template>
@@ -80,20 +99,20 @@ const initialPhysicalBlocks = [
{ type: 'empty', label: '空闲' },
{ type: 'empty', label: '空闲' },
{ type: 'os', label: '系统驱动' },
{ type: 'empty', label: '空闲' },
{ type: 'empty', label: '空闲' }
]
const physicalBlocks = ref(JSON.parse(JSON.stringify(initialPhysicalBlocks)))
const freeSpaceCount = computed(() => {
return physicalBlocks.value.filter(b => b.type === 'empty').length
return physicalBlocks.value.filter((b) => b.type === 'empty').length
})
const hasFreeSpace = computed(() => freeSpaceCount.value > 0)
const allocate = (process) => {
if (!hasFreeSpace.value) return
// Find a process block logic
if (process === 'wechat' && wechatBlocks.value < 4) {
wechatBlocks.value++
@@ -109,9 +128,10 @@ const fillRandomEmptyBlock = (type, label) => {
physicalBlocks.value.forEach((b, i) => {
if (b.type === 'empty') emptyIndices.push(i)
})
if (emptyIndices.length > 0) {
const randomIndex = emptyIndices[Math.floor(Math.random() * emptyIndices.length)]
const randomIndex =
emptyIndices[Math.floor(Math.random() * emptyIndices.length)]
physicalBlocks.value[randomIndex] = { type, label }
}
}
@@ -263,7 +283,7 @@ const reset = () => {
padding: 1rem;
position: relative;
border: 2px solid var(--vp-c-brand-1);
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.os-page-table .table-info {
@@ -317,9 +337,17 @@ const reset = () => {
}
@keyframes popIn {
0% { transform: scale(0.9); opacity: 0; }
50% { transform: scale(1.05); }
100% { transform: scale(1); opacity: 1; }
0% {
transform: scale(0.9);
opacity: 0;
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
opacity: 1;
}
}
.explanation-box {
@@ -333,7 +361,13 @@ const reset = () => {
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
@@ -7,8 +7,8 @@
<div class="demo-content">
<div class="layers-container">
<div
v-for="(layer, i) in layers"
<div
v-for="(layer, i) in layers"
:key="i"
:class="['layer', { active: activeLayer === i }]"
@click="activeLayer = i"
@@ -24,19 +24,13 @@
{{ layer.protocols }}
</div>
</div>
<div
v-if="layer.device"
class="layer-device"
>
<div v-if="layer.device" class="layer-device">
{{ layer.device }}
</div>
</div>
</div>
<div
v-if="currentLayer"
class="layer-detail"
>
<div v-if="currentLayer" class="layer-detail">
<div class="detail-header">
<span class="detail-name">{{ currentLayer.name }}</span>
<span class="detail-analogy">{{ currentLayer.analogy }}</span>
@@ -45,14 +39,9 @@
{{ currentLayer.desc }}
</div>
<div class="detail-tasks">
<div class="task-title">
核心任务
</div>
<div class="task-title">核心任务</div>
<ul>
<li
v-for="(task, j) in currentLayer.tasks"
:key="j"
>
<li v-for="(task, j) in currentLayer.tasks" :key="j">
{{ task }}
</li>
</ul>
@@ -64,35 +53,25 @@
</div>
<div class="encapsulation-demo">
<div class="encap-title">
数据封装过程
</div>
<div class="encap-title">数据封装过程</div>
<div class="encap-flow">
<div
v-for="(step, i) in encapsulation"
:key="i"
class="encap-step"
>
<div v-for="(step, i) in encapsulation" :key="i" class="encap-step">
<div class="step-layer">
{{ step.layer }}
</div>
<div class="step-data">
<span
v-if="step.header"
class="header"
>{{ step.header }}</span>
<span v-if="step.header" class="header">{{ step.header }}</span>
<span class="payload">{{ step.payload }}</span>
</div>
</div>
<div class="arrow">
发送
</div>
<div class="arrow"> 发送</div>
</div>
</div>
</div>
<div class="info-box">
<strong>核心思想</strong>分层设计让网络协议模块化每层只关心自己的职责数据从应用层向下传递时每层都会添加自己的"信封"(头部)接收时再逐层拆开
<strong>核心思想</strong
>分层设计让网络协议模块化每层只关心自己的职责数据从应用层向下传递时每层都会添加自己的"信封"(头部)接收时再逐层拆开
</div>
</div>
</template>
@@ -118,7 +97,12 @@ const layers = [
device: '',
analogy: '包裹分拣组',
desc: '负责端到端的数据传输,确保数据的可靠性或实时性。',
tasks: ['建立和管理端到端连接', '分段和重组数据', '流量控制和拥塞控制', '端口寻址'],
tasks: [
'建立和管理端到端连接',
'分段和重组数据',
'流量控制和拥塞控制',
'端口寻址'
],
unit: '段(Segment)'
},
{
@@ -177,8 +161,15 @@ const encapsulation = [
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.demo-content {
display: grid;
@@ -201,8 +201,14 @@ const protocolLayers = [
margin-bottom: 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; }
.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;
@@ -253,8 +259,14 @@ const protocolLayers = [
border-radius: 6px;
}
.app-icon { font-size: 1.5rem; }
.app-name { font-size: 0.8rem; font-weight: 600; color: var(--vp-c-brand); }
.app-icon {
font-size: 1.5rem;
}
.app-name {
font-size: 0.8rem;
font-weight: 600;
color: var(--vp-c-brand);
}
.network-path {
flex: 1;
@@ -316,8 +328,15 @@ const protocolLayers = [
}
@keyframes flowMove {
0%, 100% { transform: translateX(-20px); opacity: 0; }
50% { transform: translateX(20px); opacity: 1; }
0%,
100% {
transform: translateX(-20px);
opacity: 0;
}
50% {
transform: translateX(20px);
opacity: 1;
}
}
.flow-packet {
@@ -106,8 +106,14 @@ const principles = [
margin-bottom: 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; }
.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;
@@ -8,9 +8,7 @@
<div class="demo-content">
<div class="os-layers">
<div class="layer user-apps">
<div class="layer-title">
应用程序层
</div>
<div class="layer-title">应用程序层</div>
<div class="layer-content">
<div
v-for="app in applications"
@@ -29,9 +27,7 @@
</div>
<div class="layer kernel">
<div class="layer-title">
操作系统内核
</div>
<div class="layer-title">操作系统内核</div>
<div class="layer-content">
<div class="kernel-components">
<div
@@ -45,15 +41,11 @@
</div>
</div>
</div>
<div class="layer-desc">
进程管理内存管理文件系统设备管理
</div>
<div class="layer-desc">进程管理内存管理文件系统设备管理</div>
</div>
<div class="layer hardware">
<div class="layer-title">
硬件层
</div>
<div class="layer-title">硬件层</div>
<div class="layer-content">
<div class="hardware-icons">
<span>💻 CPU</span>
@@ -70,27 +62,18 @@
<div class="flow-content">
<div class="flow-item" :class="{ active: showFlow }">
<div class="flow-arrow"></div>
<div class="flow-desc">
应用程序请求资源内存CPU文件
</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 class="flow-desc">操作系统内核统一分配和调度</div>
</div>
<div class="flow-item" :class="{ active: showFlow }">
<div class="flow-arrow"></div>
<div class="flow-desc">
硬件执行实际操作
</div>
<div class="flow-desc">硬件执行实际操作</div>
</div>
</div>
<button
class="flow-btn"
@click="showFlow = !showFlow"
>
<button class="flow-btn" @click="showFlow = !showFlow">
{{ showFlow ? '隐藏' : '显示' }}资源流
</button>
</div>
@@ -132,13 +115,13 @@ const kernelComponents = [
]
const activeAppName = computed(() => {
const app = applications.find(a => a.id === activeApp.value)
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)
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} 的功能`
@@ -161,8 +144,14 @@ const getActiveAppDesc = () => {
margin-bottom: 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; }
.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;
@@ -213,7 +202,8 @@ const getActiveAppDesc = () => {
transition: all 0.3s;
}
.app-icon:hover, .app-icon.active {
.app-icon:hover,
.app-icon.active {
transform: scale(1.1);
background: rgba(255, 255, 255, 0.2);
}
@@ -227,7 +217,8 @@ const getActiveAppDesc = () => {
transition: all 0.3s;
}
.kernel-component:hover, .kernel-component.active {
.kernel-component:hover,
.kernel-component.active {
background: rgba(255, 255, 255, 0.3);
font-weight: 600;
}
@@ -30,32 +30,55 @@
<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" />
<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="
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>
<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="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>
<text x="420" y="110" fill="var(--vp-c-text-2)" font-size="12">
</text>
</g>
</svg>
</div>
@@ -114,7 +137,11 @@
<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">
<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>
@@ -138,7 +165,8 @@ 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',
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: '较差(易受电磁干扰)',
@@ -152,7 +180,8 @@ const mediaData = {
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',
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: '极强(不受电磁干扰)',
@@ -198,8 +227,14 @@ const currentMedia = computed(() => mediaData[activeMedia.value])
margin-bottom: 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; }
.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;
@@ -283,8 +318,12 @@ const currentMedia = computed(() => mediaData[activeMedia.value])
}
@keyframes drawSignal {
0% { stroke-dashoffset: 1000; }
100% { stroke-dashoffset: 0; }
0% {
stroke-dashoffset: 1000;
}
100% {
stroke-dashoffset: 0;
}
}
.signal-legend {
@@ -1,13 +1,21 @@
<template>
<div class="process-demo">
<div class="controls-section">
<button class="action-btn" :class="{ active: isRunning }" @click="toggleSimulation">
<button
class="action-btn"
:class="{ active: isRunning }"
@click="toggleSimulation"
>
{{ isRunning ? '⏸ 暂停时间片轮转' : '▶️ 启动 CPU' }}
</button>
<div class="speed-control">
<label>时间流速:</label>
<button :class="{ active: speed === 'slow' }" @click="setSpeed('slow')">极慢动作</button>
<button :class="{ active: speed === 'fast' }" @click="setSpeed('fast')">真实速度</button>
<button :class="{ active: speed === 'slow' }" @click="setSpeed('slow')">
极慢动作
</button>
<button :class="{ active: speed === 'fast' }" @click="setSpeed('fast')">
真实速度
</button>
</div>
</div>
@@ -18,23 +26,21 @@
<span v-if="activeProcess" class="task-badge">
正在处理: {{ activeProcess.icon }} {{ activeProcess.name }}
</span>
<span v-else class="task-badge idle">
空闲中...
</span>
<span v-else class="task-badge idle"> 空闲中... </span>
</div>
</div>
<!-- 连接线动画 -->
<div class="connector">
<div
class="data-flow"
:class="[ `flow-${activeProcessId}`, { running: isRunning }]">
</div>
<div
class="data-flow"
:class="[`flow-${activeProcessId}`, { running: isRunning }]"
></div>
</div>
</div>
<div class="processes-grid">
<div
v-for="p in processes"
<div
v-for="p in processes"
:key="p.id"
class="process-card"
:class="{ active: p.id === activeProcessId }"
@@ -44,21 +50,32 @@
<span class="icon">{{ p.icon }}</span>
<span class="name">{{ p.name }}</span>
</div>
<span class="status-badge" :class="p.id === activeProcessId ? 'running' : 'waiting'">
<span
class="status-badge"
:class="p.id === activeProcessId ? 'running' : 'waiting'"
>
{{ p.id === activeProcessId ? '独占 CPU' : '排队等待' }}
</span>
</div>
<div class="p-progress">
<div class="progress-track">
<div class="progress-fill" :style="{ width: p.progress + '%' }"></div>
<div
class="progress-fill"
:style="{ width: p.progress + '%' }"
></div>
</div>
<div class="progress-text">{{ Math.floor(p.progress) }}% 完成</div>
</div>
</div>
</div>
<div class="explanation-box" :class="{ show: isRunning && speed === 'fast' }">
💡 **关键启示**当切换速度足够快时肉眼已经无法分辨谁在等待这也就是为什么只有一个 CPU 核心的电脑依然能让你一边听歌一边打字
<div
class="explanation-box"
:class="{ show: isRunning && speed === 'fast' }"
>
💡
**关键启示**当切换速度足够快时肉眼已经无法分辨谁在等待这也就是为什么只有一个
CPU 核心的电脑依然能让你一边听歌一边打字
</div>
</div>
</template>
@@ -77,7 +94,9 @@ const processes = ref([
{ id: 3, name: '游戏渲染', icon: '🎮', progress: 0 }
])
const activeProcess = computed(() => processes.value.find(p => p.id === activeProcessId.value))
const activeProcess = computed(() =>
processes.value.find((p) => p.id === activeProcessId.value)
)
const setSpeed = (s) => {
speed.value = s
@@ -88,17 +107,17 @@ const setSpeed = (s) => {
}
const startLoop = () => {
const switchTime = speed.value === 'slow' ? 1200 : 80; // 1.2s
const switchTime = speed.value === 'slow' ? 1200 : 80 // 1.2s
if (!activeProcessId.value) {
activeProcessId.value = 1
}
interval = setInterval(() => {
//
const curr = processes.value.find(p => p.id === activeProcessId.value)
const curr = processes.value.find((p) => p.id === activeProcessId.value)
if (curr) {
curr.progress += (speed.value === 'slow' ? 15 : 4)
curr.progress += speed.value === 'slow' ? 15 : 4
if (curr.progress >= 100) curr.progress = 0
}
@@ -106,7 +125,6 @@ const startLoop = () => {
let nextId = activeProcessId.value + 1
if (nextId > 3) nextId = 1
activeProcessId.value = nextId
}, switchTime)
}
@@ -203,7 +221,7 @@ onUnmounted(() => {
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
transition: all 0.3s;
position: relative;
}
@@ -276,7 +294,9 @@ onUnmounted(() => {
.process-card.active::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--vp-c-brand-1);
}
@@ -7,9 +7,7 @@
<div class="demo-content">
<div class="collab-scene">
<div class="scene-title">
场景选择
</div>
<div class="scene-title">场景选择</div>
<div class="scene-buttons">
<button
v-for="scene in scenes"
@@ -88,7 +86,9 @@
>
<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>
<span v-if="file.size" class="file-size">{{
file.size
}}</span>
</div>
</div>
</div>
@@ -207,19 +207,21 @@ const sceneData = {
}
}
const currentSceneData = computed(() => sceneData[activeScene.value] || sceneData.launch)
const currentSceneData = computed(
() => sceneData[activeScene.value] || sceneData.launch
)
const getProcessName = (id) => {
const proc = processes.value.find(p => p.id === id)
const proc = processes.value.find((p) => p.id === id)
return proc?.name || '系统'
}
const getIcon = (type) => {
const icons = {
'json': '📋',
'db': '🗄️',
'folder': '📁',
'audio': '🎵'
json: '📋',
db: '🗄️',
folder: '📁',
audio: '🎵'
}
return icons[type] || '📄'
}
@@ -241,8 +243,14 @@ const getIcon = (type) => {
margin-bottom: 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; }
.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;
@@ -300,8 +308,12 @@ const getIcon = (type) => {
font-size: 0.9rem;
}
.zone-icon { font-size: 1.2rem; }
.zone-name { font-size: 0.85rem; }
.zone-icon {
font-size: 1.2rem;
}
.zone-name {
font-size: 0.85rem;
}
.process-list {
display: flex;
@@ -324,7 +336,9 @@ const getIcon = (type) => {
background: var(--vp-c-brand-soft);
}
.proc-name, .proc-pid, .proc-state {
.proc-name,
.proc-pid,
.proc-state {
flex: 1;
}
@@ -389,8 +403,13 @@ const getIcon = (type) => {
background: var(--vp-c-brand-soft);
}
.file-name { flex: 1; }
.file-size { color: var(--vp-c-text-2); font-size: 0.7rem; }
.file-name {
flex: 1;
}
.file-size {
color: var(--vp-c-text-2);
font-size: 0.7rem;
}
.explanation {
background: var(--vp-c-bg);
@@ -65,13 +65,17 @@
<div class="pros">
<div class="list-title"> 优点</div>
<ul>
<li v-for="(pro, index) in currentLang.pros" :key="index">{{ pro }}</li>
<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>
<li v-for="(con, index) in currentLang.cons" :key="index">
{{ con }}
</li>
</ul>
</div>
</div>
@@ -92,7 +96,11 @@
</tr>
</thead>
<tbody>
<tr v-for="(lang, index) in languages" :key="index" :class="{ highlighted: lang.name === activeLang }">
<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>
@@ -197,7 +205,9 @@ const languages = [
}
]
const currentLang = computed(() => languages.find(l => l.name === activeLang.value))
const currentLang = computed(() =>
languages.find((l) => l.name === activeLang.value)
)
</script>
<style scoped>
@@ -216,8 +226,14 @@ const currentLang = computed(() => languages.find(l => l.name === activeLang.val
margin-bottom: 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; }
.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;
@@ -147,7 +147,8 @@ const paradigms = [
icon: '📋',
desc: '告诉计算机怎么做',
idea: '通过一系列命令(语句)来改变程序状态,关注"怎么做"',
example: '// 计算1-10的和\nlet sum = 0;\nfor (let i = 1; i <= 10; i++) {\n sum += i;\n}',
example:
'// 计算1-10的和\nlet sum = 0;\nfor (let i = 1; i <= 10; i++) {\n sum += i;\n}',
features: ['变量', '循环', '条件判断', '语句'],
languages: ['C', 'Python', 'JavaScript']
},
@@ -157,7 +158,8 @@ const paradigms = [
icon: '🎯',
desc: '用对象来组织代码',
idea: '将数据和操作数据的方法封装成对象,通过对象间交互来完成任务',
example: 'class Calculator {\n add(a, b) { return a + b; }\n}\nconst calc = new Calculator();',
example:
'class Calculator {\n add(a, b) { return a + b; }\n}\nconst calc = new Calculator();',
features: ['封装', '继承', '多态', '类'],
languages: ['Java', 'C++', 'Python', 'Ruby']
},
@@ -167,13 +169,16 @@ const paradigms = [
icon: 'λ',
desc: '函数是核心',
idea: '强调纯函数、不可变数据,避免副作用,关注"做什么"',
example: '// 计算1-10的和\nconst sum = Array.from(\n {length: 10}, (_, i) => i + 1\n).reduce((a, b) => a + b, 0);',
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))
const currentParadigm = computed(() =>
paradigms.find((p) => p.id === activeParadigm.value)
)
</script>
<style scoped>
@@ -192,8 +197,14 @@ const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadi
margin-bottom: 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; }
.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;
@@ -281,7 +292,8 @@ const currentParadigm = computed(() => paradigms.find(p => p.id === activeParadi
gap: 1.5rem;
}
.detail-section {}
.detail-section {
}
.section-title {
font-weight: 600;
@@ -11,8 +11,8 @@
<div class="analogy-content">
<div class="analogy-title">俄罗斯套娃</div>
<div class="analogy-desc">
打开一个大娃娃里面有个小一点的娃娃<br>
再打开还有更小的...直到最小的一个<br>
打开一个大娃娃里面有个小一点的娃娃<br />
再打开还有更小的...直到最小的一个<br />
<strong>这就是递归</strong>
</div>
</div>
@@ -101,7 +101,8 @@
</div>
<div class="dir-pseudocode">
<div class="pseudo-title">伪代码</div>
<pre>function traverse(folder) {
<pre>
function traverse(folder) {
for each item in folder {
if item is file {
print(item)
@@ -109,7 +110,8 @@
traverse(item) //
}
}
}</pre>
}</pre
>
</div>
</div>
</div>
@@ -127,7 +129,9 @@
<div class="element-card">
<div class="element-number">2</div>
<div class="element-title">递归调用</div>
<div class="element-desc">如何让问题规模变小调用自己处理更小的规模</div>
<div class="element-desc">
如何让问题规模变小调用自己处理更小的规模
</div>
<div class="element-example">n! 转换成 (n-1)!</div>
</div>
<div class="element-card">
@@ -189,8 +193,14 @@ const examples = [
margin-bottom: 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; }
.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;
@@ -10,29 +10,45 @@
class="toggle-btn"
:class="{ on: inputData === 1 }"
@click="inputData = inputData === 1 ? 0 : 1"
>{{ inputData }}</button>
>
{{ inputData }}
</button>
</div>
<!-- Write -->
<button class="write-btn" :class="{ flash: isWriting }" @click="writeOnce">
<button
class="write-btn"
:class="{ flash: isWriting }"
@click="writeOnce"
>
写入
</button>
<!-- Stored -->
<div class="reg-block">
<span class="reg-title">存储</span>
<span class="val-box" :class="{ on: storedData === 1, flash: isWriting }">{{ storedData }}</span>
<span
class="val-box"
:class="{ on: storedData === 1, flash: isWriting }"
>{{ storedData }}</span
>
</div>
<!-- Output -->
<div class="reg-block">
<span class="reg-title">输出</span>
<span class="val-box out" :class="{ on: storedData === 1 }">{{ storedData }}</span>
<span class="val-box out" :class="{ on: storedData === 1 }">{{
storedData
}}</span>
</div>
</div>
<div class="status-line">
{{ inputData !== storedData ? '⚡ 输入≠存储 → 点"写入"即可更新' : '✓ 输入与存储一致' }}
{{
inputData !== storedData
? '⚡ 输入≠存储 → 点"写入"即可更新'
: '✓ 输入与存储一致'
}}
</div>
</div>
</template>
@@ -47,7 +63,9 @@ const isWriting = ref(false)
const writeOnce = () => {
isWriting.value = true
storedData.value = inputData.value
setTimeout(() => { isWriting.value = false }, 400)
setTimeout(() => {
isWriting.value = false
}, 400)
}
</script>
@@ -4,7 +4,8 @@
<div class="layers">
<div
v-for="(layer, i) in layers" :key="i"
v-for="(layer, i) in layers"
:key="i"
class="layer-row"
:class="{ active: activeLayer === i }"
@mouseenter="activeLayer = i"
@@ -23,7 +24,9 @@
</div>
</div>
<div class="demo-caption">层层抽象封装最底层的物理材料最终变成通用计算平台</div>
<div class="demo-caption">
层层抽象封装最底层的物理材料最终变成通用计算平台
</div>
</div>
</template>
@@ -33,13 +36,55 @@ import { ref } from 'vue'
const activeLayer = ref(null)
const layers = [
{ icon: '🏖️', name: '沙子(硅)', desc: '地球上最丰富的元素之一,提炼出高纯度硅', scale: '原材料', arrow: '提纯 → 切割' },
{ icon: '💿', name: '硅晶圆', desc: '直径约 30cm 的单晶硅片,表面极其光滑', scale: '基底', arrow: '光刻 → 蚀刻 → 掺杂' },
{ icon: '🔌', name: '晶体管(开关)', desc: 'Gate=1 导通,Gate=0 断开,用电压控制电流', scale: '数百亿 / 芯片', arrow: '组合成逻辑电路' },
{ icon: '🔲', name: '逻辑门', desc: 'AND / OR / NOT / XOR,实现基本布尔运算', scale: '数十亿', arrow: '组合成功能模块' },
{ icon: '⚙️', name: '功能单元', desc: '加法器、寄存器、多路选择器……各司其职', scale: '数百个', arrow: '集成为处理器' },
{ icon: '🧠', name: 'CPU 核心', desc: 'ALU + 控制器 + 寄存器组,取指→解码→执行→写回', scale: '1128 核', arrow: '软件编程' },
{ icon: '🚀', name: '软件应用', desc: '操作系统 / AI / 游戏 / 网页……一切皆指令', scale: '无限可能', arrow: '' },
{
icon: '🏖️',
name: '沙子(硅)',
desc: '地球上最丰富的元素之一,提炼出高纯度硅',
scale: '原材料',
arrow: '提纯 → 切割'
},
{
icon: '💿',
name: '硅晶圆',
desc: '直径约 30cm 的单晶硅片,表面极其光滑',
scale: '基底',
arrow: '光刻 → 蚀刻 → 掺杂'
},
{
icon: '🔌',
name: '晶体管(开关)',
desc: 'Gate=1 导通,Gate=0 断开,用电压控制电流',
scale: '数百亿 / 芯片',
arrow: '组合成逻辑电路'
},
{
icon: '🔲',
name: '逻辑门',
desc: 'AND / OR / NOT / XOR,实现基本布尔运算',
scale: '数十亿',
arrow: '组合成功能模块'
},
{
icon: '⚙️',
name: '功能单元',
desc: '加法器、寄存器、多路选择器……各司其职',
scale: '数百个',
arrow: '集成为处理器'
},
{
icon: '🧠',
name: 'CPU 核心',
desc: 'ALU + 控制器 + 寄存器组,取指→解码→执行→写回',
scale: '1128 核',
arrow: '软件编程'
},
{
icon: '🚀',
name: '软件应用',
desc: '操作系统 / AI / 游戏 / 网页……一切皆指令',
scale: '无限可能',
arrow: ''
}
]
</script>
@@ -28,17 +28,29 @@
<div
v-for="(num, index) in numbers"
:key="index"
:class="['array-cell', { found: index === foundIndex, searching: index <= searchStep && searching }]"
: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="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" />
目标数字<input
v-model="targetNumber"
type="number"
class="target-input"
/>
</div>
</div>
<div class="algo-stats">
@@ -55,19 +67,26 @@
<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
}]"
: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-step">
查找范围[{{ binaryLeft }}, {{ binaryRight }}]
</div>
<div class="info-mid">中间位置{{ binaryMid }}</div>
<div class="info-comparison">{{ sortedNumbers[binaryMid] }} vs {{ binaryTarget }}</div>
<div class="info-comparison">
{{ sortedNumbers[binaryMid] }} vs {{ binaryTarget }}
</div>
</div>
<div class="search-controls">
<button @click="binaryStep" class="search-btn">下一步</button>
@@ -125,7 +144,7 @@ const startLinearSearch = () => {
searching.value = true
searchStep.value = -1
foundIndex.value = -1
let step = 0
const interval = setInterval(() => {
if (step < numbers.value.length) {
@@ -151,7 +170,7 @@ const reset = () => {
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) {
@@ -185,8 +204,14 @@ const resetBinary = () => {
margin-bottom: 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; }
.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;
@@ -10,7 +10,7 @@
v-for="(item, index) in array"
:key="index"
class="array-bar"
:class="{
:class="{
comparing: comparingIndices.includes(index),
swapping: swappingIndices.includes(index),
sorted: index < sortedCount
@@ -92,27 +92,30 @@ const currentAlgoDesc = ref('选择一个排序算法开始演示')
const complexity = ref('')
const generateArray = () => {
array.value = Array.from({ length: 10 }, () => Math.floor(Math.random() * 90) + 10)
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 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)
@@ -124,7 +127,7 @@ const startBubbleSort = async () => {
}
sortedCount.value++
}
comparingIndices.value = []
sortedCount.value = arr.length
}
@@ -133,10 +136,10 @@ 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
@@ -154,11 +157,11 @@ const quickSort = async (arr, low, 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]
@@ -168,14 +171,14 @@ const partition = async (arr, low, high) => {
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>
@@ -196,8 +199,14 @@ const partition = async (arr, low, high) => {
margin-bottom: 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; }
.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;
@@ -7,8 +7,8 @@
<div class="demo-content">
<div class="storage-pyramid">
<div
v-for="(level, i) in storageLevels"
<div
v-for="(level, i) in storageLevels"
:key="level.name"
class="level"
:class="{ active: activeLevel === i }"
@@ -27,13 +27,8 @@
</div>
</div>
<div
v-if="currentLevel"
class="level-detail"
>
<div class="detail-title">
{{ currentLevel.name }} 详情
</div>
<div v-if="currentLevel" class="level-detail">
<div class="detail-title">{{ currentLevel.name }} 详情</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">访问速度</span>
@@ -59,7 +54,9 @@
</div>
<div class="info-box">
<strong>核心思想</strong>存储遵循"金字塔"原则越快的存储越贵容量越小CPU 需要的数据放在最快的存储寄存器缓存暂时不用的放在慢速大容量存储磁盘云端
<strong>核心思想</strong
>存储遵循"金字塔"原则越快的存储越贵容量越小CPU
需要的数据放在最快的存储寄存器缓存暂时不用的放在慢速大容量存储磁盘云端
</div>
</div>
</template>
@@ -70,55 +67,55 @@ import { ref, computed } from 'vue'
const activeLevel = ref(0)
const storageLevels = [
{
name: '寄存器',
speed: '~1 纳秒',
size: '几百字节',
{
name: '寄存器',
speed: '~1 纳秒',
size: '几百字节',
width: '30%',
cost: '极高',
volatile: '是',
desc: 'CPU 内部最快的存储,直接参与运算。数量有限,由编译器自动管理。'
},
{
name: 'L1 缓存',
speed: '~2 纳秒',
size: '32-64 KB',
{
name: 'L1 缓存',
speed: '~2 纳秒',
size: '32-64 KB',
width: '45%',
cost: '很高',
volatile: '是',
desc: 'CPU 内置的高速缓存,存储最常用的数据。每个核心独立拥有。'
},
{
name: 'L2/L3 缓存',
speed: '~10 纳秒',
size: '几 MB',
{
name: 'L2/L3 缓存',
speed: '~10 纳秒',
size: '几 MB',
width: '60%',
cost: '高',
volatile: '是',
desc: '更大但稍慢的缓存,L3 通常多核心共享。'
},
{
name: '内存 (RAM)',
speed: '~100 纳秒',
size: '8-128 GB',
{
name: '内存 (RAM)',
speed: '~100 纳秒',
size: '8-128 GB',
width: '75%',
cost: '中等',
volatile: '是',
desc: '程序运行时的主要工作区。断电后数据丢失。'
},
{
name: 'SSD 固态硬盘',
speed: '~100 微秒',
size: '256 GB - 4 TB',
{
name: 'SSD 固态硬盘',
speed: '~100 微秒',
size: '256 GB - 4 TB',
width: '90%',
cost: '较低',
volatile: '否',
desc: '比机械硬盘快很多,无机械部件。断电数据保留。'
},
{
name: 'HDD 机械硬盘',
speed: '~10 毫秒',
size: '1-20 TB',
{
name: 'HDD 机械硬盘',
speed: '~10 毫秒',
size: '1-20 TB',
width: '100%',
cost: '低',
volatile: '否',
@@ -145,8 +142,15 @@ const currentLevel = computed(() => storageLevels[activeLevel.value])
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.demo-content {
display: flex;
@@ -251,5 +255,4 @@ const currentLevel = computed(() => storageLevels[activeLevel.value])
display: flex;
gap: 0.25rem;
}
</style>
@@ -106,8 +106,7 @@
</div>
</template>
<script setup>
</script>
<script setup></script>
<style scoped>
.storage-hierarchy-demo {
@@ -125,8 +124,14 @@
margin-bottom: 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; }
.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;
@@ -16,7 +16,7 @@
min="0"
max="255"
@input="calculate"
>
/>
<span>.</span>
<input
v-model="ip[1]"
@@ -24,7 +24,7 @@
min="0"
max="255"
@input="calculate"
>
/>
<span>.</span>
<input
v-model="ip[2]"
@@ -32,7 +32,7 @@
min="0"
max="255"
@input="calculate"
>
/>
<span>.</span>
<input
v-model="ip[3]"
@@ -40,7 +40,7 @@
min="0"
max="255"
@input="calculate"
>
/>
</div>
</div>
<div class="input-group">
@@ -53,7 +53,7 @@
min="8"
max="30"
@input="calculate"
>
/>
</div>
</div>
</div>
@@ -82,9 +82,7 @@
</div>
<div class="binary-section">
<div class="binary-title">
二进制表示
</div>
<div class="binary-title">二进制表示</div>
<div class="binary-row">
<span class="binary-label">IP 地址:</span>
<span class="binary-value">{{ ipBinary }}</span>
@@ -104,13 +102,11 @@
</div>
<div class="visual-section">
<div class="visual-title">
地址结构可视化
</div>
<div class="visual-title">地址结构可视化</div>
<div class="address-visual">
<div class="bit-blocks">
<div
v-for="(bit, i) in bits"
<div
v-for="(bit, i) in bits"
:key="i"
:class="['bit', { network: i < cidr, host: i >= cidr }]"
>
@@ -118,15 +114,21 @@
</div>
</div>
<div class="legend">
<span class="legend-item"><span class="network-box" /> 网络位 ({{ cidr }})</span>
<span class="legend-item"><span class="host-box" /> 主机 ({{ 32 - cidr }})</span>
<span class="legend-item"
><span class="network-box" /> 网络 ({{ cidr }})</span
>
<span class="legend-item"
><span class="host-box" /> 主机位 ({{ 32 - cidr }})</span
>
</div>
</div>
</div>
</div>
<div class="info-box">
<strong>核心思想</strong>子网掩码决定了 IP 地址的哪部分是"网络号"(小区)哪部分是"主机号"(房间)/24 表示前 24 位是网络位 8 位是主机位
<strong>核心思想</strong>子网掩码决定了 IP
地址的哪部分是"网络号"(小区)哪部分是"主机号"(房间)/24 表示前 24
位是网络位 8 位是主机位
</div>
</div>
</template>
@@ -138,7 +140,7 @@ const ip = ref([192, 168, 1, 100])
const cidr = ref(24)
const mask = computed(() => {
const maskValue = 0xFFFFFFFF << (32 - cidr.value)
const maskValue = 0xffffffff << (32 - cidr.value)
return [
(maskValue >>> 24) & 255,
(maskValue >>> 16) & 255,
@@ -148,14 +150,16 @@ const mask = computed(() => {
})
const ipValue = computed(() => {
return (parseInt(ip.value[0]) << 24) +
(parseInt(ip.value[1]) << 16) +
(parseInt(ip.value[2]) << 8) +
parseInt(ip.value[3])
return (
(parseInt(ip.value[0]) << 24) +
(parseInt(ip.value[1]) << 16) +
(parseInt(ip.value[2]) << 8) +
parseInt(ip.value[3])
)
})
const maskValue = computed(() => {
return 0xFFFFFFFF << (32 - cidr.value)
return 0xffffffff << (32 - cidr.value)
})
const networkAddress = computed(() => {
@@ -187,21 +191,21 @@ const hostRange = computed(() => {
const network = ipValue.value & maskValue.value
const first = network + 1
const last = (network | (~maskValue.value >>> 0)) - 1
const firstIP = [
(first >>> 24) & 255,
(first >>> 16) & 255,
(first >>> 8) & 255,
first & 255
].join('.')
const lastIP = [
(last >>> 24) & 255,
(last >>> 16) & 255,
(last >>> 8) & 255,
last & 255
].join('.')
return `${firstIP} - ${lastIP}`
})
@@ -224,7 +228,10 @@ const maskBinary = computed(() => {
})
const bits = computed(() => {
return ip.value.map(octet => toBinary(parseInt(octet))).join('').split('')
return ip.value
.map((octet) => toBinary(parseInt(octet)))
.join('')
.split('')
})
const networkBinary = computed(() => {
@@ -236,7 +243,7 @@ const hostBinary = computed(() => {
})
const calculate = () => {
ip.value = ip.value.map(v => Math.min(255, Math.max(0, parseInt(v) || 0)))
ip.value = ip.value.map((v) => Math.min(255, Math.max(0, parseInt(v) || 0)))
cidr.value = Math.min(30, Math.max(8, cidr.value || 24))
}
@@ -261,8 +268,15 @@ onMounted(() => {
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.input-section {
display: flex;
@@ -434,7 +448,8 @@ onMounted(() => {
gap: 0.25rem;
}
.network-box, .host-box {
.network-box,
.host-box {
width: 12px;
height: 12px;
border-radius: 2px;
@@ -458,5 +473,4 @@ onMounted(() => {
display: flex;
gap: 0.25rem;
}
</style>
@@ -7,14 +7,14 @@
<div class="demo-content">
<div class="comparison-tabs">
<button
<button
:class="['tab-btn', { active: activeTab === 'tcp' }]"
@click="activeTab = 'tcp'"
>
<span class="tab-icon">📨</span>
<span>TCP (可靠)</span>
</button>
<button
<button
:class="['tab-btn', { active: activeTab === 'udp' }]"
@click="activeTab = 'udp'"
>
@@ -23,15 +23,12 @@
</button>
</div>
<div
v-if="currentProtocol"
class="protocol-detail"
>
<div v-if="currentProtocol" class="protocol-detail">
<div class="detail-header">
<span class="detail-name">{{ currentProtocol.name }}</span>
<span class="detail-full">{{ currentProtocol.fullName }}</span>
</div>
<div class="feature-grid">
<div
v-for="(feature, i) in currentProtocol.features"
@@ -45,9 +42,7 @@
</div>
<div class="mechanism-section">
<div class="mechanism-title">
核心机制
</div>
<div class="mechanism-title">核心机制</div>
<div class="mechanism-list">
<div
v-for="(m, i) in currentProtocol.mechanisms"
@@ -61,70 +56,53 @@
</div>
<div class="use-cases">
<div class="use-title">
适用场景
</div>
<div class="use-title">适用场景</div>
<div class="use-tags">
<span
v-for="(use, i) in currentProtocol.useCases"
:key="i"
class="use-tag"
>{{ use }}</span>
>{{ use }}</span
>
</div>
</div>
</div>
<div class="visual-demo">
<div class="visual-title">
传输过程演示
</div>
<div class="visual-title">传输过程演示</div>
<div class="transmission-demo">
<div class="sender">
<div class="node-label">
发送方
</div>
<div class="node-label">发送方</div>
<div class="packets">
<div
v-for="(packet, i) in packets"
<div
v-for="(packet, i) in packets"
:key="i"
:class="['packet', { sent: packet.sent, acked: packet.acked, lost: packet.lost }]"
:class="[
'packet',
{ sent: packet.sent, acked: packet.acked, lost: packet.lost }
]"
>
{{ packet.seq }}
</div>
</div>
</div>
<div class="network-channel">
<div class="channel-label">
网络通道
</div>
<div
class="channel-status"
:class="{ congested: isCongested }"
>
<div class="channel-label">网络通道</div>
<div class="channel-status" :class="{ congested: isCongested }">
{{ isCongested ? '拥堵' : '正常' }}
</div>
<button
class="demo-btn"
@click="runDemo"
>
开始演示
</button>
<button
class="demo-btn"
@click="toggleCongestion"
>
<button class="demo-btn" @click="runDemo">开始演示</button>
<button class="demo-btn" @click="toggleCongestion">
{{ isCongested ? '恢复网络' : '模拟丢包' }}
</button>
</div>
<div class="receiver">
<div class="node-label">
接收方
</div>
<div class="node-label">接收方</div>
<div class="received-packets">
<div
v-for="(packet, i) in receivedPackets"
<div
v-for="(packet, i) in receivedPackets"
:key="i"
class="received-packet"
>
@@ -133,17 +111,11 @@
</div>
</div>
</div>
<div class="demo-log">
<div class="log-title">
传输日志
</div>
<div class="log-title">传输日志</div>
<div class="log-content">
<div
v-for="(log, i) in logs"
:key="i"
class="log-item"
>
<div v-for="(log, i) in logs" :key="i" class="log-item">
{{ log }}
</div>
</div>
@@ -151,9 +123,7 @@
</div>
<div class="comparison-table">
<div class="table-title">
特性对比
</div>
<div class="table-title">特性对比</div>
<table>
<thead>
<tr>
@@ -163,10 +133,7 @@
</tr>
</thead>
<tbody>
<tr
v-for="(row, i) in comparisonData"
:key="i"
>
<tr v-for="(row, i) in comparisonData" :key="i">
<td class="feature-col">
{{ row.feature }}
</td>
@@ -183,7 +150,9 @@
</div>
<div class="info-box">
<strong>核心思想</strong>TCP 像挂号信确保送达但较慢UDP 像平信快速但不保证送达选择哪种协议取决于应用场景需要可靠性选 TCP需要实时性选 UDP
<strong>核心思想</strong>TCP 像挂号信确保送达但较慢UDP
像平信快速但不保证送达选择哪种协议取决于应用场景需要可靠性选
TCP需要实时性选 UDP
</div>
</div>
</template>
@@ -267,25 +236,25 @@ const toggleCongestion = () => {
const runDemo = async () => {
receivedPackets.value = []
logs.value = ['开始传输演示...']
for (let i = 0; i < packets.value.length; i++) {
packets.value[i].sent = false
packets.value[i].acked = false
packets.value[i].lost = false
}
const isTcp = activeTab.value === 'tcp'
for (let i = 0; i < packets.value.length; i++) {
const packet = packets.value[i]
packet.sent = true
if (isCongested.value && Math.random() > 0.5) {
packet.lost = true
logs.value.push(`${packet.seq} 丢失!`)
if (isTcp) {
await new Promise(r => setTimeout(r, 500))
await new Promise((r) => setTimeout(r, 500))
logs.value.push(`TCP 重传包 ${packet.seq}...`)
packet.lost = false
receivedPackets.value.push(packet.seq)
@@ -297,12 +266,14 @@ const runDemo = async () => {
packet.acked = true
logs.value.push(`${packet.seq} 送达`)
}
await new Promise(r => setTimeout(r, 300))
await new Promise((r) => setTimeout(r, 300))
}
if (isTcp) {
logs.value.push(`TCP 完成: 收到 ${receivedPackets.value.length} 个包,顺序: ${receivedPackets.value.join(', ')}`)
logs.value.push(
`TCP 完成: 收到 ${receivedPackets.value.length} 个包,顺序: ${receivedPackets.value.join(', ')}`
)
} else {
logs.value.push(`UDP 完成: 收到 ${receivedPackets.value.length} 个包`)
}
@@ -325,8 +296,15 @@ const runDemo = async () => {
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.comparison-tabs {
display: flex;
@@ -353,7 +331,9 @@ const runDemo = async () => {
background: var(--vp-c-brand-soft);
}
.tab-icon { font-size: 1.1rem; }
.tab-icon {
font-size: 1.1rem;
}
.protocol-detail {
background: var(--vp-c-bg);
@@ -395,15 +375,24 @@ const runDemo = async () => {
border-radius: 4px;
}
.feature-icon { font-size: 1rem; }
.feature-name { font-size: 0.75rem; color: var(--vp-c-text-2); }
.feature-value { font-size: 0.8rem; font-weight: bold; }
.feature-icon {
font-size: 1rem;
}
.feature-name {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.feature-value {
font-size: 0.8rem;
font-weight: bold;
}
.mechanism-section {
margin-bottom: 0.75rem;
}
.mechanism-title, .use-title {
.mechanism-title,
.use-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
@@ -465,7 +454,8 @@ const runDemo = async () => {
margin-bottom: 0.75rem;
}
.sender, .receiver {
.sender,
.receiver {
flex: 1;
padding: 0.5rem;
background: var(--vp-c-bg-alt);
@@ -478,7 +468,8 @@ const runDemo = async () => {
margin-bottom: 0.25rem;
}
.packets, .received-packets {
.packets,
.received-packets {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
@@ -604,7 +595,8 @@ table {
font-size: 0.8rem;
}
th, td {
th,
td {
border: 1px solid var(--vp-c-divider);
padding: 0.4rem;
text-align: center;
@@ -635,5 +627,4 @@ th {
display: flex;
gap: 0.25rem;
}
</style>
@@ -5,7 +5,7 @@
<div class="schematic" @click="gateOn = !gateOn">
<!-- Source terminal -->
<div class="terminal-box source">
<span class="pin-label">源极<br><span class="en">Source</span></span>
<span class="pin-label">源极<br /><span class="en">Source</span></span>
<div class="pin-wire" :class="{ active: gateOn }"></div>
</div>
@@ -23,13 +23,15 @@
</template>
<span v-else class="block-mark"></span>
</div>
<div class="channel-status">{{ gateOn ? '导通 → 输出 1' : '断开 → 输出 0' }}</div>
<div class="channel-status">
{{ gateOn ? '导通 → 输出 1' : '断开 → 输出 0' }}
</div>
</div>
<!-- Drain terminal -->
<div class="terminal-box drain">
<div class="pin-wire" :class="{ active: gateOn }"></div>
<span class="pin-label">漏极<br><span class="en">Drain</span></span>
<span class="pin-label">漏极<br /><span class="en">Drain</span></span>
</div>
</div>
@@ -179,14 +181,28 @@ const gateOn = ref(false)
animation: flow 1.2s linear infinite;
}
.electron.e2 { animation-delay: 0.4s; }
.electron.e3 { animation-delay: 0.8s; }
.electron.e2 {
animation-delay: 0.4s;
}
.electron.e3 {
animation-delay: 0.8s;
}
@keyframes flow {
0% { left: -8%; opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { left: 108%; opacity: 0; }
0% {
left: -8%;
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
left: 108%;
opacity: 0;
}
}
.channel-status {
@@ -208,7 +224,11 @@ const gateOn = ref(false)
}
@media (max-width: 480px) {
.pin-wire { width: 1.5rem; }
.channel-area { min-width: 5rem; }
.pin-wire {
width: 1.5rem;
}
.channel-area {
min-width: 5rem;
}
}
</style>
@@ -12,36 +12,20 @@
:class="{ active: activeType === 'serial' }"
@click="activeType = 'serial'"
>
<div class="card-icon">
</div>
<div class="card-title">
串行传输
</div>
<div class="card-desc">
一位一位依次传输
</div>
<div class="card-examples">
USBSATAPCIe
</div>
<div class="card-icon"></div>
<div class="card-title">串行传输</div>
<div class="card-desc">一位一位依次传输</div>
<div class="card-examples">USBSATAPCIe</div>
</div>
<div
class="type-card"
:class="{ active: activeType === 'parallel' }"
@click="activeType = 'parallel'"
>
<div class="card-icon">
</div>
<div class="card-title">
并行传输
</div>
<div class="card-desc">
多位同时传输
</div>
<div class="card-examples">
旧式打印机接口IDE
</div>
<div class="card-icon"></div>
<div class="card-title">并行传输</div>
<div class="card-desc">多位同时传输</div>
<div class="card-examples">旧式打印机接口IDE</div>
</div>
</div>
@@ -51,47 +35,35 @@
</div>
<div class="visual-area">
<div class="sender">
<div class="device-label">
发送端
</div>
<div class="device-label">发送端</div>
<div class="data-bits">
<span
v-for="(bit, i) in dataBits"
:key="i"
class="bit"
:class="{ sending: sendingBit === i && activeType === 'serial' }"
>{{ bit }}</span>
:class="{
sending: sendingBit === i && activeType === 'serial'
}"
>{{ bit }}</span
>
</div>
</div>
<div class="channels">
<div
v-if="activeType === 'serial'"
class="channel serial"
>
<div class="channel-label">
单通道
</div>
<div v-if="activeType === 'serial'" class="channel serial">
<div class="channel-label">单通道</div>
<div class="channel-flow">
<span
v-for="i in 5"
:key="i"
class="flow-dot"
:class="{ active: sendingBit !== null }"
></span>
></span
>
</div>
</div>
<div
v-else
class="channel parallel"
>
<div
v-for="i in 4"
:key="i"
class="channel-row"
>
<div class="channel-label">
通道{{ i }}
</div>
<div v-else class="channel parallel">
<div v-for="i in 4" :key="i" class="channel-row">
<div class="channel-label">通道{{ i }}</div>
<div class="channel-flow">
<span class="flow-dot active"></span>
</div>
@@ -99,30 +71,19 @@
</div>
</div>
<div class="receiver">
<div class="device-label">
接收端
</div>
<div class="device-label">接收端</div>
<div class="data-bits received">
<span
v-for="(bit, i) in receivedBits"
:key="i"
class="bit"
>{{ bit }}</span>
<span v-for="(bit, i) in receivedBits" :key="i" class="bit">{{
bit
}}</span>
</div>
</div>
</div>
<button
class="send-btn"
@click="startTransmission"
>
发送数据
</button>
<button class="send-btn" @click="startTransmission">发送数据</button>
</div>
<div class="comparison-table">
<div class="table-title">
串行 vs 并行对比
</div>
<div class="table-title">串行 vs 并行对比</div>
<table>
<thead>
<tr>
@@ -158,7 +119,8 @@
</div>
<div class="info-box">
<strong>核心思想</strong>现代高速传输多采用串行方式虽然并行"看起来"更快一次传多位但串行可以跑更高频率抗干扰更强实际速度反而更快
<strong>核心思想</strong
>现代高速传输多采用串行方式虽然并行"看起来"更快一次传多位但串行可以跑更高频率抗干扰更强实际速度反而更快
</div>
</div>
</template>
@@ -207,8 +169,15 @@ const startTransmission = () => {
margin-bottom: 0.75rem;
}
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.demo-content {
display: flex;
@@ -279,7 +248,8 @@ const startTransmission = () => {
margin-bottom: 0.75rem;
}
.sender, .receiver {
.sender,
.receiver {
text-align: center;
}
@@ -382,7 +352,8 @@ table {
font-size: 0.8rem;
}
th, td {
th,
td {
border: 1px solid var(--vp-c-divider);
padding: 0.4rem;
text-align: center;
@@ -402,5 +373,4 @@ th {
display: flex;
gap: 0.25rem;
}
</style>
@@ -107,7 +107,8 @@
<div class="port-title">端口号应用程序的标识</div>
<div class="port-examples">
<div class="port-intro">
端口号就像公寓房间号IP 地址是公寓楼地址合起来才能找到具体的应用程序
端口号就像公寓房间号IP
地址是公寓楼地址合起来才能找到具体的应用程序
</div>
<div class="port-list">
<div
@@ -222,8 +223,14 @@ const currentProtocol = computed(() => protocolData[activeProtocol.value])
margin-bottom: 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; }
.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;
@@ -422,9 +429,17 @@ const currentProtocol = computed(() => protocolData[activeProtocol.value])
}
@keyframes slideRight {
0% { transform: translateX(-100%); opacity: 0; }
50% { opacity: 1; }
100% { transform: translateX(100%); opacity: 0; }
0% {
transform: translateX(-100%);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100%);
opacity: 0;
}
}
.side-desc {
@@ -24,20 +24,43 @@
<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"
<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)` }"
<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>
<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>
@@ -83,14 +106,9 @@
<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;
&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">
@@ -235,8 +253,14 @@ const binaryTreeLines = [
margin-bottom: 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; }
.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;