前端Vue页面实现 Markdown文档渲染

1. 安装依赖库

npm install @kangc/v-md-editor
npm install highlight.js@^10.7.3 markdown-it-anchor@^8.6.4

2. 全局配置(在 main.js 中)

// Markdown 编辑器配置
import VMdEditor from '@kangc/v-md-editor'
import githubTheme from '@kangc/v-md-editor/lib/theme/github'
import '@kangc/v-md-editor/lib/theme/style/github.css'
import hljs from 'highlight.js/lib/core' 
import markdownItAnchor from 'markdown-it-anchor'

// 配置 Markdown 解析器
VMdEditor.use(githubTheme, {
  Hljs: hljs,
  extend(md) {
    md.use(markdownItAnchor, {
      slugify: (s) => s.toLowerCase().replace(/[^\w\u4e00-\u9fa5]+/g, '-')
    });
  },
});

// 注册到 Vue
Vue.use(VMdEditor);

3. 创建Markdown渲染组件

components 目录下新建 MarkdownViewer.vue

<template>
  <div class="markdown-wrapper">
    <!-- 左侧目录 -->
    <div class="toc" v-if="toc.length">
      <div class="toc-title">目录导航</div>
      <div
        v-for="(item, index) in toc"
        :key="index"
        :class="['toc-item', `toc-level-${item.level}`]"
      >
        <a @click="scrollToAnchor(item.anchor)">{{ item.title }}</a>
      </div>
    </div>

    <!-- 右侧内容 -->
    <div class="content">
      <v-md-editor
        :value="content"
        mode="preview"
        left-toolbar="undefined"
        @toc-change="handleTocChange"
      />
    </div>
  </div>
</template>

<script>
export default {
  props: {
    content: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      toc: []
    };
  },
  methods: {
    handleTocChange(toc) {
      this.toc = toc;
    },
    scrollToAnchor(anchor) {
      const target = document.querySelector(`#${anchor}`);
      if (target) {
        target.scrollIntoView({ behavior: 'smooth' });
      }
    }
  }
};
</script>

<style scoped>
.markdown-wrapper {
  display: flex;
  min-height: calc(100vh - 120px);
}

.toc {
  width: 240px;
  padding: 15px;
  border-right: 1px solid #eaecef;
  position: sticky;
  top: 60px;
  max-height: 90vh;
  overflow-y: auto;
}

.toc-title {
  font-weight: 600;
  margin-bottom: 10px;
  color: #2c3e50;
}

.toc-item {
  line-height: 1.5;
  padding: 4px 0;
}

.toc-level-2 { margin-left: 0 }
.toc-level-3 { margin-left: 15px }
.toc-level-4 { margin-left: 30px }
.toc-level-5 { margin-left: 45px }

.content {
  flex: 1;
  padding: 20px 40px;
  max-width: 900px;
}

/* 覆盖默认样式 */
.v-md-editor >>> pre {
  background-color: #f6f8fa !important;
  padding: 16px !important;
  border-radius: 6px;
}

.v-md-editor >>> table {
  border-collapse: collapse;
  margin: 1em 0;
}

.v-md-editor >>> table td,
.v-md-editor >>> table th {
  border: 1px solid #dfe2e5;
  padding: 0.6em 1em;
}
</style>

4.假设文件存放在 public/docs 目录

5. 在页面中使用组件,并添加回到顶部按钮

<template>
  <div>
    <markdown-viewer :content="mdContent" />
    <button v-show="showBackToTop" class="back-to-top" @click="scrollToTop">回到顶部</button>
  </div>
</template>

<script>
import MarkdownViewer from '@/components/MarkdownViewer';

export default {
  components: { MarkdownViewer },
  data() {
    return {
      mdContent: '',
      showBackToTop: false,// 控制回到顶部按钮的显示与隐藏
    };
  },
  mounted() {
    // 假设文件存放在 public/docs 目录
    fetch('/docs/work.md')
      .then(res => res.text())
      .then(text => {
        this.mdContent = text;
      });

    // 监听页面滚动事件
    window.addEventListener("scroll", this.handleScroll);
  },
  beforeDestroy() {
    // 组件销毁前移除滚动监听事件,避免内存泄漏
    window.removeEventListener("scroll", this.handleScroll);
  },
  methods: {
    handleScroll() {
      // 当页面滚动距离超过 300px 时,显示回到顶部按钮
      this.showBackToTop = window.scrollY > 300;
    },
    scrollToTop() {
      // 平滑滚动到页面顶部
      window.scrollTo({
        top: 0,
        behavior: "smooth",
      });
    },
  },
};
</script>
<style scoped>
.back-to-top {
  position: fixed;
  bottom: 20px;
  right: 20px;
  padding: 10px 15px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  z-index: 100;
}

.back-to-top:hover {
  background-color: #0056b3;
}
</style>

五、图片路径处理技巧

  1. 本地图片‌(推荐存放在 public/md-images):

    ![图片说明](/md-images/demo.png)
    
  2. 网络图片‌直接使用 URL:

    ![网络图片](https://example.com/image.jpg)
    
### Vue3 中渲染 Markdown 文档的方法 在 Vue3 项目中渲染 Markdown 文档可以通过多种方式实现,以下是基于提供的引用内容以及专业知识的一种方法。 #### 使用 `vite-plugin-markdown` 和 `vue-markdown` 通过安装和配置 `vite-plugin-markdown` 插件,可以方便地加载并渲染 Markdown 文件。同时结合 `vue-markdown` 组件来处理 Markdown 内容的展示逻辑[^2]。 ##### 安装依赖 首先,在项目中安装必要的依赖包: ```bash npm install vite-plugin-markdown vue-markdown ``` ##### 配置 Vite 插件 编辑项目的 `vite.config.js` 文件,添加如下配置以启用 Markdown 支持: ```javascript import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import markdown from 'vite-plugin-md'; export default defineConfig({ plugins: [ vue(), markdown(), // 启用 Markdown 解析插件 ], }); ``` 上述配置使得 Vite 能够解析 `.md` 文件,并将其转换为适合前端使用的格式。 ##### 创建 Markdown 渲染组件 创建一个新的 Vue 组件(如 `MarkdownViewer.vue`),用于接收并渲染 Markdown 数据: ```vue <template> <div v-html="renderedContent"></div> </template> <script> import { ref, onMounted } from 'vue'; import VueMarkdown from 'vue-markdown'; // 导入 vue-markdown 组件 export default { components: { VueMarkdown, }, props: { content: { type: String, required: true, }, }, setup(props) { const renderedContent = ref(''); onMounted(() => { renderedContent.value = props.content; }); return { renderedContent }; }, }; </script> ``` 此组件利用了 `vue-markdown` 来动态解析传入的 Markdown 字符串数据[^1]。 ##### 加载外部 Markdown 文件 如果需要从文件系统加载 Markdown 文件,则可以在父组件中导入这些文件并通过属性传递给子组件。例如: ```vue <template> <MarkdownViewer :content="markdownContent" /> </template> <script> import { ref } from 'vue'; import externalMarkdownFile from './path/to/your/markdown-file.md'; // 动态导入 .md 文件 export default { setup() { const markdownContent = ref(externalMarkdownFile); return { markdownContent }; }, }; </script> ``` 这样即可完成对外部 Markdown 文件的加载与渲染操作。 #### 自动生成 TOC 目录 为了进一步增强用户体验,还可以根据 Markdown 的标题结构来自动生成文章目录(Table of Contents)。这通常涉及扫描 Markdown 源码中的标题标记 (`#`, `##`) 并构建相应的链接列表[^3]。 以下是一个简单的示例代码片段,演示如何提取标题信息并生成 TOC: ```javascript function generateToc(markdownString) { const tocRegex = /(\#{1,6})\s*(.*?)(?:\n|$)/g; // 正则匹配各级标题 let matches; const tocItems = []; while ((matches = tocRegex.exec(markdownString)) !== null) { const level = matches[1].length; // 获取当前标题级别 const text = matches[2]; // 提取标题文字部分 const slug = text.toLowerCase().replace(/\W+/g, '-'); // 构造 URL 锚点名称 tocItems.push({ level, text, slug }); } return tocItems.map(item => `<li><a href="#${item.slug}">${item.text}</a></li>`).join(''); } ``` 调用该函数并将返回的结果插入页面 DOM 即可呈现完整的 TOC 列表。 --- ### 总结 以上展示了如何借助现代工具链(Vite + Vue3)高效地集成 Markdown 渲染能力至应用程序之中。无论是静态字符串还是远程资源均能被妥善处理;而额外加入 TOC 自动化生成功能让整体交互体验更加友好流畅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值