2026-02-18 15:52:55 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="transmission-demo">
|
|
|
|
|
|
<div class="demo-header">
|
|
|
|
|
|
<span class="title">数据传输:从串行到并行</span>
|
|
|
|
|
|
<span class="subtitle">数据如何在不同设备间移动</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="demo-content">
|
|
|
|
|
|
<div class="transmission-types">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<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">
|
|
|
|
|
|
USB、SATA、PCIe
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<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>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="transmission-visual">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div class="visual-title">
|
|
|
|
|
|
{{ activeType === 'serial' ? '串行传输示意' : '并行传输示意' }}
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
<div class="visual-area">
|
|
|
|
|
|
<div class="sender">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div class="device-label">
|
|
|
|
|
|
发送端
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
<div class="data-bits">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<span
|
|
|
|
|
|
v-for="(bit, i) in dataBits"
|
|
|
|
|
|
:key="i"
|
|
|
|
|
|
class="bit"
|
|
|
|
|
|
:class="{ sending: sendingBit === i && activeType === 'serial' }"
|
|
|
|
|
|
>{{ bit }}</span>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="channels">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div
|
|
|
|
|
|
v-if="activeType === 'serial'"
|
|
|
|
|
|
class="channel serial"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="channel-label">
|
|
|
|
|
|
单通道
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
<div class="channel-flow">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<span
|
|
|
|
|
|
v-for="i in 5"
|
|
|
|
|
|
:key="i"
|
|
|
|
|
|
class="flow-dot"
|
|
|
|
|
|
:class="{ active: sendingBit !== null }"
|
|
|
|
|
|
>●</span>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div
|
|
|
|
|
|
v-else
|
|
|
|
|
|
class="channel parallel"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="i in 4"
|
|
|
|
|
|
:key="i"
|
|
|
|
|
|
class="channel-row"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="channel-label">
|
|
|
|
|
|
通道{{ i }}
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
<div class="channel-flow">
|
|
|
|
|
|
<span class="flow-dot active">●</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="receiver">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div class="device-label">
|
|
|
|
|
|
接收端
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
<div class="data-bits received">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<span
|
|
|
|
|
|
v-for="(bit, i) in receivedBits"
|
|
|
|
|
|
:key="i"
|
|
|
|
|
|
class="bit"
|
|
|
|
|
|
>{{ bit }}</span>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<button
|
|
|
|
|
|
class="send-btn"
|
|
|
|
|
|
@click="startTransmission"
|
|
|
|
|
|
>
|
|
|
|
|
|
发送数据
|
|
|
|
|
|
</button>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="comparison-table">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div class="table-title">
|
|
|
|
|
|
串行 vs 并行对比
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
<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>主流(USB、PCIe)</td>
|
|
|
|
|
|
<td>较少</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="info-box">
|
|
|
|
|
|
<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 .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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
</style>
|