You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
5.2 KiB
189 lines
5.2 KiB
<template>
|
|
<div>
|
|
<div
|
|
v-for="anchor in titles"
|
|
:style="{ padding: `10px 0 10px ${anchor.indent}px` }"
|
|
@click="handleAnchorClick(anchor)"
|
|
:key="anchor.lineIndex"
|
|
>
|
|
<a style="cursor: pointer">{{ anchor.title }}</a>
|
|
</div>
|
|
<v-md-preview :text="text" ref="preview" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
const text = `
|
|
# heading 1
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
|
|
## heading 2
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
|
|
### heading 3
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontentcontentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
contentcontentcontent
|
|
|
|
|
|
`;
|
|
|
|
const preview = ref<any>(null);
|
|
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
|
|
|
|
onMounted(() => {
|
|
const anchors = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
const titlesArray = Array.from(anchors).filter((title) => !!title.innerText.trim());
|
|
|
|
if (!titlesArray.length) {
|
|
titles.value = [];
|
|
return;
|
|
}
|
|
|
|
const hTags = Array.from(new Set(titlesArray.map((title) => title.tagName))).sort();
|
|
|
|
titles.value = titlesArray.map((el) => ({
|
|
title: el.innerText,
|
|
lineIndex: el.getAttribute('data-v-md-line') || '', // 确认属性名是否正确
|
|
indent: 20 * (parseInt(el.tagName.substring(1)) - 1) // 确认缩进计算是否正确
|
|
}));
|
|
});
|
|
|
|
function handleAnchorClick(anchor: { title: string; lineIndex: string }) {
|
|
if (preview.value) {
|
|
const heading = preview.value.$el.querySelector(`[data-v-md-line="${anchor.lineIndex}"]`);
|
|
|
|
if (heading) {
|
|
preview.value.scrollToTarget({
|
|
target: heading,
|
|
scrollContainer: window,
|
|
top: 60,
|
|
});
|
|
} else {
|
|
console.error(`Heading element not found for lineIndex: ${anchor.lineIndex}`);
|
|
}
|
|
} else {
|
|
console.error('Preview component not initialized.');
|
|
}
|
|
}
|
|
</script>
|