半加器作为数字电路中最基础的加法单元,是理解计算机运算原理的重要起点。这个项目通过纯HTML+CSS+JavaScript实现了一个可视化半加器演示页面,无需任何后端支持即可在浏览器中直观展示二进制加法的底层逻辑。我在设计电子技术在线课程时发现,传统教材中的逻辑门符号和真值表对初学者不够友好,于是萌生了用网页动态演示的想法。
这个演示工具特别适合三类人群:计算机体系结构初学者、数字电路自学者、以及需要向学生讲解加法器原理的教师。通过交互式操作,用户可以点击输入开关切换A/B端状态,实时观察求和位(Sum)和进位位(Carry)的变化,比静态图示更容易建立直观认知。所有代码仅需一个HTML文件即可运行,兼容现代主流浏览器。
半加器的核心功能是实现两个1位二进制数的相加,其输出包含两个部分:
用布尔代数表示为:
code复制Sum = A ⊕ B
Carry = A · B
在电路实现上,最简方案只需要两个逻辑门:
注意:虽然可以用更基础的与非门组合实现,但教学演示建议直接使用标准逻辑门符号,避免增加初学者的认知负担。
传统真值表在网页中的创新呈现方式:
| 输入A | 输入B | Sum (LED颜色) | Carry (LED颜色) |
|---|---|---|---|
| 0 | 0 | 灭(灰色) | 灭(灰色) |
| 0 | 1 | 亮(绿色) | 灭(灰色) |
| 1 | 0 | 亮(绿色) | 灭(灰色) |
| 1 | 1 | 灭(灰色) | 亮(红色) |
在实现时,我们通过CSS的filter: brightness()属性模拟LED灯亮灭效果,用颜色编码区分不同状态:
html复制<!DOCTYPE html>
<html>
<head>
<title>半加器原理演示</title>
<style>
.gate { width: 80px; height: 60px; }
.led-off { filter: brightness(0.3); }
.sum-led { background-color: #00ff00; }
.carry-led { background-color: #ff0000; }
.switch { cursor: pointer; }
</style>
</head>
<body>
<div id="inputs">
<img id="switchA" class="switch" src="switch-off.png" onclick="toggleInput('A')">
<img id="switchB" class="switch" src="switch-off.png" onclick="toggleInput('B')">
</div>
<div id="circuit">
<img src="xor-gate.png" class="gate">
<img src="and-gate.png" class="gate">
</div>
<div id="outputs">
<div id="sumLed" class="led-off sum-led"></div>
<div id="carryLed" class="led-off carry-led"></div>
</div>
<script>
// 状态变量
let inputA = false, inputB = false;
function toggleInput(type) {
// 切换输入状态并更新UI
}
function updateOutputs() {
// 根据输入状态计算并显示输出
}
</script>
</body>
</html>
JavaScript核心代码解析:
javascript复制function toggleInput(type) {
// 切换开关状态
if (type === 'A') {
inputA = !inputA;
document.getElementById('switchA').src = inputA ? 'switch-on.png' : 'switch-off.png';
} else {
inputB = !inputB;
document.getElementById('switchB').src = inputB ? 'switch-on.png' : 'switch-off.png';
}
updateOutputs();
}
function updateOutputs() {
const sumLed = document.getElementById('sumLed');
const carryLed = document.getElementById('carryLed');
// 计算输出状态
const sumState = inputA !== inputB; // XOR运算
const carryState = inputA && inputB; // AND运算
// 更新LED显示
sumLed.className = sumState ? 'sum-led' : 'led-off sum-led';
carryLed.className = carryState ? 'carry-led' : 'led-off carry-led';
}
逻辑门图标:
开关动画:
css复制.switch {
transition: transform 0.2s;
}
.switch:active {
transform: translateY(2px);
}
通过CSS过渡实现点击反馈
LED发光效果:
css复制.sum-led {
box-shadow: 0 0 10px #00ff00;
transition: filter 0.3s, box-shadow 0.3s;
}
在基础功能上增加教学模式:
javascript复制let demoStep = 0;
const demoSequence = [
{A:0, B:0}, {A:0, B:1},
{A:1, B:0}, {A:1, B:1}
];
function nextStep() {
if (demoStep >= demoSequence.length) return;
const step = demoSequence[demoStep++];
inputA = step.A;
inputB = step.B;
// 更新UI...
}
使用CSS动画展示信号流动:
css复制@keyframes signalFlow {
from { stroke-dashoffset: 100; }
to { stroke-dashoffset: 0; }
}
.signal-path {
stroke-dasharray: 100;
animation: signalFlow 1s linear;
}
针对触摸设备优化:
javascript复制document.getElementById('switchA').addEventListener('touchstart', function(e) {
e.preventDefault();
toggleInput('A');
});
现象:点击开关后输出LED状态不符合真值表
排查步骤:
updateOutputs()函数被正确调用javascript复制console.log(`A:${inputA}, B:${inputB}, Sum:${sumState}, Carry:${carryState}`);
现象:图片无法显示或位置错乱
解决方案:
html复制<img src="xor-gate.png" onerror="this.src='fallback-gate.svg'">
css复制#circuit {
position: relative;
height: 120px;
}
.gate {
position: absolute;
top: 0;
}
#xorGate { left: 50px; }
#andGate { left: 180px; }
图片预加载:
javascript复制window.onload = function() {
[ 'switch-on.png', 'switch-off.png', 'xor-gate.png' ].forEach(url => {
new Image().src = url;
});
};
减少DOM操作:
javascript复制// 缓存DOM引用
const elements = {
switchA: document.getElementById('switchA'),
sumLed: document.getElementById('sumLed')
};
在现有基础上增加进位输入:
javascript复制// 全加器逻辑
function fullAdder(A, B, Cin) {
const sum1 = A ^ B;
const sum = sum1 ^ Cin;
const carry = (A & B) || (sum1 & Cin);
return { sum, carry };
}
使用Canvas绘制可拖拽逻辑门:
javascript复制class LogicGate {
constructor(type, x, y) {
this.type = type; // 'AND'/'OR'/'XOR'
this.x = x;
this.y = y;
}
draw(ctx) {
// 绘制逻辑门图形
}
}
打包为Web Component:
javascript复制class HalfAdderDemo extends HTMLElement {
constructor() {
super();
// 挂载Shadow DOM
}
}
customElements.define('half-adder-demo', HalfAdderDemo);
我在实际开发中发现,给逻辑门添加tooltip说明能显著提升教学效果。通过title属性或专门的提示框组件,当鼠标悬停在逻辑门上时显示其真值表和布尔表达式,这种即时参考对学习者非常友好。另一个实用技巧是添加音频反馈——用不同音调表示Sum和Carry的触发,多感官刺激能加强记忆。