赞
踩
先上效果图
如图所示,在网页中,能直接解析markdown文档,并且生成目录大纲,也支持点击目录标题跳转到对应栏目中,下面就来讲讲是如何实现此功能的。
yarn add vue-markdown
- <template>
- <div>
- <VueMarkdown
- class="api-content"
- :source="markdownContent"
- id="content"
- />
- </div>
- </template>
-
- <script>
- import VueMarkdown from "vue-markdown";
-
- export default {
- components: {
- VueMarkdown,
- },
- data() {
- return {
- markdownContent: "",
- };
- },
- mounted() {
- this.loadMarkdownFile();
- },
- methods: {
- async loadMarkdownFile() {
- try {
- // api.md文件存放在根目录下的public文件夹中
- const response = await fetch("/api.md");
- const markdownText = await response.text();
- this.markdownContent = markdownText;
-
- } catch (error) {
- console.error("Failed to load the Markdown file:", error);
- }
- },
- },
- };
- </script>
此时,打开浏览器查看,页面中已经正常渲染markdown文件了。
现在,我们需要有目录大纲方便我们查看文档。我的思路是,首先拿到markdown文件的html结构,然后找到所有H1-H5的标题标签,并给这些标签设置id,生成一个新数组,通过这个数组生成目录结构,说干就干。
- //html部分
-
- <div class="api-tree" id="tree">
- <el-tree
- :data="tree"
- :default-expand-all="true"
- @node-click="handleNodeClick"
- ></el-tree>
- </div>
-
-
- // js部分
- catalogTree() {
- const content = document.getElementById("content").children;
- var arr = [];
- let currentHightestLevel;
- let parentId;
- let index = 0;
- for (let i = 0; i < content.length; i++) {
- let header = content[i].localName;
- if (/\b[h][0-9]\b/.test(header)) {
- let ele = $(content[i]);
- let name = ele.text();
- // 设置id
- ele.attr("id", i);
- let id = i;
- if (index === 0 || header <= currentHightestLevel) {
- currentHightestLevel = header;
- parentId = id;
- }
- arr.push({
- id: id,
- label: name,
- parentId: parentId == id ? "0" : parentId,
- });
- index++;
- }
- }
- const tree = [];
- arr.forEach((item) => {
- if (item.parentId === "0") {
- tree.push(this.convertArrayToTree(arr, item));
- }
- });
- this.tree = tree;
- },
- convertArrayToTree(arr, node) {
- for (let i = 0; i < arr.length; i++) {
- if (arr[i].parentId === node.id) {
- const res = this.convertArrayToTree(arr, arr[i]);
- if (node.children) {
- node.children.push(res);
- } else {
- node.children = [res];
- }
- }
- }
- return node;
- },
- handleNodeClick(data) {
- let anchorElement = document.getElementById(data.id);
-
- if (anchorElement) {
- anchorElement.scrollIntoView({
- behavior: "smooth",
- block: "end",
- });
- }
- },
- <template>
- <div class="page-api" id="myElement">
- <div class="api-tree" id="tree">
- <el-tree
- :data="tree"
- :default-expand-all="true"
- @node-click="handleNodeClick"
- ></el-tree>
- </div>
- <VueMarkdown
- class="api-content"
- :source="markdownContent"
- id="content"
- />
- </div>
- </template>
-
- <script>
- import VueMarkdown from "vue-markdown";
- import $ from "jquery";
-
- export default {
- components: {
- VueMarkdown,
- },
- data() {
- return {
- markdownContent: "",
- tree: [],
- };
- },
- mounted() {
- this.loadMarkdownFile();
- },
- methods: {
- async loadMarkdownFile() {
- try {
- const response = await fetch("/api.md");
- const markdownText = await response.text();
- this.markdownContent = markdownText;
- this.$nextTick(() => {
- this.catalogTree();
- });
- } catch (error) {
- console.error("Failed to load the Markdown file:", error);
- }
- },
- catalogTree() {
- const content = document.getElementById("content").children;
- var arr = [];
- let currentHightestLevel;
- let parentId;
- let index = 0;
- for (let i = 0; i < content.length; i++) {
- let header = content[i].localName;
- if (/\b[h][0-9]\b/.test(header)) {
- let ele = $(content[i]);
- let name = ele.text();
- // 设置id
- ele.attr("id", i);
- // let id = ele.children("a").attr("id");
- let id = i;
- if (index === 0 || header <= currentHightestLevel) {
- currentHightestLevel = header;
- parentId = id;
- }
- arr.push({
- id: id,
- label: name,
- parentId: parentId == id ? "0" : parentId,
- });
- index++;
- }
- }
- const tree = [];
- arr.forEach((item) => {
- if (item.parentId === "0") {
- tree.push(this.convertArrayToTree(arr, item));
- }
- });
- this.tree = tree;
- },
- convertArrayToTree(arr, node) {
- for (let i = 0; i < arr.length; i++) {
- if (arr[i].parentId === node.id) {
- const res = this.convertArrayToTree(arr, arr[i]);
- if (node.children) {
- node.children.push(res);
- } else {
- node.children = [res];
- }
- }
- }
- return node;
- },
- handleNodeClick(data) {
- let anchorElement = document.getElementById(data.id);
-
- let scrollPosition = anchorElement.offsetTop - 20;
-
- let myElement = document.getElementById("myElement");
- myElement.scrollTo({
- left: 0,
- top: scrollPosition,
- behavior: "smooth",
- });
-
- // if (anchorElement) {
- // anchorElement.scrollIntoView({
- // behavior: "smooth",
- // block: "end",
- // });
- // }
- },
- },
- };
- </script>
-
- <style lang="scss">
- .page-api {
- display: flex;
- height: 100%;
- overflow-y: scroll;
- .api-tree {
- position: fixed;
- left: 20px;
- top: 120px;
- width: 200px;
- height: calc(100% - 160px);
- overflow-y: scroll;
- z-index: 99;
- .el-tree {
- background: none;
- color: #fff;
- .el-tree-node:focus > .el-tree-node__content,
- .el-tree-node__content:hover {
- background: none;
- color: rgb(24, 144, 255);
- }
- }
- }
- .api-content {
- flex: 1;
- margin-left: 220px;
- padding: 0 30px;
- color: rgba(255, 255, 255, 0.75);
-
- h3 {
- margin-left: 25px;
- }
- code {
- border-radius: 2px;
- color: #e96900;
- margin: 0 2px;
- padding: 3px 5px;
- white-space: pre-wrap;
- }
- table {
- border-collapse: collapse;
- border-spacing: 0;
- th,
- td {
- border: 1px solid #ddd;
- padding: 6px 13px;
- margin: 0;
- }
- }
- pre {
- background: rgba(0, 0, 0, 0.7);
- padding: 20px 30px;
- }
- }
- }
- </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。