优化交互,开放文档支持目录导航
This commit is contained in:
@@ -1,34 +1,70 @@
|
||||
<template>
|
||||
<div v-if="apiDoc.shareInstruction">
|
||||
<div class="markdown-body" v-html="markdownToHtml(apiDoc.shareInstruction)" style="margin: 0 auto;max-width: 1000px;"></div>
|
||||
<a-row>
|
||||
<a-col :xs="0" :sm="4" :md="4" :lg="6" :xl="6" v-if="navigationList.length > 0">
|
||||
<Navigation ref="navigationRef" :heading="navigationList"></Navigation>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="navigationList.length > 0?20:24" :md="navigationList.length > 0?20:24" :lg="navigationList.length > 0?18:24" :xl="navigationList.length > 0?18:24">
|
||||
<div class="markdown-body share-instruction" v-html="markdownToHtml(apiDoc.shareInstruction)" style="margin: 0 auto;max-width: 1000px;"></div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<div v-else style="text-align: center;">欢迎访问开放API文档</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {toRefs, ref, reactive, onMounted, watch, computed} from 'vue';
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import {computed, onMounted, ref, watch} from 'vue';
|
||||
import {useStore} from 'vuex';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
|
||||
import {markdownIt} from 'mavon-editor'
|
||||
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
import swaggerAnalysis from "../../assets/core/SwaggerAnalysis";
|
||||
import Navigation from './components/Navigation.vue'
|
||||
|
||||
export default {
|
||||
components: {Navigation},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const apiDoc = computed(() => store.state.apiDoc);
|
||||
onMounted(() => {
|
||||
let navigationRef = ref();
|
||||
watch(store.getters.getApiDoc, () => {
|
||||
setTimeout(() => {
|
||||
createNavigationHeading('.share-instruction');
|
||||
}, 100);
|
||||
});
|
||||
const markdownToHtml = desc => {
|
||||
return markdownIt.render(desc || '');
|
||||
}
|
||||
let navigationList = ref([]);
|
||||
const createNavigationHeading = (domClass) => {
|
||||
if (!document.querySelector(domClass)) {
|
||||
return [];
|
||||
}
|
||||
let headNodeArr = document.querySelector(domClass).querySelectorAll('h1,h2,h3,h4,h5,h6');
|
||||
if (headNodeArr.length <= 0) {
|
||||
return [];
|
||||
}
|
||||
let headArr = [];
|
||||
headNodeArr.forEach(node => {
|
||||
let text = node.innerHTML.replace(/^\s+/g, '').replace(/\s+$/g, '').replace(/<\/?[^>]+(>|$)/g, '');
|
||||
headArr.push({
|
||||
node: node,
|
||||
level: parseInt(node.tagName.replace(/[h]/i, ''), 10),
|
||||
text: text
|
||||
});
|
||||
});
|
||||
navigationList.value = headArr;
|
||||
};
|
||||
onMounted(() => {
|
||||
});
|
||||
return {
|
||||
apiDoc,
|
||||
navigationRef,
|
||||
navigationList,
|
||||
markdownToHtml,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.share-instruction{padding: 0 10px;}
|
||||
</style>
|
||||
|
||||
106
zyplayer-doc-ui/api-ui/src/views/share/components/Navigation.vue
Normal file
106
zyplayer-doc-ui/api-ui/src/views/share/components/Navigation.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="navigation">
|
||||
<div ref="navigationRef" style="display: inline-block;width: 100%;height: 1px;"></div>
|
||||
<div class="navigation-heading" :style="{width: navigationWidth}">
|
||||
<div v-for="item in heading" :class="'heading-item heading-'+item.level" @click="headingItemClick(item)">
|
||||
{{item.text}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {computed, onMounted, ref, watch} from 'vue';
|
||||
import {useStore} from 'vuex';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
heading: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
let navigationWidth = ref('100px');
|
||||
onMounted(() => {
|
||||
window.onresize = () => {
|
||||
computeNavigationWidth();
|
||||
}
|
||||
setTimeout(() => {
|
||||
computeNavigationWidth();
|
||||
}, 100);
|
||||
});
|
||||
watch(store.getters.getLeftAsideWidth, () => {
|
||||
computeNavigationWidth();
|
||||
});
|
||||
let navigationRef = ref();
|
||||
const computeNavigationWidth = () => {
|
||||
navigationWidth.value = window.getComputedStyle(navigationRef.value, null).width;
|
||||
};
|
||||
// 滚动到指定节点
|
||||
const headingItemClick = (item) => {
|
||||
item.node.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
|
||||
};
|
||||
return {
|
||||
navigationRef,
|
||||
navigationWidth,
|
||||
headingItemClick,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.navigation {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navigation-heading {
|
||||
position: fixed;
|
||||
z-index: 4;
|
||||
top: 150px;
|
||||
height: calc(100vh - 250px);
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
padding-left: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-item {
|
||||
padding: 5px 0;
|
||||
cursor: pointer;
|
||||
color: #646a73;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-item:hover {
|
||||
color: #3370ff;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-1 {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-2 {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-3 {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-4 {
|
||||
padding-left: 48px;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-5 {
|
||||
padding-left: 64px;
|
||||
}
|
||||
|
||||
.navigation-heading .heading-6 {
|
||||
padding-left: 80px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user