import { Component, createEffect, onCleanup, Show, createResource, createMemo, } from "solid-js"; import { parseMarkdown } from "../markdown"; import { extractSection } from "../data-loader"; import mermaid from "mermaid"; import { getIndexedData } from "../data-loader/file-index"; import { resolvePath } from "./utils/path"; import { useLocation } from "@solidjs/router"; export interface ArticleProps { src: string; section?: string; // 指定要显示的标题(不含 #) iconPath?: string; // 图标路径前缀,默认为 "./assets",空字符串表示禁用 onLoaded?: () => void; onError?: (error: Error) => void; class?: string; // 额外的 class 用于样式控制 scrollToHash?: boolean; // 是否自动滚动到 hash } async function fetchArticleContent(params: { src: string; section?: string; }): Promise { const text = await getIndexedData(params.src); // 如果指定了 section,提取对应内容 return params.section ? extractSection(text, params.section) : text; } /** * 滚动到指定的 hash 元素 */ function scrollToHash(hash: string) { if (!hash) return; // 移除 # 前缀 const id = hash.startsWith("#") ? hash.slice(1) : hash; if (!id) return; // 使用 decodeURIComponent 解码 ID(处理中文等特殊字符) const decodedId = decodeURIComponent(id); // 尝试查找元素 const element = document.getElementById(decodedId); if (element) { // 使用 scrollIntoView 滚动到元素 element.scrollIntoView({ behavior: "instant", block: "start" }); return true; } return false; } /** * Article 组件 * 用于将特定 src 位置的 md 文件显示为 markdown 文章 */ export const Article: Component = (props) => { const location = useLocation(); const [content, { refetch }] = createResource( () => ({ src: props.src, section: props.section }), fetchArticleContent, ); // 解析 iconPath,默认为 "./assets",空字符串表示禁用 const iconPrefix = createMemo(() => { if (props.iconPath === "") return undefined; // 空字符串禁用图标前缀 return resolvePath(props.src, props.iconPath ?? "./assets"); }); createEffect(() => { const data = content(); if (data) { props.onLoaded?.(); // 内容加载完成后,渲染 mermaid 图表 void mermaid.run(); // 内容渲染后检查 hash 并滚动 scrollToHash(location.hash); } }); onCleanup(() => { // 清理时清空内容,触发内部组件的销毁 }); return (
加载中...
加载失败:{content.error?.message}
); }; export default Article;