feat: 文档图片可放大

This commit is contained in:
zouzhiwen 2026-06-02 15:28:23 +08:00
parent 934f7f79a6
commit 3630f18551
1 changed files with 33 additions and 2 deletions

View File

@ -58,12 +58,19 @@
</div> </div>
</aside> </aside>
<main v-loading="loading" class="docs-main"> <main v-loading="loading" class="docs-main" @click="handleArticleClick">
<div v-if="loadError" class="docs-error"> <div v-if="loadError" class="docs-error">
<el-empty :description="loadError" /> <el-empty :description="loadError" />
</div> </div>
<article v-else class="docs-article" v-html="renderedHtml" /> <article v-else class="docs-article" v-html="renderedHtml" />
</main> </main>
<el-image-viewer
v-if="previewVisible"
:url-list="previewUrls"
:initial-index="previewIndex"
hide-on-click-modal
@close="previewVisible = false"
/>
</div> </div>
</template> </template>
@ -96,6 +103,9 @@ const loadError = ref('')
const keyword = ref('') const keyword = ref('')
const toc = ref<TocItem[]>([]) const toc = ref<TocItem[]>([])
const searchSections = ref<SearchSection[]>([]) const searchSections = ref<SearchSection[]>([])
const previewVisible = ref(false)
const previewIndex = ref(0)
const previewUrls = computed(() => extractImageUrls(rawMarkdown.value, activeDocPath.value))
const renderedHtml = computed(() => renderMarkdown(rawMarkdown.value, activeDocPath.value)) const renderedHtml = computed(() => renderMarkdown(rawMarkdown.value, activeDocPath.value))
const level3Toc = computed(() => toc.value.filter((item) => item.level === 3)) const level3Toc = computed(() => toc.value.filter((item) => item.level === 3))
@ -221,7 +231,7 @@ function renderMarkdown(markdown: string, docPath: string) {
if (image) { if (image) {
const alt = escapeHtml(image[1]) const alt = escapeHtml(image[1])
const src = escapeHtml(resolveDocAsset(docPath, image[2])) const src = escapeHtml(resolveDocAsset(docPath, image[2]))
html.push(`<figure><img src="${src}" alt="${alt}" loading="lazy" /><figcaption>${alt}</figcaption></figure>`) html.push(`<figure><img class="doc-preview-image" src="${src}" alt="${alt}" loading="lazy" data-preview-src="${src}" /><figcaption>${alt}</figcaption></figure>`)
return return
} }
@ -243,6 +253,14 @@ function resolveDocAsset(docPath: string, assetPath: string) {
return `${getDocsBase()}${encodeURI(normalized)}` return `${getDocsBase()}${encodeURI(normalized)}`
} }
function extractImageUrls(markdown: string, docPath: string) {
return markdown
.split('\n')
.map((line) => /^!\[[^\]]*]\(([^)]+)\)$/.exec(line.trim())?.[1])
.filter((src): src is string => Boolean(src))
.map((src) => resolveDocAsset(docPath, src))
}
function buildHeadingId(text: string, counters: Map<string, number>) { function buildHeadingId(text: string, counters: Map<string, number>) {
const base = text const base = text
.toLowerCase() .toLowerCase()
@ -282,6 +300,15 @@ function jumpTo(id: string) {
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' }) document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}) })
} }
function handleArticleClick(event: MouseEvent) {
const target = event.target
if (!(target instanceof HTMLImageElement)) return
const src = target.dataset.previewSrc
if (!src) return
previewIndex.value = Math.max(previewUrls.value.indexOf(src), 0)
previewVisible.value = true
}
</script> </script>
<style scoped> <style scoped>
@ -511,6 +538,10 @@ function jumpTo(id: string) {
background: #f5f7fa; background: #f5f7fa;
} }
:deep(.docs-article .doc-preview-image) {
cursor: zoom-in;
}
:deep(.docs-article figcaption) { :deep(.docs-article figcaption) {
margin-top: 8px; margin-top: 8px;
color: #909399; color: #909399;