Browse Source

add new

master
panda 8 months ago
parent
commit
1de8d4b460
  1. 3
      src/components/blogs/header/NavigateMenu.vue
  2. 51
      src/components/blogs/leftsite/CataloGue.vue
  3. 18
      src/stores/index.ts
  4. 160
      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 { homePageStore } from '@/stores/index';
import { useRoute } from 'vue-router';
import { useContentStore } from '@/stores';
import { HomeOutlined, HighlightOutlined, ProfileOutlined, CameraOutlined, UsergroupDeleteOutlined } from '@ant-design/icons-vue';
import type { MenuProps } from 'ant-design-vue';
const props = defineProps(["items", "updateCarouselVisibility"])
const { idShow } = homePageStore()
const { show_menu } = toRefs(idShow)
const store = useContentStore();
const searchValue = ref("")
const articleTitle = ref<string>('');
const route = useRoute()
@ -75,6 +77,7 @@ const items = ref<MenuProps['items']>([
]);
const jumpMenu = ({ key }: { key: string }) => {
router.push(`/${key}`)
store.setTitles([]);
};
watch(
() => route.name,

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

@ -1,11 +1,42 @@
<template>
</template>
<script setup lang='ts'>
</script>
<style>
</style>
<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>
<script setup lang="ts">
import { computed } from 'vue';
import { useContentStore } from '@/stores/index';
const store = useContentStore();
const titles = computed(() => store.titles);
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>

18
src/stores/index.ts

@ -11,7 +11,7 @@ export const homePageStore = defineStore("homePage", () => {
show_author: true,
show_anchornDown: true
})
return {idShow}
return { idShow }
})
export const blogStore = defineStore("blog", () => {
@ -22,19 +22,19 @@ export const blogStore = defineStore("blog", () => {
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 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;
};
}
return { blogContent, titles, setBlogContent, setTitles };
return { content,titles,setContent,setTitles };
});
export const diaryStore = defineStore("diary", () => {

160
src/views/blog/ContentDetail.vue

@ -1,100 +1,74 @@
<template>
<div class="contentDetail">
<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>
<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>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { get } from '@/tools/request';
const route = useRoute();
const props = defineProps<{
apiUrl: string;
contentField: string;
containerId: string;
}>();
const text = ref({ content: "" });
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
// Props for v-md-preview component
const previewProps = {
leftToolbar: "undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save | tip | emoji"
};
// Fetch content
const fetchContent = async () => {
try {
const response = await get(`${props.apiUrl}/${route.params.id}`);
if (response.data.data) {
text.value.content = response.data.data[props.contentField];
}
} catch (error) {
console.error("Error fetching content:", error);
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { get } from '@/tools/request';
import { useContentStore } from '@/stores';
const route = useRoute();
const store = useContentStore();
const props = defineProps<{
apiUrl: string;
contentField: string;
containerId: string;
}>();
// Props for v-md-preview component
const previewProps = {
leftToolbar: "undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save | tip | emoji"
};
// Fetch content
const fetchContent = async () => {
try {
const response = await get(`${props.apiUrl}/${route.params.id}`);
if (response.data.data) {
store.setContent(response.data.data[props.contentField]);
}
};
// Process headings after content is fetched
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 titlesArray = Array.from(anchors).filter((title: any) => !!title.innerText.trim());
if (!titlesArray.length) {
titles.value = [];
return;
}
const hTags = Array.from(new Set(titlesArray.map((title: any) => title.tagName))).sort();
titles.value = titlesArray.map((el: any) => ({
title: el.innerText,
lineIndex: el.getAttribute('data-v-md-line') || '',
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
onMounted(async () => {
await fetchContent();
await processHeadings();
});
</script>
<style scoped>
#blogDetail, #diaryDetail {
width: 45%;
margin: 0 24px;
} catch (error) {
console.error("Error fetching content:", error);
}
};
// Process headings after content is fetched
const processHeadings = async () => {
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());
if (!titlesArray.length) {
store.setTitles([]);
return;
}
</style>
const hTags = Array.from(new Set(titlesArray.map((title: any) => title.tagName))).sort();
store.setTitles(titlesArray.map((el: any) => ({
title: el.innerText,
lineIndex: el.getAttribute('data-v-md-line') || '',
indent: hTags.indexOf(el.tagName),
})));
};
// Lifecycle hook to fetch content and process headings
onMounted(async () => {
await fetchContent();
await processHeadings();
});
</script>
<style scoped>
.contentDetail {
width: 45%;
margin: 0 24px;
}
</style>
Loading…
Cancel
Save