2026-02-06 03:34:50 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="dependency-graph-demo">
|
2026-02-13 00:36:06 +08:00
|
|
|
|
<div class="demo-header">
|
|
|
|
|
|
<span class="icon">🕸️</span>
|
|
|
|
|
|
<span class="title">依赖图谱</span>
|
|
|
|
|
|
<span class="subtitle">模块依赖关系可视化</span>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
<div class="graph-container">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<svg
|
|
|
|
|
|
class="graph-svg"
|
|
|
|
|
|
viewBox="0 0 500 300"
|
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
<defs>
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<marker
|
|
|
|
|
|
id="arrow"
|
|
|
|
|
|
markerWidth="8"
|
|
|
|
|
|
markerHeight="6"
|
|
|
|
|
|
refX="18"
|
|
|
|
|
|
refY="3"
|
|
|
|
|
|
orient="auto"
|
|
|
|
|
|
>
|
|
|
|
|
|
<polygon
|
|
|
|
|
|
points="0 0, 8 3, 0 6"
|
|
|
|
|
|
fill="var(--vp-c-text-3)"
|
|
|
|
|
|
/>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
</marker>
|
|
|
|
|
|
</defs>
|
|
|
|
|
|
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<line
|
|
|
|
|
|
v-for="edge in edges"
|
|
|
|
|
|
:key="edge.id"
|
|
|
|
|
|
:x1="getNode(edge.source).x"
|
|
|
|
|
|
:y1="getNode(edge.source).y"
|
|
|
|
|
|
:x2="getNode(edge.target).x"
|
|
|
|
|
|
:y2="getNode(edge.target).y"
|
|
|
|
|
|
stroke="var(--vp-c-text-3)"
|
|
|
|
|
|
stroke-width="1.5"
|
|
|
|
|
|
marker-end="url(#arrow)"
|
2026-02-13 00:36:06 +08:00
|
|
|
|
/>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<g
|
|
|
|
|
|
v-for="node in nodes"
|
|
|
|
|
|
:key="node.id"
|
|
|
|
|
|
:transform="`translate(${node.x}, ${node.y})`"
|
|
|
|
|
|
>
|
|
|
|
|
|
<circle
|
|
|
|
|
|
:r="node.r"
|
|
|
|
|
|
:fill="node.color"
|
|
|
|
|
|
stroke="white"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<text
|
|
|
|
|
|
y="4"
|
|
|
|
|
|
text-anchor="middle"
|
|
|
|
|
|
fill="white"
|
|
|
|
|
|
font-size="12"
|
|
|
|
|
|
>{{ node.icon }}</text>
|
|
|
|
|
|
<text
|
|
|
|
|
|
:y="node.r + 14"
|
|
|
|
|
|
text-anchor="middle"
|
|
|
|
|
|
fill="var(--vp-c-text-1)"
|
|
|
|
|
|
font-size="10"
|
|
|
|
|
|
>{{ node.name }}</text>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
</g>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
<div class="legend">
|
2026-02-18 17:38:10 +08:00
|
|
|
|
<div class="legend-item">
|
|
|
|
|
|
<span class="dot entry" />入口文件
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="legend-item">
|
|
|
|
|
|
<span class="dot module" />模块
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="legend-item">
|
|
|
|
|
|
<span class="arrow">→</span>依赖关系
|
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="info-box">
|
2026-02-13 00:36:06 +08:00
|
|
|
|
<span class="icon">💡</span>
|
|
|
|
|
|
<strong>依赖图谱的作用:</strong>就像地图一样,帮助你理解模块之间是如何相互引用的。main.js 引用了 utils、components、api,而 components 又引用了 utils——这就是依赖链。
|
2026-02-06 03:34:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-02-13 00:36:06 +08:00
|
|
|
|
import { ref } from 'vue'
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
|
|
|
|
|
const nodes = ref([
|
2026-02-13 00:36:06 +08:00
|
|
|
|
{ id: 'main', name: 'main.js', icon: '🚀', color: '#646cff', r: 22, x: 250, y: 60 },
|
|
|
|
|
|
{ id: 'utils', name: 'utils.js', icon: '🛠️', color: '#ff6b6b', r: 18, x: 100, y: 150 },
|
|
|
|
|
|
{ id: 'components', name: 'components/', icon: '🧩', color: '#4ecdc4', r: 20, x: 250, y: 150 },
|
|
|
|
|
|
{ id: 'api', name: 'api.js', icon: '🔌', color: '#ffe66d', r: 18, x: 400, y: 150 },
|
|
|
|
|
|
{ id: 'hooks', name: 'hooks.js', icon: '⚓', color: '#ff8b94', r: 16, x: 180, y: 240 },
|
|
|
|
|
|
{ id: 'config', name: 'config.js', icon: '⚙️', color: '#c7ceea', r: 14, x: 320, y: 240 }
|
2026-02-06 03:34:50 +08:00
|
|
|
|
])
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
const edges = ref([
|
|
|
|
|
|
{ id: 1, source: 'main', target: 'utils' },
|
|
|
|
|
|
{ id: 2, source: 'main', target: 'components' },
|
|
|
|
|
|
{ id: 3, source: 'main', target: 'api' },
|
|
|
|
|
|
{ id: 4, source: 'components', target: 'utils' },
|
|
|
|
|
|
{ id: 5, source: 'components', target: 'hooks' },
|
|
|
|
|
|
{ id: 6, source: 'api', target: 'config' }
|
|
|
|
|
|
])
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
|
|
|
|
|
const getNode = (id) => nodes.value.find(n => n.id === id)
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.dependency-graph-demo {
|
|
|
|
|
|
border: 1px solid var(--vp-c-divider);
|
2026-02-14 20:23:34 +08:00
|
|
|
|
border-radius: 6px;
|
2026-02-13 00:36:06 +08:00
|
|
|
|
background: var(--vp-c-bg-soft);
|
2026-02-14 20:23:34 +08:00
|
|
|
|
padding: 0.75rem;
|
|
|
|
|
|
margin: 0.5rem 0;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.demo-header {
|
2026-02-06 03:34:50 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.5rem;
|
2026-02-13 00:36:06 +08:00
|
|
|
|
margin-bottom: 1rem;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.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; }
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
|
|
|
|
|
.graph-container {
|
|
|
|
|
|
background: var(--vp-c-bg);
|
2026-02-13 00:36:06 +08:00
|
|
|
|
border-radius: 6px;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
border: 1px solid var(--vp-c-divider);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.graph-svg {
|
|
|
|
|
|
width: 100%;
|
2026-02-13 00:36:06 +08:00
|
|
|
|
height: auto;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.legend {
|
2026-02-06 03:34:50 +08:00
|
|
|
|
display: flex;
|
2026-02-13 00:36:06 +08:00
|
|
|
|
gap: 1.5rem;
|
|
|
|
|
|
margin-top: 0.75rem;
|
|
|
|
|
|
font-size: 0.8rem;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
color: var(--vp-c-text-2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.legend-item { display: flex; align-items: center; gap: 0.3rem; }
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.dot {
|
|
|
|
|
|
width: 10px;
|
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
border-radius: 50%;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.dot.entry { background: #646cff; }
|
|
|
|
|
|
.dot.module { background: #4ecdc4; }
|
|
|
|
|
|
.arrow { color: var(--vp-c-text-3); }
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
|
|
|
|
|
.info-box {
|
2026-02-13 00:36:06 +08:00
|
|
|
|
background: var(--vp-c-bg-alt);
|
2026-02-06 03:34:50 +08:00
|
|
|
|
padding: 0.75rem;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
font-size: 0.85rem;
|
|
|
|
|
|
color: var(--vp-c-text-2);
|
2026-02-13 00:36:06 +08:00
|
|
|
|
margin-top: 0.75rem;
|
2026-02-06 03:34:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 00:36:06 +08:00
|
|
|
|
.info-box .icon { margin-right: 0.25rem; }
|
2026-02-06 03:34:50 +08:00
|
|
|
|
</style>
|