当前位置:   article > 正文

记一次使用vue-markdown在vue中解析markdown格式文件,并自动生成目录大纲_vue怎么解析markdown内容

vue怎么解析markdown内容

先上效果图

如图所示,在网页中,能直接解析markdown文档,并且生成目录大纲,也支持点击目录标题跳转到对应栏目中,下面就来讲讲是如何实现此功能的。

1、下载vue-markdown

yarn add vue-markdown

2、在页面中渲染markdown文件

  1. <template>
  2. <div>
  3. <VueMarkdown
  4. class="api-content"
  5. :source="markdownContent"
  6. id="content"
  7. />
  8. </div>
  9. </template>
  10. <script>
  11. import VueMarkdown from "vue-markdown";
  12. export default {
  13. components: {
  14. VueMarkdown,
  15. },
  16. data() {
  17. return {
  18. markdownContent: "",
  19. };
  20. },
  21. mounted() {
  22. this.loadMarkdownFile();
  23. },
  24. methods: {
  25. async loadMarkdownFile() {
  26. try {
  27. // api.md文件存放在根目录下的public文件夹中
  28. const response = await fetch("/api.md");
  29. const markdownText = await response.text();
  30. this.markdownContent = markdownText;
  31. } catch (error) {
  32. console.error("Failed to load the Markdown file:", error);
  33. }
  34. },
  35. },
  36. };
  37. </script>

此时,打开浏览器查看,页面中已经正常渲染markdown文件了。

3、生成目录大纲

现在,我们需要有目录大纲方便我们查看文档。我的思路是,首先拿到markdown文件的html结构,然后找到所有H1-H5的标题标签,并给这些标签设置id,生成一个新数组,通过这个数组生成目录结构,说干就干。

  1. //html部分
  2. <div class="api-tree" id="tree">
  3. <el-tree
  4. :data="tree"
  5. :default-expand-all="true"
  6. @node-click="handleNodeClick"
  7. ></el-tree>
  8. </div>
  9. // js部分
  10. catalogTree() {
  11. const content = document.getElementById("content").children;
  12. var arr = [];
  13. let currentHightestLevel;
  14. let parentId;
  15. let index = 0;
  16. for (let i = 0; i < content.length; i++) {
  17. let header = content[i].localName;
  18. if (/\b[h][0-9]\b/.test(header)) {
  19. let ele = $(content[i]);
  20. let name = ele.text();
  21. // 设置id
  22. ele.attr("id", i);
  23. let id = i;
  24. if (index === 0 || header <= currentHightestLevel) {
  25. currentHightestLevel = header;
  26. parentId = id;
  27. }
  28. arr.push({
  29. id: id,
  30. label: name,
  31. parentId: parentId == id ? "0" : parentId,
  32. });
  33. index++;
  34. }
  35. }
  36. const tree = [];
  37. arr.forEach((item) => {
  38. if (item.parentId === "0") {
  39. tree.push(this.convertArrayToTree(arr, item));
  40. }
  41. });
  42. this.tree = tree;
  43. },
  44. convertArrayToTree(arr, node) {
  45. for (let i = 0; i < arr.length; i++) {
  46. if (arr[i].parentId === node.id) {
  47. const res = this.convertArrayToTree(arr, arr[i]);
  48. if (node.children) {
  49. node.children.push(res);
  50. } else {
  51. node.children = [res];
  52. }
  53. }
  54. }
  55. return node;
  56. },
  57. handleNodeClick(data) {
  58. let anchorElement = document.getElementById(data.id);
  59. if (anchorElement) {
  60. anchorElement.scrollIntoView({
  61. behavior: "smooth",
  62. block: "end",
  63. });
  64. }
  65. },

4、大功告成,最后,附上全部代码,带css样式

  1. <template>
  2. <div class="page-api" id="myElement">
  3. <div class="api-tree" id="tree">
  4. <el-tree
  5. :data="tree"
  6. :default-expand-all="true"
  7. @node-click="handleNodeClick"
  8. ></el-tree>
  9. </div>
  10. <VueMarkdown
  11. class="api-content"
  12. :source="markdownContent"
  13. id="content"
  14. />
  15. </div>
  16. </template>
  17. <script>
  18. import VueMarkdown from "vue-markdown";
  19. import $ from "jquery";
  20. export default {
  21. components: {
  22. VueMarkdown,
  23. },
  24. data() {
  25. return {
  26. markdownContent: "",
  27. tree: [],
  28. };
  29. },
  30. mounted() {
  31. this.loadMarkdownFile();
  32. },
  33. methods: {
  34. async loadMarkdownFile() {
  35. try {
  36. const response = await fetch("/api.md");
  37. const markdownText = await response.text();
  38. this.markdownContent = markdownText;
  39. this.$nextTick(() => {
  40. this.catalogTree();
  41. });
  42. } catch (error) {
  43. console.error("Failed to load the Markdown file:", error);
  44. }
  45. },
  46. catalogTree() {
  47. const content = document.getElementById("content").children;
  48. var arr = [];
  49. let currentHightestLevel;
  50. let parentId;
  51. let index = 0;
  52. for (let i = 0; i < content.length; i++) {
  53. let header = content[i].localName;
  54. if (/\b[h][0-9]\b/.test(header)) {
  55. let ele = $(content[i]);
  56. let name = ele.text();
  57. // 设置id
  58. ele.attr("id", i);
  59. // let id = ele.children("a").attr("id");
  60. let id = i;
  61. if (index === 0 || header <= currentHightestLevel) {
  62. currentHightestLevel = header;
  63. parentId = id;
  64. }
  65. arr.push({
  66. id: id,
  67. label: name,
  68. parentId: parentId == id ? "0" : parentId,
  69. });
  70. index++;
  71. }
  72. }
  73. const tree = [];
  74. arr.forEach((item) => {
  75. if (item.parentId === "0") {
  76. tree.push(this.convertArrayToTree(arr, item));
  77. }
  78. });
  79. this.tree = tree;
  80. },
  81. convertArrayToTree(arr, node) {
  82. for (let i = 0; i < arr.length; i++) {
  83. if (arr[i].parentId === node.id) {
  84. const res = this.convertArrayToTree(arr, arr[i]);
  85. if (node.children) {
  86. node.children.push(res);
  87. } else {
  88. node.children = [res];
  89. }
  90. }
  91. }
  92. return node;
  93. },
  94. handleNodeClick(data) {
  95. let anchorElement = document.getElementById(data.id);
  96. let scrollPosition = anchorElement.offsetTop - 20;
  97. let myElement = document.getElementById("myElement");
  98. myElement.scrollTo({
  99. left: 0,
  100. top: scrollPosition,
  101. behavior: "smooth",
  102. });
  103. // if (anchorElement) {
  104. // anchorElement.scrollIntoView({
  105. // behavior: "smooth",
  106. // block: "end",
  107. // });
  108. // }
  109. },
  110. },
  111. };
  112. </script>
  113. <style lang="scss">
  114. .page-api {
  115. display: flex;
  116. height: 100%;
  117. overflow-y: scroll;
  118. .api-tree {
  119. position: fixed;
  120. left: 20px;
  121. top: 120px;
  122. width: 200px;
  123. height: calc(100% - 160px);
  124. overflow-y: scroll;
  125. z-index: 99;
  126. .el-tree {
  127. background: none;
  128. color: #fff;
  129. .el-tree-node:focus > .el-tree-node__content,
  130. .el-tree-node__content:hover {
  131. background: none;
  132. color: rgb(24, 144, 255);
  133. }
  134. }
  135. }
  136. .api-content {
  137. flex: 1;
  138. margin-left: 220px;
  139. padding: 0 30px;
  140. color: rgba(255, 255, 255, 0.75);
  141. h3 {
  142. margin-left: 25px;
  143. }
  144. code {
  145. border-radius: 2px;
  146. color: #e96900;
  147. margin: 0 2px;
  148. padding: 3px 5px;
  149. white-space: pre-wrap;
  150. }
  151. table {
  152. border-collapse: collapse;
  153. border-spacing: 0;
  154. th,
  155. td {
  156. border: 1px solid #ddd;
  157. padding: 6px 13px;
  158. margin: 0;
  159. }
  160. }
  161. pre {
  162. background: rgba(0, 0, 0, 0.7);
  163. padding: 20px 30px;
  164. }
  165. }
  166. }
  167. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/231525?site
推荐阅读
相关标签
  

闽ICP备14008679号