Browse Source

add new

master
panda 8 months ago
parent
commit
1de8d4b460
  1. 3
      src/components/blogs/header/NavigateMenu.vue
  2. 39
      src/components/blogs/leftsite/CataloGue.vue
  3. 16
      src/stores/index.ts
  4. 46
      src/views/blog/ContentDetail.vue

3
src/components/blogs/header/NavigateMenu.vue

@ -11,11 +11,13 @@ import { ref, toRefs, watch, h } from 'vue';
import router from '@/router'; import router from '@/router';
import { homePageStore } from '@/stores/index'; import { homePageStore } from '@/stores/index';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useContentStore } from '@/stores';
import { HomeOutlined, HighlightOutlined, ProfileOutlined, CameraOutlined, UsergroupDeleteOutlined } from '@ant-design/icons-vue'; import { HomeOutlined, HighlightOutlined, ProfileOutlined, CameraOutlined, UsergroupDeleteOutlined } from '@ant-design/icons-vue';
import type { MenuProps } from 'ant-design-vue'; import type { MenuProps } from 'ant-design-vue';
const props = defineProps(["items", "updateCarouselVisibility"]) const props = defineProps(["items", "updateCarouselVisibility"])
const { idShow } = homePageStore() const { idShow } = homePageStore()
const { show_menu } = toRefs(idShow) const { show_menu } = toRefs(idShow)
const store = useContentStore();
const searchValue = ref("") const searchValue = ref("")
const articleTitle = ref<string>(''); const articleTitle = ref<string>('');
const route = useRoute() const route = useRoute()
@ -75,6 +77,7 @@ const items = ref<MenuProps['items']>([
]); ]);
const jumpMenu = ({ key }: { key: string }) => { const jumpMenu = ({ key }: { key: string }) => {
router.push(`/${key}`) router.push(`/${key}`)
store.setTitles([]);
}; };
watch( watch(
() => route.name, () => route.name,

39
src/components/blogs/leftsite/CataloGue.vue

@ -1,11 +1,42 @@
<template> <template>
<div>
<div class="catalogue" v-for="anchor in titles" :style="{ padding: `4px 0 4px ${anchor.indent * 20}px` }"
@click="handleAnchorClick(anchor)" :key="anchor.lineIndex">
<a style="cursor: pointer">{{ anchor.title }}</a>
</div>
</div>
</template> </template>
<script setup lang='ts'>
<script setup lang="ts">
import { computed } from 'vue';
import { useContentStore } from '@/stores/index';
</script>
const store = useContentStore();
const titles = computed(() => store.titles);
<style>
const handleAnchorClick = (anchor: { title: string; lineIndex: string }) => {
const heading = document.querySelector(`[data-v-md-line="${anchor.lineIndex}"]`);
if (heading) {
heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
} else {
const observer = new MutationObserver((mutations, obs) => {
const heading = document.querySelector(`[data-v-md-line="${anchor.lineIndex}"]`);
if (heading) {
heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
obs.disconnect();
}
});
const container = document.querySelector('#content-container') as HTMLElement;
observer.observe(container, { childList: true, subtree: true });
}
};
</script>
<style scoped>
.catalogue {
cursor: pointer;
}
</style> </style>

16
src/stores/index.ts

@ -22,19 +22,19 @@ export const blogStore = defineStore("blog", () => {
return { delControl } return { delControl }
}) })
export const useBlogStore = defineStore('catalogue', () => {
const blogContent = ref('');
export const useContentStore = defineStore('content', () => {
const content = ref({ text: "" });
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]); const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
const setBlogContent = (content: string) => {
blogContent.value = content;
};
function setContent(newContent: string) {
content.value.text = newContent;
}
const setTitles = (newTitles: { title: string; lineIndex: string; indent: number }[]) => {
function setTitles(newTitles: { title: string; lineIndex: string; indent: number }[]) {
titles.value = newTitles; titles.value = newTitles;
};
}
return { blogContent, titles, setBlogContent, setTitles };
return { content,titles,setContent,setTitles };
}); });
export const diaryStore = defineStore("diary", () => { export const diaryStore = defineStore("diary", () => {

46
src/views/blog/ContentDetail.vue

@ -1,21 +1,21 @@
<template> <template>
<div class="contentDetail">
<div :id="containerId"> <div :id="containerId">
<div v-for="anchor in titles" :style="{ padding: `4px 0 4px ${anchor.indent * 20}px` }"
@click="handleAnchorClick(anchor)" :key="anchor.lineIndex">
<a style="cursor: pointer">{{ anchor.title }}</a>
</div>
<a-card> <a-card>
<v-md-preview v-if="text.content" :text="text.content" v-bind="previewProps" />
<v-md-preview v-if="store.content.text" :text="store.content.text" v-bind="previewProps" />
</a-card> </a-card>
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'; import { ref, onMounted, nextTick } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { get } from '@/tools/request'; import { get } from '@/tools/request';
import { useContentStore } from '@/stores';
const route = useRoute(); const route = useRoute();
const store = useContentStore();
const props = defineProps<{ const props = defineProps<{
apiUrl: string; apiUrl: string;
@ -23,10 +23,6 @@
containerId: string; containerId: string;
}>(); }>();
const text = ref({ content: "" });
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
// Props for v-md-preview component // Props for v-md-preview component
const previewProps = { const previewProps = {
leftToolbar: "undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save | tip | emoji" leftToolbar: "undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save | tip | emoji"
@ -37,7 +33,7 @@
try { try {
const response = await get(`${props.apiUrl}/${route.params.id}`); const response = await get(`${props.apiUrl}/${route.params.id}`);
if (response.data.data) { if (response.data.data) {
text.value.content = response.data.data[props.contentField];
store.setContent(response.data.data[props.contentField]);
} }
} catch (error) { } catch (error) {
console.error("Error fetching content:", error); console.error("Error fetching content:", error);
@ -46,42 +42,21 @@
// Process headings after content is fetched // Process headings after content is fetched
const processHeadings = async () => { const processHeadings = async () => {
await nextTick();
const anchors = document.querySelectorAll(`#${props.containerId} h1, #${props.containerId} h2, #${props.containerId} h3, #${props.containerId} h4, #${props.containerId} h5, #${props.containerId} h6`); const anchors = document.querySelectorAll(`#${props.containerId} h1, #${props.containerId} h2, #${props.containerId} h3, #${props.containerId} h4, #${props.containerId} h5, #${props.containerId} h6`);
const titlesArray = Array.from(anchors).filter((title: any) => !!title.innerText.trim()); const titlesArray = Array.from(anchors).filter((title: any) => !!title.innerText.trim());
if (!titlesArray.length) { if (!titlesArray.length) {
titles.value = [];
store.setTitles([]);
return; return;
} }
const hTags = Array.from(new Set(titlesArray.map((title: any) => title.tagName))).sort(); const hTags = Array.from(new Set(titlesArray.map((title: any) => title.tagName))).sort();
titles.value = titlesArray.map((el: any) => ({
store.setTitles(titlesArray.map((el: any) => ({
title: el.innerText, title: el.innerText,
lineIndex: el.getAttribute('data-v-md-line') || '', lineIndex: el.getAttribute('data-v-md-line') || '',
indent: hTags.indexOf(el.tagName), indent: hTags.indexOf(el.tagName),
}));
};
// Handle anchor click
const handleAnchorClick = (anchor: { title: string; lineIndex: string }) => {
const heading = document.querySelector(`#${props.containerId} [data-v-md-line="${anchor.lineIndex}"]`);
if (heading) {
heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
} else {
// Use MutationObserver to wait for the target element to be available
const observer = new MutationObserver((mutations, obs) => {
const heading = document.querySelector(`#${props.containerId} [data-v-md-line="${anchor.lineIndex}"]`);
if (heading) {
heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
obs.disconnect(); // Stop observing once the target element is found
}
});
const container = document.querySelector(`#${props.containerId}`) as HTMLElement;
observer.observe(container, { childList: true, subtree: true });
}
})));
}; };
// Lifecycle hook to fetch content and process headings // Lifecycle hook to fetch content and process headings
@ -92,9 +67,8 @@
</script> </script>
<style scoped> <style scoped>
#blogDetail, #diaryDetail {
.contentDetail {
width: 45%; width: 45%;
margin: 0 24px; margin: 0 24px;
} }
</style> </style>
Loading…
Cancel
Save