feat: 优化md渲染相关逻辑,优化文章页面

This commit is contained in:
539943419 committed 2025-03-24 12:31:43 +08:00
1 parent e0d967f736
commit 370ec61f3d
5 files changed
+112 -95

No files matched your search

+4 -14
View File
@@ -25,32 +25,22 @@ const VNodeArr = computed(() => {
return () => []
}
const renderedData = markdownIt.render(props.data)
console.log({
renderedData
})
const h2v = new Html2VNode()
h2v.use(
{
filter(tagName) {
return tagName === 'code'
},
rander({
render({
item,
// tagName,
tagAttrs,
// middlewareMap
}) {
// console.log({
// tagName,
// tagAttrs,
// })
const codeType = tagAttrs?.class?.slice(1, -1)?.split('-')?.[1] ?? ''
// console.log({
// codeType,
// })
// @ts-ignore
const inline = (item.children[0].children.trim() as string).includes('\n') ? false : true
console.log({
inline,
c: item.children
})
return h(
codeMirror,
{
+20 -23
View File
@@ -1,6 +1,6 @@
<template>
<div class="posts-wrapper">
<article class="posts-item" v-for="post in postsData" :key="post.id">
<article class="posts-item" v-for="post in posts" :key="post.id">
<header class="post-title">
<nuxt-link :to="`/posts/post-${post.id}`">{{ post.title }}</nuxt-link>
</header>
@@ -18,7 +18,7 @@
</div>
</footer>
</article>
<div class="posts-skeleton" v-if="!isInit">
<div class="posts-skeleton" v-if="pending">
<div class="posts-skeleton-item" v-for="_ in range(5)">
<el-skeleton :rows="3" />
</div>
@@ -33,29 +33,26 @@ import bookmark from '~/components/icons/tag.vue'
import type { postItem } from '~/types/post';
const store = useDefaultStore()
const isInit = ref(false)
const postsData = ref<postItem[]>([])
const getData = async () => {
const cache = store.getCache('posts')
if (cache) {
return cache as postItem[]
}
const response = await $fetch('/api/posts/getPostList')
const res = response.data
store.setCache('posts', res)
return res
}
onMounted(async () => {
// router.push('/posts/temp')
// await sleep(1000)
postsData.value = await getData()
isInit.value = true;
// console.log(postsData.value)
// 使用useFetch在服务器端获取数据
const { data, pending } = await useFetch<{ code: number, data: postItem[] }>('/api/posts/getPostList', {
// 如果缓存中已有数据,优先使用缓存
key: 'posts-list',
transform: (response) => {
if (response && response.data) {
store.setCache('posts', response.data)
return response
}
return { code: 0, data: [] }
},
// 添加以下选项
lazy: true, // 避免客户端自动重新获取
server: true, // 仅在服务器端获取数据
// cache: 'force-cache', // 强制使用缓存
// dedupe: 'force', // 强制使用缓存的数据
})
// 从响应中提取文章列表
const posts = computed(() => data.value?.data || []) as ComputedRef<postItem[]>
</script>
<style lang="scss" scoped>
+33 -45
View File
@@ -1,9 +1,9 @@
<template>
<div class="md-wrapper">
<div class="md" v-if="isInit">
<div class="md-title">{{ title }}</div>
<div class="md" v-if="postData">
<div class="md-title">{{ postData.title }}</div>
<div class="md-divider"></div>
<markdown-render :data="content"></markdown-render>
<markdown-render :data="postData.content"></markdown-render>
</div>
<div v-else class="md-skeleton-item">
<el-skeleton :rows="12" />
@@ -18,55 +18,43 @@ import markdownRender from '~/components/markdownRender.vue';
import type { postContent } from '~/types/post';
const postStore = usePostStore()
const route = useRoute()
const isInit = ref(false)
const title = ref('')
const content = ref('')
const renderedData = ref('')
const id = route.params.id as string
onMounted(async () => {
// 使用useFetch来获取文章内容,支持SSR
const { data: fetchedPost } = await useFetch('/api/posts/getPostContent', {
method: 'POST',
body: {
id
},
transform: async (response: postContent) => {
// 缓存数据
postStore.setPostCache(id, response)
const _p = new Promise<postContent>(async (resolve, reject) => {
try {
const cache = postStore.getPostCache(id)
if (cache) {
resolve(cache)
return
}
const res = await $fetch('/api/posts/getPostContent', {
method: 'POST',
body: {
id
}
}) as postContent
postStore.setPostCache(id, res)
resolve(res)
} catch (error) {
reject(error)
// 渲染Markdown
const markdownIt = await useMarkdownit()
return {
title: response.title,
content: response.data,
rendered: markdownIt.render(response.data)
}
})
const markdownIt = await useMarkdownit()
const postsData = await _p
content.value = postsData.data
renderedData.value = markdownIt.render(postsData.data)
title.value = postsData.title
isInit.value = true
},
// 使用缓存
async onRequest({ options }) {
const cache = postStore.getPostCache(id)
if (cache) {
return {
title: cache.title,
content: cache.data,
rendered: (await useMarkdownit()).render(cache.data)
}
}
}
})
// 响应式数据
const postData = computed(() => fetchedPost.value)
</script>
<style scoped>
+47 -6
View File
@@ -94,6 +94,49 @@ const formatTime = () => {
return `${hours}:${minutes}:${seconds}`;
};
// 定义API响应类型
interface SystemInfoResponse {
success: boolean;
data?: {
system: {
platform: string;
release: string;
hostname: string;
};
node: string;
hardware: {
cpu: {
model: string;
cores: number;
usage: number;
};
memory: {
total: string;
free: string;
used: string;
percent: number;
};
};
};
message?: string;
}
interface PerformanceResponse {
success: boolean;
data?: {
cpu: {
usage: number;
};
memory: {
total: string;
free: string;
used: string;
percent: number;
};
};
message?: string;
}
// 获取系统信息
const fetchSystemInfo = async () => {
try {
@@ -102,10 +145,9 @@ const fetchSystemInfo = async () => {
}
error.value = '';
const { data } = await useFetch('/api/system/info');
const response = data.value as any;
const response = await $fetch<SystemInfoResponse>('/api/system/info');
if (response && response.success) {
if (response && response.success && response.data) {
systemInfo.value = response.data;
// 如果还没有性能数据,初始化它
@@ -133,10 +175,9 @@ const fetchSystemInfo = async () => {
// 获取性能数据(CPU和内存使用率)
const fetchPerformanceData = async () => {
try {
const { data } = await useFetch('/api/system/performance');
const response = data.value as any;
const response = await $fetch<PerformanceResponse>('/api/system/performance');
if (response && response.success) {
if (response && response.success && response.data) {
performanceData.value = response.data;
performanceUpdated.value = formatTime();
}
+8 -7
View File
@@ -12,10 +12,11 @@ export default class Html2VNode {
this.middlewareList.push(middleware)
}
public render(htmlString: string) {
const html2ObjResult = this.html2Obj(htmlString);
const htmlString2 = htmlString.replaceAll('<hr>', '<hr></hr>').replaceAll('<br>', '<br></br>')
const html2ObjResult = this.html2Obj(htmlString2);
const middlewareMap = this.buildMiddlewareMap(html2ObjResult);
const wrinklesResult = this.wrinkles(html2ObjResult)
const vnodes = this.rander2VNode(wrinklesResult, middlewareMap)
const vnodes = this.render2VNode(wrinklesResult, middlewareMap)
return vnodes;
}
@@ -40,7 +41,7 @@ export default class Html2VNode {
return middlewareMap;
}
private rander2VNode = (
private render2VNode = (
wrinklesResult: (miaoVNodeType | string)[],
middlewareMap: Map<string, middlewareType[]>
): (VNode | string)[] => {
@@ -51,7 +52,7 @@ export default class Html2VNode {
const { tagName = '', tagAttrs } = this.parseTag(item.tag);
const middlewares = middlewareMap.get(tagName)
for(const middleware of middlewares!) {
const _res = middleware.rander({
const _res = middleware.render({
item,
tagName,
tagAttrs,
@@ -69,7 +70,7 @@ export default class Html2VNode {
filter: (_: string) => {
return true;
},
rander: ({
render: ({
item, tagName, tagAttrs, middlewareMap
}) => {
if (!tagName) {
@@ -77,7 +78,7 @@ export default class Html2VNode {
}
let child: string | (string | VNode)[] = item.children as string
if (typeof item.children !== 'string') {
child = this.rander2VNode(item.children, middlewareMap)
child = this.render2VNode(item.children, middlewareMap)
}
return h(tagName ?? 'span', tagAttrs, child)
}
@@ -214,7 +215,7 @@ type TagType = {
// 要优化也是以后优化了
export type middlewareType = {
filter: (tagName: string) => boolean,
rander: (option: {
render: (option: {
item: miaoVNodeType,
tagName: string,
tagAttrs: { [key: string]: string },