vue使用marked.js實現markdown轉html並提取標題生成目錄

html:javascript

<template>
    <div class="wrapper">
        <div class="container">
            <div class="menu">
                <ul class="menu-list">
                    <li v-for="(nav, index) in navList" 
              :key
="index"
              :class
="{on: activeIndex === index}"
              @click
="currentClick(index)"> <a href="javascript:;" @click="pageJump(nav.index)">{{nav.title}}</a> <div v-if="nav.children.length > 0 && activeIndex === index"
                class
="menu-children-list"> <ul class="nav-list"> <li v-for="(item, idx) in nav.children"
                     :key
="idx"
                     :class
="{on: childrenActiveIndex === idx}"
                     @click.stop
="childrenCurrentClick(idx)"> <a href="javascript:;" @click="pageJump(item.index)">
                        
{{item.title}}
                     
</a> </li> </ul> </div> </li> </ul> </div> <div class="help-center-content" v-html="compiledMarkdown"
       ref="helpDocs" @scroll="docsScroll"></div> </div> </div> </template>

js部分:html

<script> import marked from 'marked'; let rendererMD = new marked.Renderer(); marked.setOptions({ renderer: rendererMD, gfm: true, tables: true, breaks: false, pedantic: false, sanitize: false, smartLists: true, smartypants: false }); export default { props: ['mdContent'], data() { return { navList: [], activeIndex: 0, docsFirstLevels: [], docsSecondLevels: [], childrenActiveIndex: 0 } }, mounted() { this.navList = this.handleNavTree(); this.getDocsFirstLevels(0); }, methods: { childrenCurrentClick(index) { this.childrenActiveIndex = index }, getDocsFirstLevels(times) { // 解決圖片加載會影響高度問題
            setTimeout(() => { let firstLevels = []; Array.from(document.querySelectorAll('h1'), element => { firstLevels.push(element.offsetTop - 60) }) this.docsFirstLevels = firstLevels; if (times < 8) { this.getDocsFirstLevels(times + 1); } }, 500); }, getDocsSecondLevels(parentActiveIndex) { let idx = parentActiveIndex; let secondLevels = []; let navChildren = this.navList[idx].children if(navChildren.length > 0) { secondLevels = navChildren.map((item)=>{ return this.$el.querySelector(`#data-${item.index}`).offsetTop - 60 }) this.docsSecondLevels = secondLevels; } }, docsScroll() { if (this.titleClickScroll) { return; } let scrollTop = this.$refs.helpDocs.scrollTop let firstLevelIndex = this.getLevelActiveIndex(scrollTop, this.docsFirstLevels) this.currentClick(firstLevelIndex) let secondLevelIndex = this.getLevelActiveIndex(scrollTop, this.docsSecondLevels) this.childrenCurrentClick(secondLevelIndex) }, getLevelActiveIndex(scrollTop, docsLevels) { let currentIdx = null; let nowActive = docsLevels.some((currentValue, index) => { if(currentValue >= scrollTop) { currentIdx = index return true } }) currentIdx = currentIdx - 1
            
            if (nowActive && currentIdx === -1) { currentIdx = 0 } else if (!nowActive && currentIdx === -1) { currentIdx = docsLevels.length - 1 } return currentIdx }, pageJump(id) { this.titleClickScroll = true; this.$refs.helpDocs.scrollTop = this.$el.querySelector(`#data-${id}`).offsetTop - 40; setTimeout(() => this.titleClickScroll = false, 100); }, currentClick(index) { this.activeIndex = index this.getDocsSecondLevels(index) }, getTitle(content) { let nav = []; let tempArr = []; content.replace(/(#+)[^#][^\n]*?(?:\n)/g, function(match, m1, m2) { let title = match.replace('\n', ''); let level = m1.length; tempArr.push({ title: title.replace(/^#+/, '').replace(/\([^)]*?\)/, ''), level: level, children: [], }); }); // 只處理一級二級標題,以及添加與id對應的index值
            nav = tempArr.filter(item => item.level <= 2); let index = 0; return nav = nav.map(item => { item.index = index++; return item; }); }, // 將一級二級標題數據處理成樹結構
 handleNavTree() { let navs = this.getTitle(this.content) let navLevel = [1, 2]; let retNavs = []; let toAppendNavList; navLevel.forEach(level => { // 遍歷一級二級標題,將同一級的標題組成新數組
                toAppendNavList = this.find(navs, { level: level }); if (retNavs.length === 0) { // 處理一級標題 
                    retNavs = retNavs.concat(toAppendNavList); } else { // 處理二級標題,並將二級標題添加到對應的父級標題的children中 
                    toAppendNavList.forEach(item => { item = Object.assign(item); let parentNavIndex = this.getParentIndex(navs, item.index); return this.appendToParentNav(retNavs, parentNavIndex, item); }); } }); return retNavs; }, find(arr, condition) { return arr.filter(item => { for (let key in condition) { if (condition.hasOwnProperty(key) && condition[key] !== item[key]) { return false; } } return true; }); }, getParentIndex(nav, endIndex) { for (var i = endIndex - 1; i >= 0; i--) { if (nav[endIndex].level > nav[i].level) { return nav[i].index; } } }, appendToParentNav(nav, parentIndex, newNav) { let index = this.findIndex(nav, { index: parentIndex }); nav[index].children = nav[index].children.concat(newNav); }, findIndex(arr, condition) { let ret = -1; arr.forEach((item, index) => { for (var key in condition) { if (condition.hasOwnProperty(key) && condition[key] !== item[key]) { return false; } } ret = index; }); return ret; }, }, computed: { content() { return this.mdContent }, compiledMarkdown: function() { let index = 0; rendererMD.heading = function(text, level) { if (level <= 2) { return `<h${level} id="data-${index++}">${text}</h${level}>`;
                } else { return `<h${level}>${text}</h${level}>`;
 } }; rendererMD.code = function(code, language) { code = code.replace(/\r\n/g,"<br>") code = code.replace(/\n/g,"<br>"); return `<div class="text">${code}</div>`;
 }; return marked(this.content); } } } </script>

 

參考連接: java

https://github.com/markedjs/markedgit

https://www.jianshu.com/p/d182ea991609github

https://hk.saowen.com/a/bf975e4296e33a14e2d0ad50aa7cbf24fbfb4a9fb851de171b4c71da54eb95e5數組

相關文章
相關標籤/搜索