Files
test-repo/docs/.vitepress/theme/components/appendix/computer-fundamentals/HalfAdderDemo.vue
T
2026-02-23 12:09:47 +08:00

457 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="half-adder-demo">
<div class="demo-header">
<span class="title">半加器 (Half Adder)</span>
<span class="subtitle">最基础的二进制加法单元 只能处理两个 1 位输入</span>
</div>
<div class="terms-box">
<div class="term-item">
<span class="term-name">本位 (Sum)</span>
<span class="term-desc">当前位的计算结果不考虑外部进位</span>
</div>
<div class="term-item">
<span class="term-name">进位 (Carry)</span>
<span class="term-desc">当两位都是 1 向更高位"借位"</span>
</div>
</div>
<div class="circuit-container">
<div class="inputs">
<div class="input-line">
<button
class="toggle-btn"
:class="{ on: inputA }"
@click="inputA = !inputA"
>
{{ inputA ? '1' : '0' }}
</button>
<span class="label">输入 A</span>
</div>
<div class="input-line">
<button
class="toggle-btn"
:class="{ on: inputB }"
@click="inputB = !inputB"
>
{{ inputB ? '1' : '0' }}
</button>
<span class="label">输入 B</span>
</div>
</div>
<div class="wires">
<svg class="wire-svg" viewBox="0 0 100 150" preserveAspectRatio="none">
<path
d="M 0,30 C 50,30 50,40 100,40"
fill="none"
:stroke="inputA ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<path
d="M 0,120 C 50,120 50,60 100,60"
fill="none"
:stroke="inputB ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<path
d="M 20,30 L 20,90 C 20,90 50,90 100,90"
fill="none"
:stroke="inputA ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<path
d="M 40,120 L 40,110 C 40,110 50,110 100,110"
fill="none"
:stroke="inputB ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
<circle
cx="20"
cy="30"
r="3"
:fill="inputA ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
/>
<circle
cx="40"
cy="120"
r="3"
:fill="inputB ? 'var(--vp-c-brand-1)' : 'var(--vp-c-text-3)'"
/>
</svg>
</div>
<div class="gates">
<div class="gate-box xor-gate" :class="{ active: sumOut }">
<div class="gate-header">
<span class="gate-name">XOR</span>
<span class="gate-cn">异或门</span>
</div>
<div class="gate-formula">A B</div>
<div class="gate-desc">不同为 1 本位</div>
</div>
<div class="gate-box and-gate" :class="{ active: carryOut }">
<div class="gate-header">
<span class="gate-name">AND</span>
<span class="gate-cn">与门</span>
</div>
<div class="gate-formula">A B</div>
<div class="gate-desc"> 1 1 进位</div>
</div>
</div>
<div class="wires outputs-wires">
<svg class="wire-svg" viewBox="0 0 50 150" preserveAspectRatio="none">
<line
x1="0"
y1="50"
x2="50"
y2="50"
:stroke="
sumOut ? 'var(--vp-c-green-1, #16a34a)' : 'var(--vp-c-text-3)'
"
stroke-width="2"
/>
<line
x1="0"
y1="100"
x2="50"
y2="100"
:stroke="carryOut ? '#d97706' : 'var(--vp-c-text-3)'"
stroke-width="2"
/>
</svg>
</div>
<div class="outputs">
<div class="output-line" :class="{ active: sumOut }">
<span class="label">本位 (Sum)</span>
<span class="out-val s-val">{{ sumOut ? '1' : '0' }}</span>
</div>
<div class="output-line" :class="{ active: carryOut }">
<span class="label">进位 (Carry)</span>
<span class="out-val c-val">{{ carryOut ? '1' : '0' }}</span>
</div>
</div>
</div>
<div class="calculation-box">
<div class="calc-title">计算过程</div>
<div class="calc-content">
<div class="calc-row">
<span class="calc-label">输入</span>
<span class="calc-value">A = {{ inputA ? '1' : '0' }}B = {{ inputB ? '1' : '0' }}</span>
</div>
<div class="calc-row">
<span class="calc-label">本位</span>
<span class="calc-formula">A B = {{ inputA ? '1' : '0' }} {{ inputB ? '1' : '0' }} =
<strong>{{ sumOut ? '1' : '0' }}</strong></span>
<span class="calc-reason">{{ inputA !== inputB ? '不同' : '相同' }}</span>
</div>
<div class="calc-row">
<span class="calc-label">进位</span>
<span class="calc-formula">A B = {{ inputA ? '1' : '0' }} {{ inputB ? '1' : '0' }} =
<strong>{{ carryOut ? '1' : '0' }}</strong></span>
<span class="calc-reason">{{ inputA && inputB ? '全为 1' : '不全为 1' }}</span>
</div>
</div>
</div>
<div class="info-box">
<strong>核心思想</strong>
半加器用 XOR "本位和" AND
"进位"它是最小的加法单元但无法处理来自低位的进位
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const inputA = ref(false)
const inputB = ref(true)
const sumOut = computed(() => inputA.value !== inputB.value)
const carryOut = computed(() => inputA.value && inputB.value)
</script>
<style scoped>
.half-adder-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem 1.2rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
flex-direction: column;
gap: 0.15rem;
margin-bottom: 0.75rem;
}
.title {
font-size: 0.9rem;
font-weight: bold;
color: var(--vp-c-text-1);
}
.subtitle {
font-size: 0.75rem;
color: var(--vp-c-text-3);
}
.terms-box {
display: flex;
gap: 0.5rem;
margin-bottom: 0.75rem;
padding: 0.5rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
}
.term-item {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.15rem;
}
.term-name {
font-size: 0.78rem;
font-weight: 600;
color: var(--vp-c-brand-1);
}
.term-desc {
font-size: 0.68rem;
color: var(--vp-c-text-3);
line-height: 1.3;
}
.circuit-container {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
padding: 1rem;
overflow-x: auto;
}
.inputs,
.outputs {
display: flex;
flex-direction: column;
gap: 3.5rem;
min-width: 6rem;
z-index: 2;
}
.outputs {
min-width: 8rem;
}
.input-line,
.output-line {
display: flex;
align-items: center;
gap: 0.5rem;
}
.label {
font-size: 0.8rem;
color: var(--vp-c-text-1);
}
.toggle-btn {
width: 2.2rem;
height: 2.2rem;
border-radius: 4px;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
font-weight: bold;
font-family: monospace;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
}
.toggle-btn.on {
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand-1);
border-color: var(--vp-c-brand-1);
}
.out-val {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.2rem;
height: 2.2rem;
border-radius: 4px;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
font-weight: bold;
font-family: monospace;
font-size: 1rem;
transition: all 0.2s;
}
.output-line.active .s-val {
background: #dcfce7;
color: #16a34a;
border-color: #16a34a;
}
.output-line.active .c-val {
background: #fef3c7;
color: #d97706;
border-color: #d97706;
}
.wires {
width: 80px;
height: 150px;
position: relative;
}
.outputs-wires {
width: 40px;
}
.wire-svg {
width: 100%;
height: 100%;
}
.gates {
display: flex;
flex-direction: column;
gap: 1.5rem;
z-index: 2;
margin-top: 5px;
}
.gate-box {
width: 7.5rem;
height: 4rem;
background: var(--vp-c-bg-alt);
border: 2px solid var(--vp-c-divider);
border-radius: 4px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.2s;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.gate-box.active {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 8px var(--vp-c-brand-soft);
}
.gate-header {
display: flex;
align-items: baseline;
gap: 0.25rem;
}
.gate-name {
font-weight: bold;
font-size: 0.9rem;
color: var(--vp-c-text-1);
}
.gate-cn {
font-size: 0.7rem;
color: var(--vp-c-text-3);
}
.gate-formula {
font-size: 0.75rem;
color: var(--vp-c-brand-1);
font-family: 'JetBrains Mono', monospace;
}
.gate-desc {
font-size: 0.65rem;
color: var(--vp-c-text-3);
margin-top: 0.15rem;
}
.calculation-box {
margin-top: 1rem;
padding: 0.6rem 0.8rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.calc-title {
font-size: 0.75rem;
font-weight: 600;
color: var(--vp-c-text-2);
margin-bottom: 0.4rem;
}
.calc-content {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.calc-row {
display: flex;
align-items: baseline;
gap: 0.3rem;
font-size: 0.78rem;
}
.calc-label {
color: var(--vp-c-text-3);
min-width: 3.5rem;
}
.calc-formula {
font-family: 'JetBrains Mono', monospace;
color: var(--vp-c-text-1);
}
.calc-formula strong {
color: var(--vp-c-brand-1);
}
.calc-reason {
color: var(--vp-c-text-3);
font-size: 0.72rem;
}
.info-box {
display: flex;
gap: 0.25rem;
margin-top: 0.75rem;
padding: 0.6rem 0.8rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.info-box strong {
white-space: nowrap;
flex-shrink: 0;
color: var(--vp-c-text-1);
}
@media (max-width: 600px) {
.circuit-container {
transform: scale(0.85);
transform-origin: left top;
padding-bottom: 0;
}
.terms-box {
flex-direction: column;
}
}
</style>