feat(computer-fundamentals): add comprehensive content for computer fundamentals section

Add detailed documentation and interactive demos for computer fundamentals topics including:
- Transistor to CPU architecture
- Data encoding, storage and transmission
- Operating system concepts (processes, memory, filesystems)
- Programming language overview and paradigms
- Algorithm and data structure basics

Includes Vue component demos for key concepts with visualizations and interactive elements to enhance learning experience. All content is written in Chinese with markdown formatting and embedded components.

The commit also updates the sidebar navigation and adds new Vue components for interactive demonstrations of key computer science concepts.
This commit is contained in:
sanbuphy
2026-02-18 15:52:55 +08:00
parent 47377646df
commit d0afb042b8
27 changed files with 8843 additions and 10 deletions
@@ -0,0 +1,300 @@
<template>
<div class="adder-demo">
<div class="demo-header">
<span class="icon"></span>
<span class="title">加法器用逻辑门做加法</span>
<span class="subtitle">从逻辑门到算术运算</span>
</div>
<div class="demo-content">
<div class="adder-controls">
<div class="input-group">
<label>A:</label>
<div class="bits">
<button
v-for="(bit, i) in bitsA"
:key="'a'+i"
class="bit-btn"
:class="{ on: bit }"
@click="toggleBit('A', i)"
>{{ bit }}</button>
</div>
<span class="decimal">= {{ decimalA }}</span>
</div>
<div class="operator">+</div>
<div class="input-group">
<label>B:</label>
<div class="bits">
<button
v-for="(bit, i) in bitsB"
:key="'b'+i"
class="bit-btn"
:class="{ on: bit }"
@click="toggleBit('B', i)"
>{{ bit }}</button>
</div>
<span class="decimal">= {{ decimalB }}</span>
</div>
</div>
<div class="adder-visual">
<div class="adder-stage" v-for="(s, i) in stages" :key="i">
<div class="stage-label">{{ s.label }}</div>
<div class="stage-bits">
<span class="bit-label">A{{ 3-i }}: {{ bitsA[i] }}</span>
<span class="bit-label">B{{ 3-i }}: {{ bitsB[i] }}</span>
<span class="bit-label" v-if="i > 0">C{{ i }}: {{ carries[i-1] }}</span>
</div>
<div class="stage-result">
<span class="sum-bit">S{{ 3-i }}: {{ sumBits[i] }}</span>
<span class="carry-bit">C{{ i+1 }}: {{ carries[i] }}</span>
</div>
</div>
</div>
<div class="result-display">
<div class="result-row">
<span class="result-label">二进制结果:</span>
<span class="result-bits">{{ resultBinary }}</span>
</div>
<div class="result-row">
<span class="result-label">十进制验证:</span>
<span class="result-decimal">{{ decimalA }} + {{ decimalB }} = {{ resultDecimal }}</span>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>加法器用全加器级联实现每个全加器处理一位产生"和""进位"进位传递给下一位就像我们手算加法一样
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const bitsA = ref([0, 0, 1, 1])
const bitsB = ref([0, 0, 1, 0])
const toggleBit = (arr, i) => {
if (arr === 'A') {
bitsA.value[i] = bitsA.value[i] ? 0 : 1
} else {
bitsB.value[i] = bitsB.value[i] ? 0 : 1
}
}
const decimalA = computed(() => {
return bitsA.value.reduce((acc, bit, i) => acc + bit * Math.pow(2, 3-i), 0)
})
const decimalB = computed(() => {
return bitsB.value.reduce((acc, bit, i) => acc + bit * Math.pow(2, 3-i), 0)
})
const carries = computed(() => {
const c = [0, 0, 0, 0]
for (let i = 3; i >= 0; i--) {
const sum = bitsA.value[i] + bitsB.value[i] + (i < 3 ? c[i+1] : 0)
c[i] = sum >= 2 ? 1 : 0
}
return c
})
const sumBits = computed(() => {
const s = [0, 0, 0, 0]
for (let i = 3; i >= 0; i--) {
const sum = bitsA.value[i] + bitsB.value[i] + (i < 3 ? carries.value[i+1] : 0)
s[i] = sum % 2
}
return s
})
const resultBinary = computed(() => {
const allBits = [carries.value[0], ...sumBits.value]
return allBits.join('')
})
const resultDecimal = computed(() => {
return decimalA.value + decimalB.value
})
const stages = [
{ label: '第4位 (个位)' },
{ label: '第3位' },
{ label: '第2位' },
{ label: '第1位 (最高位)' }
]
</script>
<style scoped>
.adder-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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; }
.adder-controls {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.input-group {
display: flex;
align-items: center;
gap: 0.5rem;
}
.input-group label {
font-weight: bold;
font-size: 0.9rem;
}
.bits {
display: flex;
gap: 0.25rem;
}
.bit-btn {
width: 28px;
height: 28px;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
transition: all 0.2s;
}
.bit-btn.on {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.decimal {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.operator {
font-size: 1.2rem;
font-weight: bold;
color: var(--vp-c-brand);
}
.adder-visual {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
overflow-x: auto;
}
.adder-stage {
flex: 1;
min-width: 100px;
padding: 0.5rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.stage-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
text-align: center;
margin-bottom: 0.5rem;
border-bottom: 1px solid var(--vp-c-divider);
padding-bottom: 0.25rem;
}
.stage-bits {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.75rem;
margin-bottom: 0.5rem;
}
.bit-label {
color: var(--vp-c-text-2);
}
.stage-result {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.8rem;
font-weight: bold;
}
.sum-bit {
color: var(--vp-c-brand);
}
.carry-bit {
color: var(--vp-c-warning);
}
.result-display {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.result-row {
display: flex;
gap: 0.5rem;
margin-bottom: 0.25rem;
}
.result-row:last-child {
margin-bottom: 0;
}
.result-label {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.result-bits {
font-family: monospace;
font-weight: bold;
color: var(--vp-c-brand);
}
.result-decimal {
font-weight: bold;
color: var(--vp-c-success);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,535 @@
<template>
<div class="algorithm-demo">
<div class="demo-header">
<span class="icon">🎯</span>
<span class="title">算法思维解决问题的方法</span>
<span class="subtitle">不同策略解决不同类型的问题</span>
</div>
<div class="demo-content">
<div class="algorithm-tabs">
<button
v-for="algo in algorithms"
:key="algo.name"
:class="['tab-btn', { active: activeAlgo === algo.name }]"
@click="activeAlgo = algo.name"
>{{ algo.name }}</button>
</div>
<div class="algorithm-visual">
<div class="visual-header">
<span class="algo-name">{{ currentAlgo.name }}</span>
<span class="algo-desc">{{ currentAlgo.desc }}</span>
</div>
<div class="visual-content">
<div v-if="activeAlgo === '二分查找'" class="binary-search">
<div class="search-input">
<span>在有序数组中查找</span>
<input v-model.number="searchTarget" type="number" class="num-input" placeholder="输入数字" />
<button class="search-btn" @click="runBinarySearch">查找</button>
</div>
<div class="array-display">
<div
v-for="(num, i) in sortedArray"
:key="i"
class="array-cell"
:class="{
highlight: i >= searchRange.left && i <= searchRange.right,
found: i === foundIndex,
mid: i === midIndex
}"
>
{{ num }}
</div>
</div>
<div class="search-info" v-if="searchSteps.length">
<div class="step" v-for="(step, i) in searchSteps" :key="i">{{ step }}</div>
</div>
</div>
<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>
</div>
<div class="array-display">
<div
v-for="(num, i) in sortArray"
:key="i"
class="array-cell"
:class="{ comparing: comparingIndices.includes(i), sorted: sortedIndices.includes(i) }"
>
{{ num }}
</div>
</div>
<div class="sort-info">{{ sortStatus }}</div>
</div>
<div v-else-if="activeAlgo === '递归'" class="recursion">
<div class="recursion-input">
<span>计算斐波那契数列第</span>
<input v-model.number="fibN" type="number" min="1" max="15" class="num-input" />
<span></span>
<button class="calc-btn" @click="calcFib">计算</button>
</div>
<div class="fib-result" v-if="fibResult !== null">
<span class="result-value">F({{ fibN }}) = {{ fibResult }}</span>
</div>
<div class="recursion-tree" v-if="fibSteps.length">
<div class="tree-title">递归调用过程</div>
<div class="tree-content">
<div v-for="(step, i) in fibSteps.slice(0, 8)" :key="i" class="tree-node">
{{ step }}
</div>
<div v-if="fibSteps.length > 8" class="tree-more">... {{ fibSteps.length }} 次调用</div>
</div>
</div>
</div>
<div v-else-if="activeAlgo === '贪心'" class="greedy">
<div class="greedy-desc">硬币找零问题用最少的硬币凑出指定金额</div>
<div class="greedy-input">
<span>目标金额</span>
<input v-model.number="coinTarget" type="number" min="1" class="num-input" />
<button class="calc-btn" @click="calcCoins">计算</button>
</div>
<div class="coins-available">
可用硬币{{ coins.join(', ') }}
</div>
<div class="coin-result" v-if="coinResult.length">
<div class="result-title">找零方案</div>
<div class="coin-list">
<span v-for="(c, i) in coinResult" :key="i" class="coin">{{ c }}</span>
</div>
<div class="result-summary"> {{ coinResult.length }} 枚硬币</div>
</div>
</div>
</div>
</div>
<div class="complexity-info">
<div class="info-title">时间复杂度速查</div>
<div class="complexity-list">
<div class="complexity-item" v-for="c in complexities" :key="c.name">
<span class="c-name">{{ c.name }}</span>
<span class="c-value" :class="c.class">{{ c.value }}</span>
<span class="c-desc">{{ c.desc }}</span>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>算法是解决问题的方法好的算法能让程序效率提升几个数量级理解算法思维比记住具体算法更重要
</div>
</div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue'
const activeAlgo = ref('二分查找')
const algorithms = [
{ name: '二分查找', desc: '每次排除一半,O(log n)' },
{ name: '排序', desc: '将无序变有序' },
{ name: '递归', desc: '自己调用自己' },
{ name: '贪心', desc: '每步选最优' }
]
const currentAlgo = computed(() => {
return algorithms.find(a => a.name === activeAlgo.value)
})
const sortedArray = ref([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25])
const searchTarget = ref(13)
const searchRange = reactive({ left: 0, right: 12 })
const foundIndex = ref(-1)
const midIndex = ref(-1)
const searchSteps = ref([])
const runBinarySearch = () => {
searchSteps.value = []
foundIndex.value = -1
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]}`)
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},在右半部分继续查找`)
} else {
right = mid - 1
searchSteps.value.push(`${sortedArray.value[mid]} > ${searchTarget.value},在左半部分继续查找`)
}
}
searchSteps.value.push(`未找到目标 ${searchTarget.value}`)
}
const sortArray = ref([64, 34, 25, 12, 22, 11, 90, 45])
const comparingIndices = ref([])
const sortedIndices = ref([])
const sortStatus = ref('点击"开始排序"观察冒泡排序过程')
const resetArray = () => {
sortArray.value = [64, 34, 25, 12, 22, 11, 90, 45]
comparingIndices.value = []
sortedIndices.value = []
sortStatus.value = '数组已重置'
}
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))
if (arr[j] > arr[j + 1]) {
[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))
}
}
sortedIndices.value.push(n - i - 1)
}
sortedIndices.value.push(0)
comparingIndices.value = []
sortStatus.value = '排序完成!'
}
const fibN = ref(8)
const fibResult = ref(null)
const fibSteps = ref([])
const calcFib = () => {
fibSteps.value = []
const fib = (n) => {
fibSteps.value.push(`fib(${n})`)
if (n <= 1) return n
return fib(n - 1) + fib(n - 2)
}
fibResult.value = fib(fibN.value)
}
const coinTarget = ref(67)
const coins = [100, 50, 20, 10, 5, 1]
const coinResult = ref([])
const calcCoins = () => {
coinResult.value = []
let remaining = coinTarget.value
for (const coin of coins) {
while (remaining >= coin) {
coinResult.value.push(coin)
remaining -= coin
}
}
}
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²)', value: '平方', desc: '较慢,如冒泡排序', class: 'bad' },
{ name: 'O(2ⁿ)', value: '指数', desc: '很慢,如暴力递归', class: 'bad' }
]
</script>
<style scoped>
.algorithm-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.tab-btn {
padding: 0.4rem 0.8rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.algorithm-visual {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.visual-header {
margin-bottom: 0.75rem;
}
.algo-name {
font-weight: bold;
font-size: 1rem;
}
.algo-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-left: 0.5rem;
}
.search-input, .greedy-input, .recursion-input {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
flex-wrap: wrap;
}
.num-input {
width: 60px;
padding: 0.25rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
background: var(--vp-c-bg-alt);
}
.search-btn, .sort-btn, .calc-btn {
padding: 0.25rem 0.75rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
}
.array-display {
display: flex;
gap: 2px;
margin-bottom: 0.75rem;
flex-wrap: wrap;
}
.array-cell {
padding: 0.5rem;
background: var(--vp-c-bg-alt);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
font-weight: bold;
font-size: 0.85rem;
min-width: 32px;
text-align: center;
}
.array-cell.highlight {
background: var(--vp-c-brand-soft);
}
.array-cell.found {
background: var(--vp-c-success);
color: white;
}
.array-cell.mid {
border: 2px solid var(--vp-c-brand);
}
.array-cell.comparing {
background: var(--vp-c-warning-soft);
}
.array-cell.sorted {
background: var(--vp-c-success-soft);
}
.search-info, .sort-info {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.step {
padding: 0.15rem 0;
}
.sort-controls {
display: flex;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.fib-result {
font-size: 1.1rem;
font-weight: bold;
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.recursion-tree {
background: var(--vp-c-bg-alt);
padding: 0.5rem;
border-radius: 4px;
}
.tree-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.25rem;
}
.tree-content {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
.tree-node {
font-size: 0.75rem;
font-family: monospace;
background: var(--vp-c-bg);
padding: 0.15rem 0.4rem;
border-radius: 3px;
}
.tree-more {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.greedy-desc {
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.coins-available {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.coin-result {
margin-top: 0.5rem;
}
.result-title {
font-weight: bold;
font-size: 0.85rem;
}
.coin-list {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
margin: 0.25rem 0;
}
.coin {
padding: 0.25rem 0.5rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-size: 0.8rem;
}
.result-summary {
font-size: 0.85rem;
color: var(--vp-c-success);
font-weight: bold;
}
.complexity-info {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.info-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.complexity-list {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.complexity-item {
display: flex;
gap: 0.5rem;
font-size: 0.8rem;
}
.c-name {
font-family: monospace;
font-weight: bold;
min-width: 60px;
}
.c-value {
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-desc {
color: var(--vp-c-text-2);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,598 @@
<template>
<div class="compiler-demo">
<div class="demo-header">
<span class="icon"></span>
<span class="title">编译器工作流程</span>
<span class="subtitle">从源代码到机器码的旅程</span>
</div>
<div class="demo-content">
<div class="pipeline-visual">
<div class="pipeline-title">编译流程</div>
<div class="pipeline-stages">
<div
v-for="(stage, i) in stages"
:key="i"
:class="['stage', { active: activeStage === i }]"
@click="activeStage = i"
>
<div class="stage-num">{{ i + 1 }}</div>
<div class="stage-name">{{ stage.name }}</div>
<div class="stage-output">{{ stage.output }}</div>
</div>
<div class="stage-arrow" v-for="i in stages.length - 1" :key="'arrow-' + i"></div>
</div>
</div>
<div class="stage-detail" v-if="currentStage">
<div class="detail-header">
<span class="detail-name">{{ currentStage.name }}</span>
</div>
<div class="detail-desc">{{ currentStage.desc }}</div>
<div class="detail-tasks">
<div class="task-title">主要任务</div>
<ul>
<li v-for="(task, j) in currentStage.tasks" :key="j">{{ task }}</li>
</ul>
</div>
<div class="detail-example">
<div class="example-title">示例</div>
<pre><code>{{ currentStage.example }}</code></pre>
</div>
</div>
<div class="interactive-demo">
<div class="demo-title">词法分析演示</div>
<div class="lexer-input">
<label>输入代码</label>
<input v-model="sourceCode" type="text" placeholder="例如: int x = 10 + 5;" />
</div>
<div class="lexer-output">
<div class="output-title">词法单元 (Tokens)</div>
<div class="tokens">
<div
v-for="(token, i) in tokens"
:key="i"
:class="['token', token.type]"
>
<span class="token-value">{{ token.value }}</span>
<span class="token-type">{{ token.type }}</span>
</div>
</div>
</div>
</div>
<div class="ast-demo">
<div class="demo-title">语法树 (AST) 可视化</div>
<div class="ast-input">
<label>表达式</label>
<input v-model="expression" type="text" placeholder="例如: 1 + 2 * 3" />
</div>
<div class="ast-visual">
<div class="ast-node root" v-if="ast">
<div class="node-value">{{ ast.value }}</div>
<div class="node-children" v-if="ast.left || ast.right">
<div class="ast-node left" v-if="ast.left">
<div class="node-value">{{ ast.left.value }}</div>
</div>
<div class="ast-node right" v-if="ast.right">
<div class="node-value">{{ ast.right.value }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="comparison-section">
<div class="section-title">编译型 vs 解释型 vs JIT</div>
<div class="comparison-grid">
<div class="comparison-item" v-for="(item, i) in executionModels" :key="i">
<div class="item-name">{{ item.name }}</div>
<div class="item-flow">{{ item.flow }}</div>
<div class="item-pros">{{ item.pros }}</div>
<div class="item-cons">{{ item.cons }}</div>
<div class="item-langs">{{ item.langs }}</div>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>编译器将人类可读的源代码转换为机器可执行的指令主要阶段包括词法分析语法分析语义分析中间代码生成优化和目标代码生成
</div>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const activeStage = ref(0)
const stages = [
{
name: '词法分析',
output: 'Token 流',
desc: '将源代码分解为一个个词法单元(Token)',
tasks: ['识别关键字、标识符、字面量、运算符', '过滤空白和注释', '记录位置信息'],
example: `源代码: int x = 10;
Tokens: [int][x][=][10][;]`
},
{
name: '语法分析',
output: 'AST',
desc: '根据语法规则,将 Token 流组织成语法树',
tasks: ['构建抽象语法树 (AST)', '检查语法错误', '确定运算优先级'],
example: `表达式: 1 + 2 * 3
AST:
+
/ \\
1 *
/ \\
2 3`
},
{
name: '语义分析',
output: '带类型的 AST',
desc: '检查语义正确性,进行类型检查',
tasks: ['类型检查', '作用域分析', '符号表构建', '类型推断'],
example: `int x = "hello"; // 类型错误!
int y = 10 + 5; // 正确`
},
{
name: '中间代码',
output: 'IR',
desc: '生成平台无关的中间表示',
tasks: ['生成三地址码或 SSA', '便于优化', '支持多目标平台'],
example: `x = 10 + 5
// 三地址码:
t1 = 10 + 5
x = t1`
},
{
name: '优化',
output: '优化后的 IR',
desc: '对中间代码进行各种优化',
tasks: ['常量折叠', '死代码消除', '循环优化', '内联展开'],
example: `// 优化前
x = 10 + 5
y = x * 2
// 优化后(常量折叠)
x = 15
y = 30`
},
{
name: '代码生成',
output: '机器码',
desc: '生成目标机器的机器码',
tasks: ['指令选择', '寄存器分配', '指令调度', '生成可执行文件'],
example: `// x = 15 的汇编
mov eax, 15
mov [x], eax`
}
]
const currentStage = computed(() => stages[activeStage.value])
const sourceCode = ref('int x = 10 + 5;')
const keywords = ['int', 'float', 'if', 'else', 'while', 'for', 'return', 'void', 'class', 'public', 'private']
const operators = ['+', '-', '*', '/', '=', '==', '!=', '<', '>', '<=', '>=']
const tokens = computed(() => {
const code = sourceCode.value
if (!code.trim()) return []
const result = []
const words = code.split(/(\s+|[;,\(\)\{\}\[\]])/)
for (const word of words) {
if (!word.trim()) continue
if (keywords.includes(word)) {
result.push({ value: word, type: 'keyword' })
} else if (operators.includes(word)) {
result.push({ value: word, type: 'operator' })
} else if (/^\d+$/.test(word)) {
result.push({ value: word, type: 'number' })
} else if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(word)) {
result.push({ value: word, type: 'identifier' })
} else if (word === ';') {
result.push({ value: word, type: 'punctuation' })
} else {
result.push({ value: word, type: 'unknown' })
}
}
return result
})
const expression = ref('1 + 2 * 3')
const ast = computed(() => {
const expr = expression.value.trim()
if (!expr) return null
const parseExpression = (str) => {
str = str.trim()
const addSubMatch = str.match(/^(.+?)\s*([+-])\s*(.+)$/)
if (addSubMatch) {
return {
value: addSubMatch[2],
left: parseExpression(addSubMatch[1]),
right: parseExpression(addSubMatch[3])
}
}
const mulDivMatch = str.match(/^(.+?)\s*([*/])\s*(.+)$/)
if (mulDivMatch) {
return {
value: mulDivMatch[2],
left: parseExpression(mulDivMatch[1]),
right: parseExpression(mulDivMatch[3])
}
}
if (/^\d+$/.test(str)) {
return { value: str }
}
return { value: str }
}
return parseExpression(expr)
})
const executionModels = [
{
name: '编译型',
flow: '源码 → 编译 → 机器码 → 执行',
pros: '执行快,编译期检查',
cons: '编译慢,跨平台难',
langs: 'C, C++, Rust, Go'
},
{
name: '解释型',
flow: '源码 → 解释器 → 逐行执行',
pros: '跨平台,开发快',
cons: '执行慢,运行时检查',
langs: 'Python, Ruby, PHP'
},
{
name: 'JIT',
flow: '源码 → 字节码 → JIT编译 → 执行',
pros: '兼顾性能和跨平台',
cons: '启动慢,内存占用大',
langs: 'Java, JavaScript(V8)'
}
]
</script>
<style scoped>
.compiler-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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; }
.pipeline-visual {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.pipeline-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.pipeline-stages {
display: flex;
align-items: center;
gap: 0.25rem;
flex-wrap: wrap;
position: relative;
}
.stage {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.4rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
cursor: pointer;
min-width: 80px;
border: 2px solid transparent;
}
.stage:hover {
background: var(--vp-c-bg-soft);
}
.stage.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.stage-num {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.7rem;
font-weight: bold;
margin-bottom: 0.25rem;
}
.stage-name {
font-size: 0.75rem;
font-weight: bold;
}
.stage-output {
font-size: 0.65rem;
color: var(--vp-c-text-2);
}
.stage-arrow {
color: var(--vp-c-text-3);
font-size: 0.8rem;
}
.stage-detail {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.detail-header {
margin-bottom: 0.5rem;
}
.detail-name {
font-weight: bold;
font-size: 1rem;
color: var(--vp-c-brand);
}
.detail-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.detail-tasks {
margin-bottom: 0.5rem;
}
.task-title, .example-title {
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 0.25rem;
}
.detail-tasks ul {
margin: 0;
padding-left: 1rem;
font-size: 0.8rem;
}
.detail-example {
background: var(--vp-c-bg-alt);
padding: 0.5rem;
border-radius: 4px;
}
pre {
margin: 0;
font-size: 0.75rem;
white-space: pre-wrap;
}
code {
font-family: monospace;
}
.interactive-demo, .ast-demo {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.demo-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.lexer-input, .ast-input {
margin-bottom: 0.5rem;
}
.lexer-input label, .ast-input label {
display: block;
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.25rem;
}
.lexer-input input, .ast-input input {
width: 100%;
padding: 0.4rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
background: var(--vp-c-bg-alt);
font-family: monospace;
font-size: 0.85rem;
}
.output-title {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.25rem;
}
.tokens {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
}
.token {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.25rem 0.4rem;
border-radius: 4px;
font-size: 0.75rem;
}
.token.keyword { background: #d4edda; }
.token.operator { background: #fff3cd; }
.token.number { background: #cce5ff; }
.token.identifier { background: #e2e3e5; }
.token.punctuation { background: #f8d7da; }
.token-value {
font-family: monospace;
font-weight: bold;
}
.token-type {
font-size: 0.65rem;
color: var(--vp-c-text-2);
}
.ast-visual {
display: flex;
justify-content: center;
padding: 1rem;
}
.ast-node {
display: flex;
flex-direction: column;
align-items: center;
}
.node-value {
padding: 0.4rem 0.6rem;
background: var(--vp-c-brand);
color: white;
border-radius: 4px;
font-weight: bold;
font-family: monospace;
}
.node-children {
display: flex;
gap: 1rem;
margin-top: 0.5rem;
position: relative;
}
.node-children::before {
content: '';
position: absolute;
top: -0.5rem;
left: 50%;
width: 1px;
height: 0.5rem;
background: var(--vp-c-divider);
}
.ast-node.left .node-value,
.ast-node.right .node-value {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand);
}
.comparison-section {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.section-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.comparison-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.5rem;
}
.comparison-item {
padding: 0.5rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
}
.item-name {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.25rem;
color: var(--vp-c-brand);
}
.item-flow {
font-size: 0.75rem;
font-family: monospace;
margin-bottom: 0.25rem;
}
.item-pros, .item-cons {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.item-pros::before { content: '✅ '; }
.item-cons::before { content: '❌ '; }
.item-langs {
font-size: 0.7rem;
color: var(--vp-c-text-3);
margin-top: 0.25rem;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,245 @@
<template>
<div class="cpu-arch-demo">
<div class="demo-header">
<span class="icon">🖥</span>
<span class="title">CPU 架构全貌</span>
<span class="subtitle">从门电路到处理器</span>
</div>
<div class="demo-content">
<div class="architecture-layers">
<div
v-for="(layer, i) in layers"
:key="layer.name"
class="layer"
:class="{ active: activeLayer === i }"
@click="activeLayer = activeLayer === i ? null : i"
>
<div class="layer-header">
<span class="layer-icon">{{ layer.icon }}</span>
<span class="layer-name">{{ layer.name }}</span>
<span class="layer-count">{{ layer.count }}</span>
</div>
<Transition name="fade">
<div v-if="activeLayer === i" class="layer-detail">
<p class="detail-desc">{{ layer.desc }}</p>
<div class="detail-example">
<span class="example-label">🌰 例子</span>
<span class="example-content">{{ layer.example }}</span>
</div>
</div>
</Transition>
</div>
</div>
<div class="cpu-components">
<div class="comp-title">CPU 核心组件</div>
<div class="comp-grid">
<div class="comp-item" v-for="comp in components" :key="comp.name">
<span class="comp-icon">{{ comp.icon }}</span>
<span class="comp-name">{{ comp.name }}</span>
<span class="comp-desc">{{ comp.desc }}</span>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>CPU是层次化构建的晶体管逻辑门功能单元处理器每一层都是下一层的"积木"最终形成能执行程序的"大脑"
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeLayer = ref(null)
const layers = [
{
name: '晶体管',
icon: '⚡',
count: '数十亿个',
desc: '最基本的开关单元,用半导体材料制成。现代CPU包含数十亿个晶体管。',
example: 'Apple M2 芯片有约 200 亿个晶体管'
},
{
name: '逻辑门',
icon: '🔌',
count: '数亿个',
desc: '由多个晶体管组成,实现基本逻辑运算(AND、OR、NOT等)。',
example: '一个 AND 门需要 2-6 个晶体管'
},
{
name: '功能单元',
icon: '🔧',
count: '数百个',
desc: '由逻辑门组成,实现特定功能:加法器、多路选择器、寄存器等。',
example: '一个 64 位加法器需要约 1000 个逻辑门'
},
{
name: 'CPU 核心',
icon: '🧠',
count: '1-128个',
desc: '包含完整的运算和控制能力,能独立执行指令流。',
example: 'Intel i9-13900K 有 24 核心'
}
]
const components = [
{ icon: '📊', name: 'ALU', desc: '算术逻辑单元,做加减乘除和逻辑运算' },
{ icon: '📁', name: '寄存器', desc: '超高速存储,存放正在处理的数据' },
{ icon: '🎮', name: '控制器', desc: '指挥官,解码指令并协调各部件' },
{ icon: '🚌', name: '总线', desc: '数据高速公路,连接各部件' }
]
</script>
<style scoped>
.cpu-arch-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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; }
.architecture-layers {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.layer {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
padding: 0.5rem 0.75rem;
cursor: pointer;
transition: all 0.2s;
}
.layer:hover {
border-color: var(--vp-c-brand);
}
.layer.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.layer-header {
display: flex;
align-items: center;
gap: 0.5rem;
}
.layer-icon {
font-size: 1rem;
}
.layer-name {
font-weight: bold;
font-size: 0.9rem;
}
.layer-count {
margin-left: auto;
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.layer-detail {
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--vp-c-divider);
}
.detail-desc {
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.detail-example {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.example-label {
font-weight: bold;
}
.cpu-components {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.comp-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.comp-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
}
.comp-item {
display: flex;
flex-direction: column;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 4px;
}
.comp-icon {
font-size: 1rem;
margin-bottom: 0.25rem;
}
.comp-name {
font-weight: bold;
font-size: 0.85rem;
}
.comp-desc {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,529 @@
<template>
<div class="data-structure-demo">
<div class="demo-header">
<span class="icon">📦</span>
<span class="title">数据结构数据的"容器"</span>
<span class="subtitle">不同场景选择不同的存储方式</span>
</div>
<div class="demo-content">
<div class="structure-tabs">
<button
v-for="s in structures"
:key="s.name"
:class="['tab-btn', { active: activeStructure === s.name }]"
@click="activeStructure = s.name"
>{{ s.name }}</button>
</div>
<div class="structure-visual">
<div class="visual-header">
<span class="structure-name">{{ currentStructure.name }}</span>
<span class="structure-desc">{{ currentStructure.desc }}</span>
</div>
<div class="visual-content">
<div v-if="activeStructure === '数组'" class="array-visual">
<div class="array-container">
<div v-for="(item, i) in arrayData" :key="i" class="array-item">
<span class="index">{{ i }}</span>
<span class="value">{{ item }}</span>
</div>
</div>
<div class="operation-hint">访问 arr[2] = O(1)插入/删除 = O(n)</div>
</div>
<div v-else-if="activeStructure === '链表'" class="linked-visual">
<div class="linked-container">
<div v-for="(item, i) in linkedData" :key="i" class="linked-node">
<span class="node-value">{{ item.value }}</span>
<span class="node-arrow" v-if="i < linkedData.length - 1"></span>
</div>
</div>
<div class="operation-hint">访问第 n = O(n)插入/删除 = O(1)</div>
</div>
<div v-else-if="activeStructure === '栈'" class="stack-visual">
<div class="stack-container">
<div v-for="(item, i) in stackData" :key="i" class="stack-item">
{{ item }}
</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)</div>
</div>
<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">
{{ 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)</div>
</div>
<div v-else-if="activeStructure === '哈希表'" class="hash-visual">
<div class="hash-container">
<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>
</div>
</div>
</div>
<div class="operation-hint">查找/插入/删除平均 O(1)最坏 O(n)</div>
</div>
<div v-else-if="activeStructure === '树'" class="tree-visual">
<div class="tree-container">
<div class="tree-level">
<div class="tree-node root">{{ treeData.value }}</div>
</div>
<div class="tree-level">
<div class="tree-node">{{ treeData.left?.value }}</div>
<div class="tree-node">{{ treeData.right?.value }}</div>
</div>
<div class="tree-level">
<div class="tree-node leaf">{{ treeData.left?.left?.value }}</div>
<div class="tree-node leaf">{{ treeData.left?.right?.value }}</div>
<div class="tree-node leaf">{{ treeData.right?.left?.value }}</div>
<div class="tree-node leaf">{{ treeData.right?.right?.value }}</div>
</div>
</div>
<div class="operation-hint">查找/插入/删除 O(log n)遍历 O(n)</div>
</div>
</div>
</div>
<div class="complexity-table">
<div class="table-title">时间复杂度对比</div>
<table>
<thead>
<tr>
<th>操作</th>
<th>数组</th>
<th>链表</th>
<th>哈希表</th>
<th></th>
</tr>
</thead>
<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>
</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>
</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>
</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>
</tr>
</tbody>
</table>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>数据结构是数据的"容器"不同的容器有不同的特点选择合适的数据结构能让程序效率提升几个数量级
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeStructure = ref('数组')
const structures = [
{ name: '数组', desc: '连续内存,索引访问快' },
{ name: '链表', desc: '节点相连,插入删除快' },
{ name: '栈', desc: '后进先出,函数调用用' },
{ name: '队列', desc: '先进先出,任务调度用' },
{ name: '哈希表', desc: '键值对,查找最快' },
{ name: '树', desc: '层次结构,排序搜索' }
]
const currentStructure = computed(() => {
return structures.find(s => s.name === activeStructure.value)
})
const arrayData = ref([10, 20, 30, 40, 50, 60, 70, 80])
const linkedData = ref([
{ value: 10 },
{ value: 20 },
{ value: 30 },
{ value: 40 },
{ value: 50 }
])
const stackData = ref(['A', 'B', 'C'])
const stackCounter = ref(68)
const pushStack = () => {
stackCounter.value++
stackData.value.push(String.fromCharCode(stackCounter.value))
}
const popStack = () => {
if (stackData.value.length > 0) {
stackData.value.pop()
}
}
const queueData = ref(['任务1', '任务2', '任务3'])
const queueCounter = ref(3)
const enqueue = () => {
queueCounter.value++
queueData.value.push(`任务${queueCounter.value}`)
}
const dequeue = () => {
if (queueData.value.length > 0) {
queueData.value.shift()
}
}
const hashData = ref([
['apple', 'ant'],
['banana'],
[],
['cat', 'car', 'cup'],
['dog'],
[],
['egg', 'eye']
])
const treeData = ref({
value: 50,
left: {
value: 30,
left: { value: 20 },
right: { value: 40 }
},
right: {
value: 70,
left: { value: 60 },
right: { value: 80 }
}
})
</script>
<style scoped>
.data-structure-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
flex-wrap: wrap;
gap: 0.25rem;
margin-bottom: 1rem;
}
.tab-btn {
padding: 0.35rem 0.6rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.structure-visual {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.visual-header {
margin-bottom: 0.75rem;
}
.structure-name {
font-weight: bold;
font-size: 1rem;
}
.structure-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-left: 0.5rem;
}
.visual-content {
min-height: 120px;
}
.array-container {
display: flex;
gap: 2px;
}
.array-item {
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid var(--vp-c-divider);
padding: 0.25rem 0.5rem;
background: var(--vp-c-bg-alt);
}
.index {
font-size: 0.65rem;
color: var(--vp-c-text-3);
}
.value {
font-weight: bold;
font-size: 0.9rem;
}
.linked-container {
display: flex;
align-items: center;
gap: 0;
}
.linked-node {
display: flex;
align-items: center;
}
.node-value {
padding: 0.5rem 0.75rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-weight: bold;
}
.node-arrow {
margin: 0 0.25rem;
color: var(--vp-c-brand);
}
.stack-container {
display: flex;
flex-direction: column-reverse;
align-items: center;
gap: 2px;
}
.stack-item {
padding: 0.5rem 1.5rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-weight: bold;
}
.stack-bottom {
font-size: 0.75rem;
color: var(--vp-c-text-3);
margin-top: 0.25rem;
}
.stack-ops, .queue-ops {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
justify-content: center;
}
.op-btn {
padding: 0.35rem 0.75rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
}
.queue-container {
display: flex;
align-items: center;
gap: 0.25rem;
}
.queue-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.queue-item {
padding: 0.5rem 0.75rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-weight: bold;
}
.hash-container {
display: flex;
flex-direction: column;
gap: 2px;
}
.hash-bucket {
display: flex;
align-items: center;
gap: 0.5rem;
}
.bucket-index {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-bg-alt);
border-radius: 4px;
font-size: 0.75rem;
font-weight: bold;
}
.bucket-items {
display: flex;
gap: 0.25rem;
}
.bucket-item {
padding: 0.25rem 0.5rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-size: 0.8rem;
}
.tree-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.tree-level {
display: flex;
gap: 0.5rem;
}
.tree-node {
padding: 0.5rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-weight: bold;
min-width: 40px;
text-align: center;
}
.tree-node.root {
background: var(--vp-c-brand);
color: white;
}
.tree-node.leaf {
background: var(--vp-c-bg-alt);
}
.operation-hint {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-top: 0.5rem;
text-align: center;
}
.complexity-table {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.table-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.8rem;
}
th, td {
border: 1px solid var(--vp-c-divider);
padding: 0.35rem;
text-align: center;
}
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); }
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,265 @@
<template>
<div class="encoding-demo">
<div class="demo-header">
<span class="icon">🔢</span>
<span class="title">数字编码 0 1 表示一切</span>
<span class="subtitle">字符数字图像如何变成二进制</span>
</div>
<div class="demo-content">
<div class="encoding-tabs">
<button
v-for="tab in tabs"
:key="tab.name"
:class="['tab-btn', { active: activeTab === tab.name }]"
@click="activeTab = tab.name"
>{{ tab.label }}</button>
</div>
<div class="encoding-area">
<div class="input-section">
<label>输入内容</label>
<input
v-model="inputValue"
class="input-field"
:placeholder="currentTab.placeholder"
/>
</div>
<div class="output-section">
<div class="output-label">编码结果</div>
<div class="output-box">
<code>{{ encodedResult }}</code>
</div>
<div class="output-info" v-if="currentTab.name === 'text'">
<span>字符数: {{ inputValue.length }}</span>
<span>字节数: {{ byteCount }}</span>
</div>
</div>
<div class="encoding-table" v-if="currentTab.name === 'text' && inputValue">
<div class="table-title">字符编码详情</div>
<div class="char-list">
<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>
</div>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>所有数据最终都要变成 0 1不同类型的数据用不同的编码规则字符用 ASCII/Unicode数字用二进制图像用像素值
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeTab = ref('text')
const inputValue = ref('Hello')
const tabs = [
{ name: 'text', label: '文本编码' },
{ name: 'number', label: '数字编码' },
{ name: 'color', label: '颜色编码' }
]
const currentTab = computed(() => {
const tab = tabs.find(t => t.name === activeTab.value)
return {
...tab,
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'))
.join(' ')
case 'number':
const num = parseInt(inputValue.value)
if (isNaN(num)) return '请输入有效数字'
return num.toString(2)
case 'color':
const hex = inputValue.value.replace('#', '')
if (!/^[0-9A-Fa-f]{6}$/.test(hex)) return '请输入有效的颜色值(如 #FF5733)'
const r = parseInt(hex.slice(0, 2), 16)
const g = parseInt(hex.slice(2, 4), 16)
const b = parseInt(hex.slice(4, 6), 16)
return `R: ${r.toString(2).padStart(8, '0')} G: ${g.toString(2).padStart(8, '0')} B: ${b.toString(2).padStart(8, '0')}`
default:
return ''
}
})
const byteCount = computed(() => {
return new Blob([inputValue.value]).size
})
</script>
<style scoped>
.encoding-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 0.5rem;
margin-bottom: 1rem;
}
.tab-btn {
padding: 0.4rem 0.8rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.encoding-area {
display: flex;
flex-direction: column;
gap: 1rem;
}
.input-section {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.input-section label {
font-size: 0.85rem;
font-weight: bold;
}
.input-field {
padding: 0.5rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
background: var(--vp-c-bg);
font-size: 1rem;
}
.output-section {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.output-label {
font-size: 0.85rem;
font-weight: bold;
margin-bottom: 0.5rem;
}
.output-box {
background: var(--vp-c-bg-alt);
padding: 0.5rem;
border-radius: 4px;
font-family: monospace;
font-size: 0.85rem;
word-break: break-all;
}
.output-info {
display: flex;
gap: 1rem;
margin-top: 0.5rem;
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.encoding-table {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.table-title {
font-size: 0.85rem;
font-weight: bold;
margin-bottom: 0.5rem;
}
.char-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.char-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 4px;
min-width: 80px;
}
.char-display {
font-size: 1.2rem;
font-weight: bold;
}
.char-unicode {
font-size: 0.7rem;
color: var(--vp-c-brand);
}
.char-binary {
font-size: 0.65rem;
font-family: monospace;
color: var(--vp-c-text-2);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,292 @@
<template>
<div class="filesystem-demo">
<div class="demo-header">
<span class="icon">📁</span>
<span class="title">文件系统数据的"档案柜"</span>
<span class="subtitle">操作系统如何组织和管理文件</span>
</div>
<div class="demo-content">
<div class="fs-tree">
<div class="tree-header">
<span class="header-icon">📂</span>
<span>目录结构</span>
</div>
<div class="tree-content">
<div
v-for="item in fileTree"
:key="item.path"
class="tree-item"
:class="{ selected: selectedItem === item.path }"
:style="{ paddingLeft: (item.level * 12) + 'px' }"
@click="selectItem(item)"
>
<span class="item-icon">{{ item.icon }}</span>
<span class="item-name">{{ item.name }}</span>
</div>
</div>
</div>
<div class="fs-detail">
<div class="detail-header">
<span class="detail-icon">{{ selectedItemInfo?.icon }}</span>
<span class="detail-name">{{ selectedItemInfo?.name }}</span>
</div>
<div class="detail-info" v-if="selectedItemInfo">
<div class="info-row">
<span class="info-label">类型</span>
<span class="info-value">{{ selectedItemInfo.type }}</span>
</div>
<div class="info-row">
<span class="info-label">路径</span>
<span class="info-value">{{ selectedItemInfo.path }}</span>
</div>
<div class="info-row" v-if="selectedItemInfo.type === '文件'">
<span class="info-label">大小</span>
<span class="info-value">{{ selectedItemInfo.size }}</span>
</div>
<div class="info-row">
<span class="info-label">权限</span>
<span class="info-value">{{ selectedItemInfo.permission }}</span>
</div>
</div>
<div class="inode-info" v-if="selectedItemInfo?.type === '文件'">
<div class="inode-title">inode 信息</div>
<div class="inode-visual">
<div class="inode-block">
<span class="inode-label">inode 编号</span>
<span class="inode-value">{{ selectedItemInfo.inode }}</span>
</div>
<div class="inode-block">
<span class="inode-label">数据块</span>
<div class="data-blocks">
<span v-for="b in selectedItemInfo.blocks" :key="b" class="block">{{ b }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>文件系统用"目录树"组织文件"inode"记录文件元数据文件名只是给人看的系统通过 inode 编号找到真正的数据
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const selectedItem = ref('/home')
const fileTree = ref([
{ name: '/', path: '/', icon: '📁', level: 0, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'home', path: '/home', icon: '📁', level: 1, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'user', path: '/home/user', icon: '📁', level: 2, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'documents', path: '/home/user/documents', icon: '📁', level: 3, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'report.pdf', path: '/home/user/documents/report.pdf', icon: '📄', level: 4, type: '文件', size: '2.5MB', permission: 'rw-r--r--', inode: 12345, blocks: ['块1', '块2', '块3'] },
{ name: 'photos', path: '/home/user/photos', icon: '📁', level: 3, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'vacation.jpg', path: '/home/user/photos/vacation.jpg', icon: '🖼️', level: 4, type: '文件', size: '4.2MB', permission: 'rw-r--r--', inode: 12346, blocks: ['块4', '块5', '块6', '块7'] },
{ name: 'etc', path: '/etc', icon: '📁', level: 1, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'config.yml', path: '/etc/config.yml', icon: '⚙️', level: 2, type: '文件', size: '1.2KB', permission: 'rw-r--r--', inode: 10001, blocks: ['块8'] },
{ name: 'var', path: '/var', icon: '📁', level: 1, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'log', path: '/var/log', icon: '📁', level: 2, type: '目录', permission: 'rwxr-xr-x' },
{ name: 'system.log', path: '/var/log/system.log', icon: '📝', level: 3, type: '文件', size: '128MB', permission: 'rw-r-----', inode: 20001, blocks: ['块9', '块10', '...'] }
])
const selectedItemInfo = computed(() => {
return fileTree.value.find(item => item.path === selectedItem.value)
})
const selectItem = (item) => {
selectedItem.value = item.path
}
</script>
<style scoped>
.filesystem-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 1rem;
flex-wrap: wrap;
}
.fs-tree {
flex: 1;
min-width: 250px;
background: var(--vp-c-bg);
border-radius: 6px;
overflow: hidden;
}
.tree-header {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: var(--vp-c-bg-alt);
font-weight: bold;
font-size: 0.85rem;
}
.tree-content {
max-height: 280px;
overflow-y: auto;
}
.tree-item {
display: flex;
align-items: center;
gap: 0.25rem;
padding: 0.35rem 0.5rem;
cursor: pointer;
transition: all 0.2s;
font-size: 0.85rem;
}
.tree-item:hover {
background: var(--vp-c-bg-soft);
}
.tree-item.selected {
background: var(--vp-c-brand-soft);
}
.item-icon {
font-size: 0.9rem;
}
.fs-detail {
flex: 1;
min-width: 250px;
}
.detail-header {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
margin-bottom: 0.75rem;
}
.detail-icon {
font-size: 1.5rem;
}
.detail-name {
font-weight: bold;
font-size: 1rem;
}
.detail-info {
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 4px;
margin-bottom: 0.75rem;
}
.info-row {
display: flex;
justify-content: space-between;
padding: 0.25rem 0;
font-size: 0.85rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
color: var(--vp-c-text-2);
}
.info-value {
font-weight: 500;
}
.inode-info {
background: var(--vp-c-bg-alt);
padding: 0.5rem;
border-radius: 4px;
}
.inode-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.inode-visual {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.inode-block {
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 4px;
}
.inode-label {
display: block;
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.25rem;
}
.inode-value {
font-weight: bold;
font-size: 0.9rem;
}
.data-blocks {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
}
.block {
padding: 0.15rem 0.4rem;
background: var(--vp-c-brand-soft);
border-radius: 3px;
font-size: 0.75rem;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,404 @@
<template>
<div class="language-map-demo">
<div class="demo-header">
<span class="icon">🗺</span>
<span class="title">编程语言图谱语言的演化</span>
<span class="subtitle">从机器语言到现代语言</span>
</div>
<div class="demo-content">
<div class="timeline">
<div class="timeline-item" v-for="(era, i) in eras" :key="i">
<div class="era-year">{{ era.year }}</div>
<div class="era-content">
<div class="era-name">{{ era.name }}</div>
<div class="era-langs">{{ era.languages.join(' → ') }}</div>
<div class="era-desc">{{ era.desc }}</div>
</div>
</div>
</div>
<div class="paradigm-section">
<div class="section-title">编程范式</div>
<div class="paradigm-tabs">
<button
v-for="p in paradigms"
:key="p.name"
:class="['tab-btn', { active: activeParadigm === p.name }]"
@click="activeParadigm = p.name"
>{{ p.name }}</button>
</div>
<div class="paradigm-content" v-if="currentParadigm">
<div class="paradigm-desc">{{ currentParadigm.desc }}</div>
<div class="paradigm-langs">
<span class="label">代表语言</span>
<span v-for="lang in currentParadigm.languages" :key="lang" class="lang-tag">{{ lang }}</span>
</div>
<div class="paradigm-example">
<div class="example-label">代码示例</div>
<pre><code>{{ currentParadigm.example }}</code></pre>
</div>
</div>
</div>
<div class="type-section">
<div class="section-title">类型系统分类</div>
<div class="type-grid">
<div class="type-card" v-for="t in typeCategories" :key="t.name">
<div class="card-header">
<span class="card-name">{{ t.name }}</span>
<span class="card-type">{{ t.type }}</span>
</div>
<div class="card-desc">{{ t.desc }}</div>
<div class="card-examples">{{ t.examples.join(', ') }}</div>
</div>
</div>
</div>
<div class="comparison-table">
<div class="table-title">语言特性对比</div>
<table>
<thead>
<tr>
<th>语言</th>
<th>类型</th>
<th>范式</th>
<th>运行方式</th>
<th>主要用途</th>
</tr>
</thead>
<tbody>
<tr v-for="lang in languageComparison" :key="lang.name">
<td class="lang-name">{{ lang.name }}</td>
<td>{{ lang.type }}</td>
<td>{{ lang.paradigm }}</td>
<td>{{ lang.runtime }}</td>
<td>{{ lang.usage }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>编程语言是人类与计算机沟通的桥梁不同的语言有不同的设计哲学适合解决不同类型的问题选择语言时要考虑问题领域团队熟悉度生态系统等因素
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const eras = [
{ year: '1950s', name: '早期语言', languages: ['Fortran', 'Lisp', 'COBOL'], desc: '科学计算和商业应用' },
{ year: '1960s', name: '结构化编程', languages: ['ALGOL', 'BASIC', 'PL/I'], desc: '引入结构化控制流' },
{ year: '1970s', name: '系统编程', languages: ['C', 'Pascal', 'Smalltalk'], desc: '面向对象和系统级开发' },
{ year: '1980s', name: '面向对象', languages: ['C++', 'Objective-C', 'Perl'], desc: 'OOP 成为主流' },
{ year: '1990s', name: '互联网时代', languages: ['Java', 'JavaScript', 'Python', 'PHP'], desc: 'Web 开发驱动语言发展' },
{ year: '2000s', name: '现代语言', languages: ['C#', 'Ruby', 'Scala', 'Go'], desc: '注重开发效率和安全性' },
{ year: '2010s', name: '新一代语言', languages: ['Rust', 'Swift', 'Kotlin', 'TypeScript'], desc: '内存安全与类型系统' }
]
const activeParadigm = ref('命令式')
const paradigms = [
{
name: '命令式',
desc: '通过语句改变程序状态,描述"怎么做"',
languages: ['C', 'Fortran', 'BASIC'],
example: `// 计算数组总和
int sum = 0;
for (int i = 0; i < n; i++) {
sum += arr[i];
}`
},
{
name: '面向对象',
desc: '将数据和操作封装在对象中,模拟现实世界',
languages: ['Java', 'C++', 'Python', 'Ruby'],
example: `class Dog {
constructor(name) {
this.name = name
}
bark() {
console.log(this.name + ' says woof!')
}
}`
},
{
name: '函数式',
desc: '将计算视为函数求值,避免状态变化',
languages: ['Haskell', 'Lisp', 'Erlang', 'F#'],
example: `-- 计算数组总和
sum arr = foldl (+) 0 arr
-- 或更简洁
sum = foldl (+) 0`
},
{
name: '声明式',
desc: '描述"做什么"而非"怎么做"',
languages: ['SQL', 'Prolog', 'HTML'],
example: `-- 查询所有用户
SELECT name, email
FROM users
WHERE active = true
ORDER BY created_at DESC`
}
]
const currentParadigm = computed(() => {
return paradigms.find(p => p.name === activeParadigm.value)
})
const typeCategories = [
{ name: '静态类型', type: '编译时检查', desc: '变量类型在编译时确定', examples: ['Java', 'C++', 'Rust', 'TypeScript'] },
{ name: '动态类型', type: '运行时检查', desc: '变量类型在运行时确定', examples: ['Python', 'JavaScript', 'Ruby', 'PHP'] },
{ name: '强类型', type: '严格检查', desc: '不允许隐式类型转换', examples: ['Python', 'Java', 'Rust', 'Haskell'] },
{ name: '弱类型', type: '宽松检查', desc: '允许隐式类型转换', examples: ['JavaScript', 'PHP', 'C'] }
]
const languageComparison = [
{ name: 'Python', type: '动态强类型', paradigm: '多范式', runtime: '解释执行', usage: 'AI、数据分析、Web' },
{ name: 'JavaScript', type: '动态弱类型', paradigm: '多范式', runtime: 'JIT 编译', usage: 'Web 前端、Node.js' },
{ name: 'Java', type: '静态强类型', paradigm: '面向对象', runtime: 'JVM', usage: '企业应用、Android' },
{ name: 'C++', type: '静态弱类型', paradigm: '多范式', runtime: '编译执行', usage: '系统、游戏、嵌入式' },
{ name: 'Rust', type: '静态强类型', paradigm: '多范式', runtime: '编译执行', usage: '系统、WebAssembly' },
{ name: 'Go', type: '静态强类型', paradigm: '并发导向', runtime: '编译执行', usage: '云原生、微服务' }
]
</script>
<style scoped>
.language-map-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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; }
.timeline {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.timeline-item {
display: flex;
gap: 0.75rem;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.era-year {
font-weight: bold;
font-size: 0.85rem;
color: var(--vp-c-brand);
min-width: 60px;
}
.era-name {
font-weight: bold;
font-size: 0.85rem;
}
.era-langs {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.era-desc {
font-size: 0.75rem;
color: var(--vp-c-text-3);
}
.section-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.paradigm-section {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.paradigm-tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 0.75rem;
flex-wrap: wrap;
}
.tab-btn {
padding: 0.35rem 0.6rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-alt);
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.paradigm-desc {
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.paradigm-langs {
display: flex;
align-items: center;
gap: 0.25rem;
flex-wrap: wrap;
margin-bottom: 0.5rem;
}
.label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.lang-tag {
padding: 0.15rem 0.4rem;
background: var(--vp-c-brand-soft);
border-radius: 3px;
font-size: 0.75rem;
}
.paradigm-example {
background: var(--vp-c-bg-alt);
border-radius: 4px;
overflow: hidden;
}
.example-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
padding: 0.25rem 0.5rem;
background: var(--vp-c-divider);
}
pre {
margin: 0;
padding: 0.5rem;
font-size: 0.75rem;
overflow-x: auto;
}
code {
font-family: monospace;
}
.type-section {
margin-bottom: 1rem;
}
.type-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.5rem;
}
.type-card {
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 6px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.25rem;
}
.card-name {
font-weight: bold;
font-size: 0.85rem;
}
.card-type {
font-size: 0.7rem;
color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
padding: 0.1rem 0.3rem;
border-radius: 3px;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.25rem;
}
.card-examples {
font-size: 0.75rem;
color: var(--vp-c-text-3);
}
.comparison-table {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.table-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.8rem;
}
th, td {
border: 1px solid var(--vp-c-divider);
padding: 0.35rem;
text-align: left;
}
th {
background: var(--vp-c-bg);
}
.lang-name {
font-weight: bold;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,374 @@
<template>
<div class="logic-gate-demo">
<div class="demo-header">
<span class="icon">🔌</span>
<span class="title">逻辑门用开关做运算</span>
<span class="subtitle">晶体管组合成基本运算单元</span>
</div>
<div class="demo-content">
<div class="gate-tabs">
<button
v-for="gate in gates"
:key="gate.name"
:class="['tab-btn', { active: activeGate === gate.name }]"
@click="activeGate = gate.name"
>
{{ gate.name }}
</button>
</div>
<div class="gate-display">
<div class="gate-visual">
<div class="inputs">
<div class="input-item">
<span>A:</span>
<button
class="input-btn"
:class="{ on: inputA }"
@click="inputA = !inputA"
>{{ inputA ? '1' : '0' }}</button>
</div>
<div class="input-item">
<span>B:</span>
<button
class="input-btn"
:class="{ on: inputB }"
@click="inputB = !inputB"
>{{ inputB ? '1' : '0' }}</button>
</div>
</div>
<div class="gate-symbol">
<svg viewBox="0 0 120 80" class="gate-svg">
<template v-if="activeGate === 'AND'">
<path d="M20,20 L20,60 L60,60 Q90,60 90,40 Q90,20 60,20 Z" fill="none" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="90" y1="40" x2="110" y2="40" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="30" x2="20" y2="30" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="50" x2="20" y2="50" stroke="var(--vp-c-brand)" stroke-width="2"/>
</template>
<template v-else-if="activeGate === 'OR'">
<path d="M20,20 Q40,40 20,60 Q60,60 90,40 Q60,20 20,20" fill="none" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="90" y1="40" x2="110" y2="40" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="30" x2="25" y2="30" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="50" x2="25" y2="50" stroke="var(--vp-c-brand)" stroke-width="2"/>
</template>
<template v-else-if="activeGate === 'NOT'">
<polygon points="20,20 80,40 20,60" fill="none" stroke="var(--vp-c-brand)" stroke-width="2"/>
<circle cx="85" cy="40" r="5" fill="none" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="90" y1="40" x2="110" y2="40" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="40" x2="20" y2="40" stroke="var(--vp-c-brand)" stroke-width="2"/>
</template>
<template v-else-if="activeGate === 'XOR'">
<path d="M25,20 Q45,40 25,60 Q65,60 95,40 Q65,20 25,20" fill="none" stroke="var(--vp-c-brand)" stroke-width="2"/>
<path d="M15,20 Q35,40 15,60" fill="none" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="95" y1="40" x2="115" y2="40" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="30" x2="30" y2="30" stroke="var(--vp-c-brand)" stroke-width="2"/>
<line x1="0" y1="50" x2="30" y2="50" stroke="var(--vp-c-brand)" stroke-width="2"/>
</template>
</svg>
<div class="gate-name">{{ activeGate }}</div>
</div>
<div class="output">
<span class="output-label">输出:</span>
<span class="output-value" :class="{ on: output }">{{ output ? '1' : '0' }}</span>
</div>
</div>
<div class="truth-table-mini">
<div class="table-title">{{ activeGate }} 真值表</div>
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>输出</th>
</tr>
</thead>
<tbody>
<tr v-for="row in currentTruthTable" :key="row.a + '-' + row.b"
:class="{ highlight: row.a === inputA && row.b === inputB && (activeGate !== 'NOT') }">
<td>{{ row.a }}</td>
<td>{{ row.b }}</td>
<td>{{ row.out }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="gate-explanation">
<div class="exp-title">{{ currentGate.expTitle }}</div>
<div class="exp-content">{{ currentGate.expContent }}</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>逻辑门用晶体管的"开关"组合实现基本运算AND门像"串联开关"(两个都开才通)OR门像"并联开关"(任一个开就通)
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeGate = ref('AND')
const inputA = ref(false)
const inputB = ref(false)
const gates = [
{
name: 'AND',
expTitle: 'AND门:两个都为1才输出1',
expContent: '就像串联的两个开关,必须两个都按下灯才会亮。用于"同时满足多个条件"的场景。'
},
{
name: 'OR',
expTitle: 'OR门:任一个为1就输出1',
expContent: '就像并联的两个开关,按任意一个灯就会亮。用于"满足任一条件"的场景。'
},
{
name: 'NOT',
expTitle: 'NOT门:取反,0变11变0',
expContent: '就像一个反相器,输入开就输出关,输入关就输出开。用于"否定"的场景。'
},
{
name: 'XOR',
expTitle: 'XOR门:相同为0,不同为1',
expContent: '就像"异或"判断,两个输入不同才输出1。用于比较两个值是否不同。'
}
]
const currentGate = computed(() => gates.find(g => g.name === activeGate.value))
const output = computed(() => {
const a = inputA.value
const b = inputB.value
switch (activeGate.value) {
case 'AND': return a && b ? 1 : 0
case 'OR': return a || b ? 1 : 0
case 'NOT': return a ? 0 : 1
case 'XOR': return a !== b ? 1 : 0
default: return 0
}
})
const currentTruthTable = computed(() => {
if (activeGate.value === 'NOT') {
return [
{ a: 0, b: '-', out: 1 },
{ a: 1, b: '-', out: 0 }
]
}
const table = []
for (let a = 0; a <= 1; a++) {
for (let b = 0; b <= 1; b++) {
let out = 0
switch (activeGate.value) {
case 'AND': out = a && b ? 1 : 0; break
case 'OR': out = a || b ? 1 : 0; break
case 'XOR': out = a !== b ? 1 : 0; break
}
table.push({ a, b, out })
}
}
return table
})
</script>
<style scoped>
.logic-gate-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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; }
.gate-tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
.tab-btn {
padding: 0.4rem 0.8rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
transition: all 0.2s;
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.gate-display {
display: flex;
gap: 1.5rem;
align-items: flex-start;
flex-wrap: wrap;
}
.gate-visual {
display: flex;
align-items: center;
gap: 1rem;
}
.inputs {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.input-item {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
}
.input-btn {
width: 36px;
height: 36px;
border: 2px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
font-weight: bold;
transition: all 0.2s;
}
.input-btn.on {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.gate-symbol {
width: 120px;
text-align: center;
}
.gate-svg {
width: 100%;
height: 60px;
}
.gate-name {
font-weight: bold;
font-size: 0.9rem;
margin-top: 0.25rem;
color: var(--vp-c-brand);
}
.output {
display: flex;
align-items: center;
gap: 0.5rem;
}
.output-label {
font-size: 0.85rem;
}
.output-value {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
font-weight: bold;
font-size: 1.1rem;
}
.output-value.on {
background: var(--vp-c-success);
color: white;
border-color: var(--vp-c-success);
}
.truth-table-mini {
flex: 1;
min-width: 150px;
}
.table-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.8rem;
}
th, td {
border: 1px solid var(--vp-c-divider);
padding: 0.3rem 0.5rem;
text-align: center;
}
th {
background: var(--vp-c-bg-alt);
}
tr.highlight {
background: var(--vp-c-brand-soft);
}
.gate-explanation {
width: 100%;
margin-top: 1rem;
padding: 0.75rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
}
.exp-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.exp-content {
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,282 @@
<template>
<div class="memory-demo">
<div class="demo-header">
<span class="icon">🧠</span>
<span class="title">内存管理程序的"工作台"</span>
<span class="subtitle">操作系统如何分配和管理内存</span>
</div>
<div class="demo-content">
<div class="memory-visual">
<div class="mem-header">
<span>虚拟内存空间 (4GB)</span>
<span class="used-info">已用: {{ usedMemory }}MB / 4096MB</span>
</div>
<div class="mem-blocks">
<div
v-for="(block, i) in memoryBlocks"
:key="i"
class="mem-block"
:class="{ allocated: block.allocated, selected: selectedBlock === i }"
:style="{ height: block.size + '%' }"
@click="selectedBlock = i"
>
<span class="block-label" v-if="block.size > 5">{{ block.name }}</span>
<span class="block-size" v-if="block.size > 8">{{ block.sizeMB }}MB</span>
</div>
</div>
</div>
<div class="memory-info">
<div class="info-section">
<div class="section-title">内存分配策略</div>
<div class="strategy-tabs">
<button
v-for="s in strategies"
:key="s.name"
:class="['strat-btn', { active: activeStrategy === s.name }]"
@click="activeStrategy = s.name"
>{{ s.name }}</button>
</div>
<div class="strategy-desc">{{ currentStrategy.desc }}</div>
</div>
<div class="info-section">
<div class="section-title">虚拟内存的作用</div>
<div class="vm-benefits">
<div class="benefit-item" v-for="b in benefits" :key="b.title">
<span class="benefit-icon">{{ b.icon }}</span>
<div class="benefit-content">
<span class="benefit-title">{{ b.title }}</span>
<span class="benefit-desc">{{ b.desc }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>虚拟内存让每个进程都以为自己独占整个内存空间实际由操作系统统一管理和映射实现隔离和保护
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const selectedBlock = ref(0)
const activeStrategy = ref('首次适应')
const memoryBlocks = ref([
{ name: '内核空间', size: 25, allocated: true, sizeMB: 1024 },
{ name: '进程A', size: 15, allocated: true, sizeMB: 600 },
{ name: '空闲', size: 5, allocated: false, sizeMB: 200 },
{ name: '进程B', size: 20, allocated: true, sizeMB: 800 },
{ name: '空闲', size: 10, allocated: false, sizeMB: 400 },
{ name: '进程C', size: 10, allocated: true, sizeMB: 400 },
{ name: '空闲', size: 15, allocated: false, sizeMB: 600 }
])
const strategies = [
{ name: '首次适应', desc: '从内存开始找,找到第一个足够大的空闲块就分配。速度快,但可能产生小碎片。' },
{ name: '最佳适应', desc: '找最小的能满足需求的空闲块。内存利用率高,但可能产生很多小碎片。' },
{ name: '最坏适应', desc: '找最大的空闲块分配。减少小碎片,但大块内存很快用完。' }
]
const benefits = [
{ icon: '🔒', title: '内存隔离', desc: '进程间互不干扰,一个崩溃不影响其他' },
{ icon: '📦', title: '内存保护', desc: '防止进程访问不该访问的内存区域' },
{ icon: '💾', title: '内存扩展', desc: '用磁盘当内存用,突破物理内存限制' }
]
const currentStrategy = computed(() => {
return strategies.find(s => s.name === activeStrategy.value)
})
const usedMemory = computed(() => {
return memoryBlocks.value
.filter(b => b.allocated)
.reduce((sum, b) => sum + b.sizeMB, 0)
})
</script>
<style scoped>
.memory-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 1rem;
flex-wrap: wrap;
}
.memory-visual {
flex: 1;
min-width: 200px;
}
.mem-header {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
margin-bottom: 0.5rem;
padding: 0.25rem 0.5rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
}
.used-info {
color: var(--vp-c-brand);
font-weight: bold;
}
.mem-blocks {
display: flex;
flex-direction: column;
gap: 2px;
height: 250px;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
overflow: hidden;
}
.mem-block {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
}
.mem-block.allocated {
background: var(--vp-c-brand-soft);
}
.mem-block:not(.allocated) {
background: var(--vp-c-bg);
border: 1px dashed var(--vp-c-divider);
}
.mem-block.selected {
outline: 2px solid var(--vp-c-brand);
}
.block-label {
font-size: 0.75rem;
font-weight: bold;
}
.block-size {
font-size: 0.65rem;
color: var(--vp-c-text-2);
}
.memory-info {
flex: 1;
min-width: 280px;
}
.info-section {
margin-bottom: 1rem;
}
.section-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.strategy-tabs {
display: flex;
gap: 0.25rem;
margin-bottom: 0.5rem;
}
.strat-btn {
padding: 0.25rem 0.5rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
font-size: 0.75rem;
cursor: pointer;
}
.strat-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.strategy-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 4px;
}
.vm-benefits {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.benefit-item {
display: flex;
gap: 0.5rem;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 4px;
}
.benefit-icon {
font-size: 1.2rem;
}
.benefit-content {
display: flex;
flex-direction: column;
}
.benefit-title {
font-weight: bold;
font-size: 0.85rem;
}
.benefit-desc {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,361 @@
<template>
<div class="network-layers-demo">
<div class="demo-header">
<span class="icon">🌐</span>
<span class="title">网络五层模型</span>
<span class="subtitle">从应用到物理的数据封装过程</span>
</div>
<div class="demo-content">
<div class="layers-container">
<div
v-for="(layer, i) in layers"
:key="i"
:class="['layer', { active: activeLayer === i }]"
@click="activeLayer = i"
>
<div class="layer-num">{{ 5 - i }}</div>
<div class="layer-info">
<div class="layer-name">{{ layer.name }}</div>
<div class="layer-protocol">{{ layer.protocols }}</div>
</div>
<div class="layer-device" v-if="layer.device">{{ layer.device }}</div>
</div>
</div>
<div class="layer-detail" v-if="currentLayer">
<div class="detail-header">
<span class="detail-name">{{ currentLayer.name }}</span>
<span class="detail-analogy">{{ currentLayer.analogy }}</span>
</div>
<div class="detail-desc">{{ currentLayer.desc }}</div>
<div class="detail-tasks">
<div class="task-title">核心任务</div>
<ul>
<li v-for="(task, j) in currentLayer.tasks" :key="j">{{ task }}</li>
</ul>
</div>
<div class="detail-unit">
<span class="label">数据单位</span>
<span class="value">{{ currentLayer.unit }}</span>
</div>
</div>
<div class="encapsulation-demo">
<div class="encap-title">数据封装过程</div>
<div class="encap-flow">
<div class="encap-step" v-for="(step, i) in encapsulation" :key="i">
<div class="step-layer">{{ step.layer }}</div>
<div class="step-data">
<span class="header" v-if="step.header">{{ step.header }}</span>
<span class="payload">{{ step.payload }}</span>
</div>
</div>
<div class="arrow"> 发送</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>分层设计让网络协议模块化每层只关心自己的职责数据从应用层向下传递时每层都会添加自己的"信封"(头部)接收时再逐层拆开
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeLayer = ref(0)
const layers = [
{
name: '应用层',
protocols: 'HTTP, FTP, SMTP, DNS',
device: '',
analogy: '客户服务部门',
desc: '直接为用户的应用程序提供服务,处理具体的业务逻辑。',
tasks: ['定义应用程序之间的通信格式', '处理用户身份认证', '数据格式转换'],
unit: '消息(Message)'
},
{
name: '传输层',
protocols: 'TCP, UDP',
device: '',
analogy: '包裹分拣组',
desc: '负责端到端的数据传输,确保数据的可靠性或实时性。',
tasks: ['建立和管理端到端连接', '分段和重组数据', '流量控制和拥塞控制', '端口寻址'],
unit: '段(Segment)'
},
{
name: '网络层',
protocols: 'IP, ICMP, ARP',
device: '路由器',
analogy: '路由规划部',
desc: '负责将数据包从源主机传送到目标主机,实现跨网络通信。',
tasks: ['IP地址分配和管理', '路由选择', '数据包转发', '拥塞控制'],
unit: '包(Packet)'
},
{
name: '数据链路层',
protocols: '以太网, Wi-Fi',
device: '交换机',
analogy: '车队管理',
desc: '负责在直连的两个节点之间传输数据帧。',
tasks: ['MAC地址寻址', '帧的封装和解封装', '错误检测', '介质访问控制'],
unit: '帧(Frame)'
},
{
name: '物理层',
protocols: 'RS-232, RJ45',
device: '中继器, 集线器',
analogy: '道路和车辆',
desc: '负责在物理介质上传输原始的比特流。',
tasks: ['定义物理设备标准', '规定传输介质', '确定电气特性', '比特同步'],
unit: '比特(Bit)'
}
]
const currentLayer = computed(() => layers[activeLayer.value])
const encapsulation = [
{ layer: '应用层', header: '', payload: '原始数据' },
{ layer: '传输层', header: 'TCP头', payload: '原始数据' },
{ layer: '网络层', header: 'IP头', payload: 'TCP头+原始数据' },
{ layer: '数据链路层', header: 'MAC头', payload: 'IP头+TCP头+原始数据' },
{ layer: '物理层', header: '', payload: '比特流 010101...' }
]
</script>
<style scoped>
.network-layers-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.layers-container {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.layer {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
border: 2px solid transparent;
}
.layer:hover {
background: var(--vp-c-bg-alt);
}
.layer.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.layer-num {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.8rem;
font-weight: bold;
}
.layer-info {
flex: 1;
}
.layer-name {
font-weight: bold;
font-size: 0.85rem;
}
.layer-protocol {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.layer-device {
font-size: 0.7rem;
color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
padding: 0.15rem 0.4rem;
border-radius: 3px;
}
.layer-detail {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.detail-name {
font-weight: bold;
font-size: 1rem;
}
.detail-analogy {
font-size: 0.75rem;
color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
padding: 0.15rem 0.4rem;
border-radius: 3px;
}
.detail-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.detail-tasks {
margin-bottom: 0.5rem;
}
.task-title {
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 0.25rem;
}
.detail-tasks ul {
margin: 0;
padding-left: 1rem;
font-size: 0.8rem;
}
.detail-tasks li {
margin: 0.15rem 0;
}
.detail-unit {
font-size: 0.8rem;
}
.detail-unit .label {
color: var(--vp-c-text-2);
}
.detail-unit .value {
font-weight: bold;
color: var(--vp-c-brand);
}
.encapsulation-demo {
grid-column: 1 / -1;
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.encap-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.encap-flow {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.encap-step {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.35rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
min-width: 80px;
}
.step-layer {
font-size: 0.7rem;
color: var(--vp-c-text-2);
}
.step-data {
display: flex;
gap: 0.15rem;
font-size: 0.75rem;
}
.header {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand);
padding: 0.1rem 0.3rem;
border-radius: 2px;
}
.payload {
background: var(--vp-c-divider);
padding: 0.1rem 0.3rem;
border-radius: 2px;
}
.arrow {
font-size: 0.8rem;
color: var(--vp-c-brand);
font-weight: bold;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
@media (max-width: 640px) {
.demo-content {
grid-template-columns: 1fr;
}
}
</style>
@@ -0,0 +1,261 @@
<template>
<div class="process-demo">
<div class="demo-header">
<span class="icon">🔄</span>
<span class="title">进程程序的"分身术"</span>
<span class="subtitle">一个程序如何同时运行多个实例</span>
</div>
<div class="demo-content">
<div class="process-list">
<div class="process-header">
<span class="col-name">进程名</span>
<span class="col-pid">PID</span>
<span class="col-state">状态</span>
<span class="col-mem">内存</span>
</div>
<div
v-for="p in processes"
:key="p.pid"
class="process-item"
:class="{ running: p.state === '运行中', selected: selectedPid === p.pid }"
@click="selectedPid = p.pid"
>
<span class="col-name">
<span class="process-icon">{{ p.icon }}</span>
{{ p.name }}
</span>
<span class="col-pid">{{ p.pid }}</span>
<span class="col-state">
<span class="state-badge" :class="p.state === '运行中' ? 'running' : 'waiting'">
{{ p.state }}
</span>
</span>
<span class="col-mem">{{ p.memory }}</span>
</div>
</div>
<div class="process-detail" v-if="selectedProcess">
<div class="detail-title">进程详情{{ selectedProcess.name }}</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">进程ID (PID)</span>
<span class="value">{{ selectedProcess.pid }}</span>
</div>
<div class="detail-item">
<span class="label">父进程ID</span>
<span class="value">{{ selectedProcess.ppid }}</span>
</div>
<div class="detail-item">
<span class="label">内存占用</span>
<span class="value">{{ selectedProcess.memory }}</span>
</div>
<div class="detail-item">
<span class="label">CPU 占用</span>
<span class="value">{{ selectedProcess.cpu }}%</span>
</div>
</div>
<div class="memory-layout">
<div class="layout-title">进程内存布局</div>
<div class="layout-visual">
<div class="segment" v-for="seg in memorySegments" :key="seg.name" :style="{ height: seg.height }">
<span class="seg-name">{{ seg.name }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>进程是程序的"运行实例"同一个程序可以启动多个进程每个进程有独立的内存空间互不干扰
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const selectedPid = ref(1001)
const processes = ref([
{ pid: 1001, name: 'Chrome', icon: '🌐', state: '运行中', memory: '512MB', cpu: 15, ppid: 1 },
{ pid: 1002, name: 'VS Code', icon: '📝', state: '运行中', memory: '384MB', cpu: 8, ppid: 1 },
{ pid: 1003, name: '微信', icon: '💬', state: '等待中', memory: '256MB', cpu: 2, ppid: 1 },
{ pid: 1004, name: '终端', icon: '⬛', state: '等待中', memory: '32MB', cpu: 0, ppid: 1002 },
{ pid: 1005, name: '音乐', icon: '🎵', state: '运行中', memory: '128MB', cpu: 3, ppid: 1 }
])
const selectedProcess = computed(() => {
return processes.value.find(p => p.pid === selectedPid.value)
})
const memorySegments = [
{ name: '栈区 (Stack)', height: '20%' },
{ name: '堆区 (Heap)', height: '35%' },
{ name: '数据段 (Data)', height: '15%' },
{ name: '代码段 (Text)', height: '30%' }
]
</script>
<style scoped>
.process-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 1rem;
flex-wrap: wrap;
}
.process-list {
flex: 1;
min-width: 280px;
font-size: 0.85rem;
}
.process-header {
display: grid;
grid-template-columns: 2fr 1fr 1.5fr 1fr;
gap: 0.5rem;
padding: 0.5rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
font-weight: bold;
margin-bottom: 0.25rem;
}
.process-item {
display: grid;
grid-template-columns: 2fr 1fr 1.5fr 1fr;
gap: 0.5rem;
padding: 0.5rem;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.process-item:hover {
background: var(--vp-c-bg);
}
.process-item.selected {
background: var(--vp-c-brand-soft);
}
.process-icon {
margin-right: 0.25rem;
}
.state-badge {
padding: 0.1rem 0.4rem;
border-radius: 3px;
font-size: 0.75rem;
}
.state-badge.running {
background: var(--vp-c-success);
color: white;
}
.state-badge.waiting {
background: var(--vp-c-divider);
color: var(--vp-c-text-2);
}
.process-detail {
flex: 1;
min-width: 250px;
}
.detail-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.detail-item {
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 4px;
}
.detail-item .label {
display: block;
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.detail-item .value {
font-weight: bold;
font-size: 0.9rem;
}
.memory-layout {
background: var(--vp-c-bg-alt);
padding: 0.5rem;
border-radius: 4px;
}
.layout-title {
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 0.5rem;
}
.layout-visual {
display: flex;
flex-direction: column;
gap: 2px;
height: 120px;
}
.segment {
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand-soft);
border-radius: 2px;
}
.seg-name {
font-size: 0.7rem;
font-weight: bold;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,246 @@
<template>
<div class="storage-demo">
<div class="demo-header">
<span class="icon">💾</span>
<span class="title">存储层次从寄存器到云存储</span>
<span class="subtitle">速度与容量的权衡</span>
</div>
<div class="demo-content">
<div class="storage-pyramid">
<div
v-for="(level, i) in storageLevels"
:key="level.name"
class="level"
:class="{ active: activeLevel === i }"
:style="{ width: level.width }"
@click="activeLevel = i"
>
<div class="level-name">{{ level.name }}</div>
<div class="level-speed">{{ level.speed }}</div>
<div class="level-size">{{ level.size }}</div>
</div>
</div>
<div class="level-detail" v-if="currentLevel">
<div class="detail-title">{{ currentLevel.name }} 详情</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">访问速度</span>
<span class="value">{{ currentLevel.speed }}</span>
</div>
<div class="detail-item">
<span class="label">典型容量</span>
<span class="value">{{ currentLevel.size }}</span>
</div>
<div class="detail-item">
<span class="label">每字节成本</span>
<span class="value">{{ currentLevel.cost }}</span>
</div>
<div class="detail-item">
<span class="label">易失性</span>
<span class="value">{{ currentLevel.volatile }}</span>
</div>
</div>
<div class="detail-desc">{{ currentLevel.desc }}</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>存储遵循"金字塔"原则越快的存储越贵容量越小CPU 需要的数据放在最快的存储寄存器缓存暂时不用的放在慢速大容量存储磁盘云端
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeLevel = ref(0)
const storageLevels = [
{
name: '寄存器',
speed: '~1 纳秒',
size: '几百字节',
width: '30%',
cost: '极高',
volatile: '是',
desc: 'CPU 内部最快的存储,直接参与运算。数量有限,由编译器自动管理。'
},
{
name: 'L1 缓存',
speed: '~2 纳秒',
size: '32-64 KB',
width: '45%',
cost: '很高',
volatile: '是',
desc: 'CPU 内置的高速缓存,存储最常用的数据。每个核心独立拥有。'
},
{
name: 'L2/L3 缓存',
speed: '~10 纳秒',
size: '几 MB',
width: '60%',
cost: '高',
volatile: '是',
desc: '更大但稍慢的缓存,L3 通常多核心共享。'
},
{
name: '内存 (RAM)',
speed: '~100 纳秒',
size: '8-128 GB',
width: '75%',
cost: '中等',
volatile: '是',
desc: '程序运行时的主要工作区。断电后数据丢失。'
},
{
name: 'SSD 固态硬盘',
speed: '~100 微秒',
size: '256 GB - 4 TB',
width: '90%',
cost: '较低',
volatile: '否',
desc: '比机械硬盘快很多,无机械部件。断电数据保留。'
},
{
name: 'HDD 机械硬盘',
speed: '~10 毫秒',
size: '1-20 TB',
width: '100%',
cost: '低',
volatile: '否',
desc: '容量大、成本低,但有机械延迟。适合存储大量数据。'
}
]
const currentLevel = computed(() => storageLevels[activeLevel.value])
</script>
<style scoped>
.storage-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 1rem;
flex-wrap: wrap;
}
.storage-pyramid {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
flex: 1;
min-width: 200px;
}
.level {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.5rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
cursor: pointer;
transition: all 0.2s;
}
.level:hover {
background: var(--vp-c-bg-soft);
}
.level.active {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
}
.level-name {
font-weight: bold;
font-size: 0.85rem;
}
.level-speed {
font-size: 0.75rem;
color: var(--vp-c-success);
}
.level-size {
font-size: 0.7rem;
color: var(--vp-c-text-2);
}
.level-detail {
flex: 1;
min-width: 250px;
}
.detail-title {
font-weight: bold;
font-size: 1rem;
margin-bottom: 0.75rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.detail-item {
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 4px;
}
.detail-item .label {
display: block;
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.detail-item .value {
font-weight: bold;
font-size: 0.9rem;
}
.detail-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
background: var(--vp-c-bg-alt);
padding: 0.5rem;
border-radius: 4px;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,432 @@
<template>
<div class="subnet-calculator">
<div class="demo-header">
<span class="icon">🔢</span>
<span class="title">子网计算器</span>
<span class="subtitle">理解 IP 地址和子网掩码</span>
</div>
<div class="demo-content">
<div class="input-section">
<div class="input-group">
<label>IP 地址</label>
<div class="ip-inputs">
<input v-model="ip[0]" type="number" min="0" max="255" @input="calculate" />
<span>.</span>
<input v-model="ip[1]" type="number" min="0" max="255" @input="calculate" />
<span>.</span>
<input v-model="ip[2]" type="number" min="0" max="255" @input="calculate" />
<span>.</span>
<input v-model="ip[3]" type="number" min="0" max="255" @input="calculate" />
</div>
</div>
<div class="input-group">
<label>子网掩码 (CIDR)</label>
<div class="cidr-input">
<span>/</span>
<input v-model.number="cidr" type="number" min="8" max="30" @input="calculate" />
</div>
</div>
</div>
<div class="result-section">
<div class="result-item">
<span class="label">子网掩码</span>
<span class="value">{{ mask }}</span>
</div>
<div class="result-item">
<span class="label">网络地址</span>
<span class="value">{{ networkAddress }}</span>
</div>
<div class="result-item">
<span class="label">广播地址</span>
<span class="value">{{ broadcastAddress }}</span>
</div>
<div class="result-item">
<span class="label">可用主机数</span>
<span class="value">{{ usableHosts }}</span>
</div>
<div class="result-item">
<span class="label">主机范围</span>
<span class="value">{{ hostRange }}</span>
</div>
</div>
<div class="binary-section">
<div class="binary-title">二进制表示</div>
<div class="binary-row">
<span class="binary-label">IP 地址:</span>
<span class="binary-value">{{ ipBinary }}</span>
</div>
<div class="binary-row">
<span class="binary-label">子网掩码:</span>
<span class="binary-value">{{ maskBinary }}</span>
</div>
<div class="binary-row">
<span class="binary-label">网络部分:</span>
<span class="binary-value network">{{ networkBinary }}</span>
</div>
<div class="binary-row">
<span class="binary-label">主机部分:</span>
<span class="binary-value host">{{ hostBinary }}</span>
</div>
</div>
<div class="visual-section">
<div class="visual-title">地址结构可视化</div>
<div class="address-visual">
<div class="bit-blocks">
<div
v-for="(bit, i) in bits"
:key="i"
:class="['bit', { network: i < cidr, host: i >= cidr }]"
>
{{ bit }}
</div>
</div>
<div class="legend">
<span class="legend-item"><span class="network-box"></span> 网络位 ({{ cidr }})</span>
<span class="legend-item"><span class="host-box"></span> 主机位 ({{ 32 - cidr }})</span>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>子网掩码决定了 IP 地址的哪部分是"网络号"(小区)哪部分是"主机号"(房间)/24 表示前 24 位是网络位 8 位是主机位
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
const ip = ref([192, 168, 1, 100])
const cidr = ref(24)
const mask = computed(() => {
const maskValue = 0xFFFFFFFF << (32 - cidr.value)
return [
(maskValue >>> 24) & 255,
(maskValue >>> 16) & 255,
(maskValue >>> 8) & 255,
maskValue & 255
].join('.')
})
const ipValue = computed(() => {
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)
})
const networkAddress = computed(() => {
const network = ipValue.value & maskValue.value
return [
(network >>> 24) & 255,
(network >>> 16) & 255,
(network >>> 8) & 255,
network & 255
].join('.')
})
const broadcastAddress = computed(() => {
const network = ipValue.value & maskValue.value
const broadcast = network | (~maskValue.value >>> 0)
return [
(broadcast >>> 24) & 255,
(broadcast >>> 16) & 255,
(broadcast >>> 8) & 255,
broadcast & 255
].join('.')
})
const usableHosts = computed(() => {
return Math.pow(2, 32 - cidr.value) - 2
})
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}`
})
const toBinary = (num) => {
return num.toString(2).padStart(8, '0')
}
const ipBinary = computed(() => {
return ip.value.map(toBinary).join(' ')
})
const maskBinary = computed(() => {
const m = [
(maskValue.value >>> 24) & 255,
(maskValue.value >>> 16) & 255,
(maskValue.value >>> 8) & 255,
maskValue.value & 255
]
return m.map(toBinary).join(' ')
})
const bits = computed(() => {
return ip.value.map(octet => toBinary(parseInt(octet))).join('').split('')
})
const networkBinary = computed(() => {
return bits.value.slice(0, cidr.value).join('') + ' '.repeat(32 - cidr.value)
})
const hostBinary = computed(() => {
return ' '.repeat(cidr.value) + bits.value.slice(cidr.value).join('')
})
const calculate = () => {
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))
}
onMounted(() => {
calculate()
})
</script>
<style scoped>
.subnet-calculator {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.input-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.input-group label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.ip-inputs {
display: flex;
align-items: center;
gap: 0.25rem;
}
.ip-inputs input {
width: 50px;
padding: 0.35rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
background: var(--vp-c-bg);
text-align: center;
font-size: 0.85rem;
}
.ip-inputs span {
color: var(--vp-c-text-2);
}
.cidr-input {
display: flex;
align-items: center;
gap: 0.25rem;
}
.cidr-input input {
width: 50px;
padding: 0.35rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
background: var(--vp-c-bg);
text-align: center;
font-size: 0.85rem;
}
.result-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0.5rem;
margin-bottom: 1rem;
}
.result-item {
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 6px;
}
.result-item .label {
display: block;
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.15rem;
}
.result-item .value {
font-size: 0.9rem;
font-weight: bold;
color: var(--vp-c-brand);
}
.binary-section {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.binary-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.binary-row {
display: flex;
gap: 0.5rem;
font-family: monospace;
font-size: 0.75rem;
margin-bottom: 0.25rem;
}
.binary-label {
color: var(--vp-c-text-2);
min-width: 80px;
}
.binary-value {
letter-spacing: 1px;
}
.binary-value.network {
color: var(--vp-c-brand);
}
.binary-value.host {
color: var(--vp-c-text-3);
}
.visual-section {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.visual-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.bit-blocks {
display: flex;
flex-wrap: wrap;
gap: 2px;
margin-bottom: 0.5rem;
}
.bit {
width: 12px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.65rem;
font-family: monospace;
border-radius: 2px;
}
.bit.network {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand);
}
.bit.host {
background: var(--vp-c-divider);
color: var(--vp-c-text-2);
}
.legend {
display: flex;
gap: 1rem;
font-size: 0.75rem;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.25rem;
}
.network-box, .host-box {
width: 12px;
height: 12px;
border-radius: 2px;
}
.network-box {
background: var(--vp-c-brand-soft);
}
.host-box {
background: var(--vp-c-divider);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,584 @@
<template>
<div class="tcp-udp-demo">
<div class="demo-header">
<span class="icon">📦</span>
<span class="title">TCP vs UDP可靠 vs 快速</span>
<span class="subtitle">两种不同的传输策略</span>
</div>
<div class="demo-content">
<div class="comparison-tabs">
<button
:class="['tab-btn', { active: activeTab === 'tcp' }]"
@click="activeTab = 'tcp'"
>
<span class="tab-icon">📨</span>
<span>TCP (可靠)</span>
</button>
<button
:class="['tab-btn', { active: activeTab === 'udp' }]"
@click="activeTab = 'udp'"
>
<span class="tab-icon">📮</span>
<span>UDP (快速)</span>
</button>
</div>
<div class="protocol-detail" v-if="currentProtocol">
<div class="detail-header">
<span class="detail-name">{{ currentProtocol.name }}</span>
<span class="detail-full">{{ currentProtocol.fullName }}</span>
</div>
<div class="feature-grid">
<div class="feature-item" v-for="(feature, i) in currentProtocol.features" :key="i">
<span class="feature-icon">{{ feature.icon }}</span>
<span class="feature-name">{{ feature.name }}</span>
<span class="feature-value">{{ feature.value }}</span>
</div>
</div>
<div class="mechanism-section">
<div class="mechanism-title">核心机制</div>
<div class="mechanism-list">
<div class="mechanism-item" v-for="(m, i) in currentProtocol.mechanisms" :key="i">
<span class="mechanism-name">{{ m.name }}</span>
<span class="mechanism-desc">{{ m.desc }}</span>
</div>
</div>
</div>
<div class="use-cases">
<div class="use-title">适用场景</div>
<div class="use-tags">
<span class="use-tag" v-for="(use, i) in currentProtocol.useCases" :key="i">{{ use }}</span>
</div>
</div>
</div>
<div class="visual-demo">
<div class="visual-title">传输过程演示</div>
<div class="transmission-demo">
<div class="sender">
<div class="node-label">发送方</div>
<div class="packets">
<div
v-for="(packet, i) in packets"
:key="i"
: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 }">
{{ isCongested ? '拥堵' : '正常' }}
</div>
<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="received-packets">
<div
v-for="(packet, i) in receivedPackets"
:key="i"
class="received-packet"
>
{{ packet }}
</div>
</div>
</div>
</div>
<div class="demo-log">
<div class="log-title">传输日志</div>
<div class="log-content">
<div v-for="(log, i) in logs" :key="i" class="log-item">{{ log }}</div>
</div>
</div>
</div>
<div class="comparison-table">
<div class="table-title">特性对比</div>
<table>
<thead>
<tr>
<th>特性</th>
<th>TCP</th>
<th>UDP</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, i) in comparisonData" :key="i">
<td class="feature-col">{{ row.feature }}</td>
<td :class="{ highlight: row.tcpBetter }">{{ row.tcp }}</td>
<td :class="{ highlight: !row.tcpBetter }">{{ row.udp }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>TCP 像挂号信确保送达但较慢UDP 像平信快速但不保证送达选择哪种协议取决于应用场景需要可靠性选 TCP需要实时性选 UDP
</div>
</div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue'
const activeTab = ref('tcp')
const protocols = {
tcp: {
name: 'TCP',
fullName: 'Transmission Control Protocol',
features: [
{ icon: '✅', name: '可靠性', value: '保证数据送达' },
{ icon: '📊', name: '有序性', value: '按顺序重组' },
{ icon: '🔄', name: '重传机制', value: '丢包自动重传' },
{ icon: '⚖️', name: '流量控制', value: '防止接收方溢出' },
{ icon: '🚦', name: '拥塞控制', value: '避免网络拥堵' },
{ icon: '🤝', name: '连接导向', value: '需要建立连接' }
],
mechanisms: [
{ name: '三次握手', desc: '建立可靠连接,确保双方都能收发' },
{ name: '序列号', desc: '每个字节编号,保证有序和完整性' },
{ name: '确认应答', desc: '收到数据必须回复 ACK' },
{ name: '超时重传', desc: '未收到 ACK 则重传' },
{ name: '滑动窗口', desc: '控制发送速率,提高效率' }
],
useCases: ['网页浏览', '文件传输', '邮件发送', '数据库连接']
},
udp: {
name: 'UDP',
fullName: 'User Datagram Protocol',
features: [
{ icon: '⚡', name: '速度', value: '无连接开销' },
{ icon: '📦', name: '数据报', value: '独立的数据包' },
{ icon: '❌', name: '无保证', value: '不保证送达' },
{ icon: '🔀', name: '无序', value: '可能乱序到达' },
{ icon: '💡', name: '轻量', value: '头部仅 8 字节' },
{ icon: '🎯', name: '灵活', value: '应用层控制' }
],
mechanisms: [
{ name: '无连接', desc: '直接发送,无需建立连接' },
{ name: '校验和', desc: '检测数据是否损坏' },
{ name: '端口复用', desc: '支持多路复用' },
{ name: '应用层控制', desc: '由应用决定重传等策略' }
],
useCases: ['视频直播', '在线游戏', 'DNS 查询', 'VoIP 通话']
}
}
const currentProtocol = computed(() => protocols[activeTab.value])
const comparisonData = [
{ feature: '连接', tcp: '面向连接', udp: '无连接', tcpBetter: true },
{ feature: '可靠性', tcp: '可靠传输', udp: '不保证', tcpBetter: true },
{ feature: '顺序', tcp: '有序', udp: '可能乱序', tcpBetter: true },
{ feature: '速度', tcp: '较慢', udp: '快', tcpBetter: false },
{ feature: '头部开销', tcp: '20 字节', udp: '8 字节', tcpBetter: false },
{ feature: '流量控制', tcp: '有', udp: '无', tcpBetter: true },
{ feature: '拥塞控制', tcp: '有', udp: '无', tcpBetter: true },
{ feature: '广播/多播', tcp: '不支持', udp: '支持', tcpBetter: false }
]
const packets = ref([
{ seq: 1, sent: false, acked: false, lost: false },
{ seq: 2, sent: false, acked: false, lost: false },
{ seq: 3, sent: false, acked: false, lost: false },
{ seq: 4, sent: false, acked: false, lost: false }
])
const receivedPackets = ref([])
const logs = ref([])
const isCongested = ref(false)
const toggleCongestion = () => {
isCongested.value = !isCongested.value
logs.value.push(`网络状态: ${isCongested.value ? '拥堵(模拟丢包)' : '正常'}`)
}
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))
logs.value.push(`TCP 重传包 ${packet.seq}...`)
packet.lost = false
receivedPackets.value.push(packet.seq)
packet.acked = true
logs.value.push(`${packet.seq} 重传成功`)
}
} else {
receivedPackets.value.push(packet.seq)
packet.acked = true
logs.value.push(`${packet.seq} 送达`)
}
await new Promise(r => setTimeout(r, 300))
}
if (isTcp) {
logs.value.push(`TCP 完成: 收到 ${receivedPackets.value.length} 个包,顺序: ${receivedPackets.value.join(', ')}`)
} else {
logs.value.push(`UDP 完成: 收到 ${receivedPackets.value.length} 个包`)
}
}
</script>
<style scoped>
.tcp-udp-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 0.5rem;
margin-bottom: 1rem;
}
.tab-btn {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.5rem;
border: 2px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
}
.tab-btn.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.tab-icon { font-size: 1.1rem; }
.protocol-detail {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
}
.detail-name {
font-weight: bold;
font-size: 1.1rem;
}
.detail-full {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.feature-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.4rem;
background: var(--vp-c-bg-alt);
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; }
.mechanism-section {
margin-bottom: 0.75rem;
}
.mechanism-title, .use-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.mechanism-list {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.mechanism-item {
display: flex;
gap: 0.5rem;
font-size: 0.8rem;
}
.mechanism-name {
font-weight: bold;
color: var(--vp-c-brand);
min-width: 70px;
}
.mechanism-desc {
color: var(--vp-c-text-2);
}
.use-tags {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
}
.use-tag {
padding: 0.2rem 0.5rem;
background: var(--vp-c-brand-soft);
border-radius: 4px;
font-size: 0.75rem;
}
.visual-demo {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.visual-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.transmission-demo {
display: flex;
justify-content: space-between;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.sender, .receiver {
flex: 1;
padding: 0.5rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
}
.node-label {
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 0.25rem;
}
.packets, .received-packets {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
}
.packet {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-divider);
border-radius: 4px;
font-size: 0.8rem;
font-weight: bold;
}
.packet.sent {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand);
}
.packet.acked {
background: var(--vp-c-brand);
color: white;
}
.packet.lost {
background: #ff6b6b;
color: white;
}
.received-packet {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-brand);
color: white;
border-radius: 4px;
font-size: 0.8rem;
font-weight: bold;
}
.network-channel {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
padding: 0.5rem;
}
.channel-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.channel-status {
font-size: 0.7rem;
padding: 0.15rem 0.4rem;
background: #51cf66;
color: white;
border-radius: 3px;
}
.channel-status.congested {
background: #ff6b6b;
}
.demo-btn {
padding: 0.25rem 0.5rem;
font-size: 0.7rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 4px;
cursor: pointer;
}
.demo-btn:hover {
background: var(--vp-c-bg-alt);
}
.demo-log {
background: var(--vp-c-bg-alt);
border-radius: 4px;
overflow: hidden;
}
.log-title {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
background: var(--vp-c-divider);
}
.log-content {
padding: 0.5rem;
max-height: 100px;
overflow-y: auto;
}
.log-item {
font-size: 0.75rem;
font-family: monospace;
margin-bottom: 0.15rem;
}
.comparison-table {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.table-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.8rem;
}
th, td {
border: 1px solid var(--vp-c-divider);
padding: 0.4rem;
text-align: center;
}
th {
background: var(--vp-c-bg);
}
.feature-col {
text-align: left;
font-weight: bold;
}
.highlight {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand);
font-weight: bold;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,201 @@
<template>
<div class="transistor-demo">
<div class="demo-header">
<span class="icon"></span>
<span class="title">晶体管数字世界的开关</span>
<span class="subtitle">一个开关如何变成计算能力</span>
</div>
<div class="demo-content">
<div class="switch-container">
<div class="switch-area" @click="toggleSwitch">
<div class="transistor-symbol">
<svg viewBox="0 0 100 80" class="transistor-svg">
<line x1="10" y1="40" x2="35" y2="40" stroke="var(--vp-c-text-1)" stroke-width="2"/>
<line x1="65" y1="40" x2="90" y2="40" stroke="var(--vp-c-text-1)" stroke-width="2"/>
<line x1="50" y1="20" x2="50" y2="35" stroke="var(--vp-c-text-1)" stroke-width="2"/>
<line x1="50" y1="45" x2="50" y2="60" stroke="var(--vp-c-text-1)" stroke-width="2"/>
<line x1="35" y1="30" x2="35" y2="50" stroke="var(--vp-c-text-1)" stroke-width="3"/>
<line x1="65" y1="30" x2="65" y2="50" stroke="var(--vp-c-text-1)" stroke-width="3"/>
<line x1="35" y1="40" x2="65" y2="40" stroke="var(--vp-c-text-1)" stroke-width="2"/>
<circle cx="50" cy="60" r="4" fill="var(--vp-c-text-1)"/>
</svg>
</div>
<div class="switch-label">
<span class="state-label">{{ isOn ? 'ON (1)' : 'OFF (0)' }}</span>
<div class="current-flow" :class="{ active: isOn }">
<span class="flow-indicator">电流</span>
</div>
</div>
</div>
</div>
<div class="truth-table">
<div class="table-title">晶体管状态表</div>
<table>
<thead>
<tr>
<th>栅极(控制端)</th>
<th>源极漏极</th>
<th>输出</th>
</tr>
</thead>
<tbody>
<tr :class="{ highlight: !isOn }">
<td>低电压 (0)</td>
<td>断开</td>
<td>0</td>
</tr>
<tr :class="{ highlight: isOn }">
<td>高电压 (1)</td>
<td>导通</td>
<td>1</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>晶体管就是一个用电控制的开关给它高电压(1)它就导通给低电压(0)它就断开这是所有数字计算的基础
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isOn = ref(false)
const toggleSwitch = () => {
isOn.value = !isOn.value
}
</script>
<style scoped>
.transistor-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
gap: 1.5rem;
align-items: center;
flex-wrap: wrap;
}
.switch-container {
flex: 1;
min-width: 200px;
}
.switch-area {
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1rem;
cursor: pointer;
transition: all 0.3s;
text-align: center;
}
.switch-area:hover {
border-color: var(--vp-c-brand);
}
.transistor-symbol {
width: 120px;
height: 80px;
margin: 0 auto 0.5rem;
}
.transistor-svg {
width: 100%;
height: 100%;
}
.switch-label {
display: flex;
flex-direction: column;
gap: 0.25rem;
align-items: center;
}
.state-label {
font-weight: bold;
font-size: 1.1rem;
color: var(--vp-c-brand);
}
.current-flow {
font-size: 0.8rem;
color: var(--vp-c-text-3);
opacity: 0.5;
transition: all 0.3s;
}
.current-flow.active {
opacity: 1;
color: var(--vp-c-success);
}
.truth-table {
flex: 1;
min-width: 250px;
}
.table-title {
font-weight: bold;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
th, td {
border: 1px solid var(--vp-c-divider);
padding: 0.5rem;
text-align: center;
}
th {
background: var(--vp-c-bg-alt);
}
tr.highlight {
background: var(--vp-c-brand-soft);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,345 @@
<template>
<div class="transmission-demo">
<div class="demo-header">
<span class="icon">📡</span>
<span class="title">数据传输从串行到并行</span>
<span class="subtitle">数据如何在不同设备间移动</span>
</div>
<div class="demo-content">
<div class="transmission-types">
<div class="type-card" :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>
<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>
</div>
<div class="transmission-visual">
<div class="visual-title">{{ activeType === 'serial' ? '串行传输示意' : '并行传输示意' }}</div>
<div class="visual-area">
<div class="sender">
<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>
</div>
</div>
<div class="channels">
<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>
</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 class="channel-flow">
<span class="flow-dot active"></span>
</div>
</div>
</div>
</div>
<div class="receiver">
<div class="device-label">接收端</div>
<div class="data-bits received">
<span v-for="(bit, i) in receivedBits" :key="i" class="bit">{{ bit }}</span>
</div>
</div>
</div>
<button class="send-btn" @click="startTransmission">发送数据</button>
</div>
<div class="comparison-table">
<div class="table-title">串行 vs 并行对比</div>
<table>
<thead>
<tr>
<th>特性</th>
<th>串行</th>
<th>并行</th>
</tr>
</thead>
<tbody>
<tr>
<td>传输线数量</td>
<td>1-几根</td>
<td>8-64</td>
</tr>
<tr>
<td>抗干扰能力</td>
<td></td>
<td>线间干扰</td>
</tr>
<tr>
<td>传输距离</td>
<td></td>
<td></td>
</tr>
<tr>
<td>现代应用</td>
<td>主流USBPCIe</td>
<td>较少</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>现代高速传输多采用串行方式虽然并行"看起来"更快一次传多位但串行可以跑更高频率抗干扰更强实际速度反而更快
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeType = ref('serial')
const dataBits = ref(['1', '0', '1', '1', '0', '0', '1', '0'])
const receivedBits = ref(['-', '-', '-', '-', '-', '-', '-', '-'])
const sendingBit = ref(null)
const startTransmission = () => {
if (activeType.value === 'serial') {
receivedBits.value = ['-', '-', '-', '-', '-', '-', '-', '-']
let i = 0
const interval = setInterval(() => {
if (i < dataBits.value.length) {
sendingBit.value = i
receivedBits.value[i] = dataBits.value[i]
i++
} else {
clearInterval(interval)
sendingBit.value = null
}
}, 300)
} else {
receivedBits.value = [...dataBits.value]
}
}
</script>
<style scoped>
.transmission-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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;
flex-direction: column;
gap: 1rem;
}
.transmission-types {
display: flex;
gap: 1rem;
}
.type-card {
flex: 1;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
text-align: center;
transition: all 0.2s;
}
.type-card.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
}
.card-icon {
font-size: 1.5rem;
margin-bottom: 0.25rem;
}
.card-title {
font-weight: bold;
font-size: 0.9rem;
}
.card-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.card-examples {
font-size: 0.75rem;
color: var(--vp-c-brand);
margin-top: 0.25rem;
}
.transmission-visual {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.visual-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
text-align: center;
}
.visual-area {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.sender, .receiver {
text-align: center;
}
.device-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.25rem;
}
.data-bits {
display: flex;
gap: 2px;
}
.bit {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
background: var(--vp-c-bg-alt);
border-radius: 2px;
font-size: 0.75rem;
font-family: monospace;
}
.bit.sending {
background: var(--vp-c-brand);
color: white;
}
.channels {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.channel.serial {
display: flex;
flex-direction: column;
align-items: center;
}
.channel.parallel {
gap: 2px;
}
.channel-row {
display: flex;
align-items: center;
gap: 0.25rem;
}
.channel-label {
font-size: 0.65rem;
color: var(--vp-c-text-3);
}
.channel-flow {
display: flex;
gap: 2px;
}
.flow-dot {
font-size: 0.5rem;
color: var(--vp-c-divider);
}
.flow-dot.active {
color: var(--vp-c-brand);
}
.send-btn {
width: 100%;
padding: 0.5rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
}
.comparison-table {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
}
.table-title {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.8rem;
}
th, td {
border: 1px solid var(--vp-c-divider);
padding: 0.4rem;
text-align: center;
}
th {
background: var(--vp-c-bg);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
</style>
@@ -0,0 +1,481 @@
<template>
<div class="type-system-demo">
<div class="demo-header">
<span class="icon">🏷</span>
<span class="title">类型系统数据的分类规则</span>
<span class="subtitle">静态 vs 动态强类型 vs 弱类型</span>
</div>
<div class="demo-content">
<div class="type-quadrant">
<div class="quadrant-title">类型系统四象限</div>
<div class="quadrant-grid">
<div class="quadrant-cell strong-static">
<div class="cell-label">强类型 + 静态</div>
<div class="cell-langs">Java, Rust, Haskell</div>
<div class="cell-desc">最安全编译期检查</div>
</div>
<div class="quadrant-cell weak-static">
<div class="cell-label">弱类型 + 静态</div>
<div class="cell-langs">C, C++</div>
<div class="cell-desc">高效但需小心</div>
</div>
<div class="quadrant-cell strong-dynamic">
<div class="cell-label">强类型 + 动态</div>
<div class="cell-langs">Python, Ruby</div>
<div class="cell-desc">灵活运行时检查</div>
</div>
<div class="quadrant-cell weak-dynamic">
<div class="cell-label">弱类型 + 动态</div>
<div class="cell-langs">JavaScript, PHP</div>
<div class="cell-desc">最灵活但易出错</div>
</div>
</div>
<div class="axis-labels">
<span class="axis-x">静态 动态</span>
<span class="axis-y">强类型 弱类型</span>
</div>
</div>
<div class="type-demo">
<div class="demo-title">类型检查演示</div>
<div class="code-comparison">
<div class="code-block">
<div class="code-label">静态类型 (Java)</div>
<pre><code>String name = "Alice";
name = 123; //
int x = 10;
String s = x; // </code></pre>
<div class="code-result error">编译期发现错误</div>
</div>
<div class="code-block">
<div class="code-label">动态类型 (Python)</div>
<pre><code>name = "Alice"
name = 123 # 运行正常
x = 10
s = str(x) # 需要显式转换</code></pre>
<div class="code-result success">运行时类型可变</div>
</div>
</div>
</div>
<div class="conversion-demo">
<div class="demo-title">类型转换演示</div>
<div class="conversion-tabs">
<button
v-for="lang in languages"
:key="lang.name"
:class="['tab-btn', { active: activeLang === lang.name }]"
@click="activeLang = lang.name"
>{{ lang.name }}</button>
</div>
<div class="conversion-content" v-if="currentLang">
<div class="conversion-item" v-for="(item, i) in currentLang.conversions" :key="i">
<code class="code-expr">{{ item.expr }}</code>
<span class="arrow"></span>
<code class="code-result" :class="{ error: item.error }">{{ item.result }}</code>
<span class="explanation">{{ item.explain }}</span>
</div>
</div>
</div>
<div class="type-inference">
<div class="demo-title">类型推断</div>
<div class="inference-examples">
<div class="inference-item" v-for="(example, i) in inferenceExamples" :key="i">
<div class="inference-lang">{{ example.lang }}</div>
<code class="inference-code">{{ example.code }}</code>
<div class="inference-result">推断为: <span class="type">{{ example.type }}</span></div>
</div>
</div>
</div>
<div class="type-benefits">
<div class="benefits-title">类型系统的好处</div>
<div class="benefits-grid">
<div class="benefit-item" v-for="(b, i) in benefits" :key="i">
<span class="benefit-icon">{{ b.icon }}</span>
<span class="benefit-name">{{ b.name }}</span>
<span class="benefit-desc">{{ b.desc }}</span>
</div>
</div>
</div>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>类型系统是编程语言的"交通规则"帮助我们在编译期或运行时发现错误静态类型在编译期检查动态类型在运行时检查强类型不允许隐式转换弱类型允许
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeLang = ref('JavaScript')
const languages = [
{
name: 'JavaScript',
conversions: [
{ expr: '"1" + 1', result: '"11"', explain: '字符串拼接', error: false },
{ expr: '"1" - 1', result: '0', explain: '自动转数字', error: false },
{ expr: '[] + []', result: '""', explain: '空数组转空字符串', error: false },
{ expr: '[] + {}', result: '"[object Object]"', explain: '对象转字符串', error: false },
{ expr: 'true + true', result: '2', explain: '布尔转数字', error: false }
]
},
{
name: 'Python',
conversions: [
{ expr: '"1" + 1', result: 'TypeError', explain: '不允许隐式转换', error: true },
{ expr: '"1" + str(1)', result: '"11"', explain: '显式转换', error: false },
{ expr: 'int("1") + 1', result: '2', explain: '显式转换', error: false },
{ expr: 'True + True', result: '2', explain: '布尔是整数子类', error: false },
{ expr: '[1] + [2]', result: '[1, 2]', explain: '列表拼接', error: false }
]
},
{
name: 'Java',
conversions: [
{ expr: '"1" + 1', result: '"11"', explain: '字符串拼接(特殊规则)', error: false },
{ expr: '(String) 1', result: '编译错误', explain: '不允许转换', error: true },
{ expr: '(int) 1.5', result: '1', explain: '强制类型转换', error: false },
{ expr: 'Integer.parseInt("1")', result: '1', explain: '显式解析', error: false }
]
},
{
name: 'Rust',
conversions: [
{ expr: '"1".to_string() + "1"', result: '"11"', explain: '字符串拼接', error: false },
{ expr: '"1".parse::<i32>()', result: 'Ok(1)', explain: '显式解析', error: false },
{ expr: '1_i32 + 1_i64', result: '编译错误', explain: '类型不匹配', error: true },
{ expr: '1 as f64', result: '1.0', explain: '显式转换', error: false }
]
}
]
const currentLang = computed(() => {
return languages.find(l => l.name === activeLang.value)
})
const inferenceExamples = [
{ lang: 'TypeScript', code: 'let x = 1', type: 'number' },
{ lang: 'TypeScript', code: 'let arr = [1, 2, 3]', type: 'number[]' },
{ lang: 'Rust', code: 'let x = 1', type: 'i32 (默认整数类型)' },
{ lang: 'Rust', code: 'let s = "hello"', type: '&str (字符串切片)' },
{ lang: 'Haskell', code: 'x = 1', type: 'Num a => a (多态)' },
{ lang: 'C++ (auto)', code: 'auto x = 1', type: 'int' }
]
const benefits = [
{ icon: '🐛', name: '错误检测', desc: '在编译期发现类型错误' },
{ icon: '📖', name: '文档作用', desc: '类型签名即文档' },
{ icon: '🔧', name: 'IDE 支持', desc: '自动补全、重构' },
{ icon: '⚡', name: '性能优化', desc: '编译器可进行优化' },
{ icon: '🧩', name: '代码抽象', desc: '类型作为设计工具' },
{ icon: '🔒', name: '安全保障', desc: '避免运行时类型错误' }
]
</script>
<style scoped>
.type-system-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.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; }
.type-quadrant {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.quadrant-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.quadrant-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.quadrant-cell {
padding: 0.5rem;
border-radius: 6px;
text-align: center;
}
.strong-static { background: #d4edda; }
.weak-static { background: #fff3cd; }
.strong-dynamic { background: #cce5ff; }
.weak-dynamic { background: #f8d7da; }
.cell-label {
font-weight: bold;
font-size: 0.8rem;
margin-bottom: 0.25rem;
}
.cell-langs {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.15rem;
}
.cell-desc {
font-size: 0.7rem;
color: var(--vp-c-text-3);
}
.axis-labels {
display: flex;
justify-content: space-between;
margin-top: 0.5rem;
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.type-demo {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.demo-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.code-comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.code-block {
background: var(--vp-c-bg-alt);
border-radius: 4px;
overflow: hidden;
}
.code-label {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
background: var(--vp-c-divider);
}
pre {
margin: 0;
padding: 0.5rem;
font-size: 0.75rem;
overflow-x: auto;
}
code {
font-family: monospace;
}
.code-result {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
text-align: center;
}
.code-result.error {
background: #f8d7da;
color: #721c24;
}
.code-result.success {
background: #d4edda;
color: #155724;
}
.conversion-demo {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.conversion-tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 0.5rem;
flex-wrap: wrap;
}
.tab-btn {
padding: 0.35rem 0.6rem;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-alt);
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.conversion-content {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.conversion-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.35rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
font-size: 0.8rem;
}
.code-expr {
background: var(--vp-c-divider);
padding: 0.15rem 0.4rem;
border-radius: 3px;
font-family: monospace;
}
.arrow {
color: var(--vp-c-text-2);
}
.code-result {
background: var(--vp-c-brand-soft);
padding: 0.15rem 0.4rem;
border-radius: 3px;
font-family: monospace;
}
.code-result.error {
background: #f8d7da;
color: #721c24;
}
.explanation {
color: var(--vp-c-text-2);
font-size: 0.75rem;
}
.type-inference {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
}
.inference-examples {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.5rem;
}
.inference-item {
padding: 0.4rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
}
.inference-lang {
font-size: 0.7rem;
color: var(--vp-c-brand);
font-weight: bold;
}
.inference-code {
display: block;
font-family: monospace;
font-size: 0.8rem;
margin: 0.25rem 0;
}
.inference-result {
font-size: 0.75rem;
color: var(--vp-c-text-2);
}
.inference-result .type {
color: var(--vp-c-brand);
font-weight: bold;
}
.type-benefits {
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
}
.benefits-title {
font-weight: bold;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.benefits-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 0.5rem;
}
.benefit-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.4rem;
background: var(--vp-c-bg-alt);
border-radius: 4px;
text-align: center;
}
.benefit-icon { font-size: 1rem; }
.benefit-name { font-size: 0.8rem; font-weight: bold; }
.benefit-desc { font-size: 0.7rem; color: var(--vp-c-text-2); }
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-top: 0.75rem;
display: flex;
gap: 0.25rem;
}
.info-box .icon { flex-shrink: 0; }
@media (max-width: 640px) {
.code-comparison {
grid-template-columns: 1fr;
}
}
</style>