赞
踩
根据string类型的字符串文章内容,提取H1-H6标签,生成文章目录结构展示,并且对应生成锚点,点击可跳转。
1. Template代码
- <a-card style="margin:10px 10px 0 20px;position: absolute;top:30%;width:15%;">
- <b>文章目录</b>
- <p></p>
- <p v-for="menuitem in menuTree" :key="menuitem"><a :href="getElementmaodian(menuitem)" :style="menustyle(menuitem)">{{getElementcontent(menuitem)}}</a></p></a-card>
2. Method代码
1)根据文章内容生成目录结构
- /*设置文章目录结构*/
- getCenceptQuerySelect(){
- const str_content = this.selectConcept.contents
- const regex = /<h[1-6](.*?)>(.*?)<\/h[1-6]>/g;//正则表达式匹配提取所有H1-H6标签
- var match
- while((match = regex.exec(str_content)) !== null{
- this.menuTree.push(match[0])
- }
- },
2)目录样式
- /*文章结构标题缩进*/
- menustyle(menuiten){
- var type = menuiten.slice(1,3)
- var menutyle = ''
- switch(type){
- case 'h1': menutyle = 'margin-left:10px;';break
- case 'h2': menutyle = 'margin-left:20px;';break
- case 'h3': menutyle = 'margin-left:30px;';break
- case 'h4': menutyle = 'margin-left:40px;';break
- case 'h5': menutyle = 'margin-left:50px;';break
- case 'h6': menutyle = 'margin-left:60px;';break
- default: break
- }
- return menutyle
- },
3)获取标签锚点
- /*获取标签锚点*/
- getElementmaodian(item){
- var placeholder = document.createElement('div')
- placeholder.innerHTML = item //返回id锚点
- return '#' + placeholder.firstElementChild.id
- },
4)文章创建时添加锚点代码
由于使用quill富文本创建文章是生成的内容没有锚点,所以需要自定义:
- const str_content = this.addConcept.contents
- const regex = /<h[1-6]>(.*?)<\/h[1-6]>/g;
- var match var menuTree = []
- while((match = regex.exec(str_content)) !== null){
- menuTree.push(match[0])
- }
- menuTree.forEach(item=>{
- var placeholder = document.createElement('div')
- placeholder.innerHTML = item
-
- //生成有锚点的元素,锚点value为显示的内容
- var rep = item.replaceAll('>'+placeholder.firstElementChild.innerHTML+'<', ' id=\'' + placeholder.firstElementChild.innerHTML + '\'>'+placeholder.firstElementChild.innerHTML+'<')
- this.addConcept.contents = this.addConcept.contents.replaceAll(item, rep) //替换有锚点的元素
- })
需求
目录树结构,可展开收缩。
效果图
代码实现
1. 生成目录树结构的Json
menuTree_json存放结构数据
- generateDirectoryTree_Json(content){
- const regex = /<h[1-6](.*?)>(.*?)<\/h[1-6]>/g;
- var match
- while ((match = regex.exec(content)) !== null) {
- var item = {
- level: this.menuItemLevel(match[0]), //层级:H1-1/H2-2/H3-3/H4-4/H5-5/H6-6
- anchor: this.getElementmaodian(match[0]), //锚点
- title: this.getElementcontent(match[0]), //内容
- child: [], //子节点
- isExpand:true //默认该树节点展开
- }
-
- this.addMenuitem(this.menuTree_json,item) //从树根节点开始添加子节点
- }
- },
-
- /*递归插入*/
- addMenuitem(menu, item){
- if (menu.length === 0) {
- menu.push(item)
- }
- else {
- if (item.level > menu[menu.length - 1].level) {
- //递归添加子节点
- this.addMenuitem(menu[menu.length - 1].child, item)
- }
- else if (menu.length - 1 === 0) {
- menu.push(item)
- }
- else {
- menu.push(item)
- }
- }
- },
2.templace中根据目录树结构的Json递归生成目录
这里将这部分定义为一个组件,方便递归调用。
组件调用:
<ContentMenu :menu="menuTree_json"></ContentMenu>
组件定义:
- <template>
- <div>
- <div v-for="menuitem in menu" :key="menuitem" style="overflow: auto;margin-top:10px;">
- <svg @click="menuitem.isExpand=!menuitem.isExpand" v-if="menuitem.child.length != 0 && !menuitem.isExpand" t="1682300013635" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3229" width="16" height="16"><path d="M946.33106 697.353498 541.30749 284.093337c-15.690354-16.009625-41.469484-16.009625-57.160861 0l-405.024593 413.260162c-24.819269 25.323758-6.877641 68.028373 28.579919 68.028373l810.048163 0C953.209724 765.381871 971.150328 722.677257 946.33106 697.353498z" fill="#1296db" p-id="3230"></path></svg>
- <svg @click="menuitem.isExpand=!menuitem.isExpand" v-if="menuitem.child.length != 0 && menuitem.isExpand" t="1682300082130" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3505" width="16" height="16"><path d="M79.123059 327.850933l405.024593 413.260162c15.690354 16.009625 41.469484 16.009625 57.160861 0l405.02357-413.260162c24.819269-25.323758 6.877641-68.028373-28.579919-68.028373L107.704001 259.82256C72.245418 259.82256 54.30379 302.527175 79.123059 327.850933z" fill="#1296db" p-id="3506"></path></svg>
- <a href="javascript:void(0)" @click="goAnchor(menuitem.anchor)" style="margin-left:5px;margin-top:3px;">
- <span v-html="menuitem.title"></span>
- </a>
- <div v-if="menuitem.isExpand" style="margin-left:30px;margin-top:10px;">
- <!--递归生成目录树,递归自己-->
- <contentMenu :menu="menuitem.child"></contentMenu>
- </div>
- </div>
- </div>
- </template>
- <script>
- import { mixins_menutree } from '../../mixin/menutree'
- export default {
- name:'contentMenu', //定义name才能组件自己递归调用自己
- mixins:[mixins_menutree],
- props:{
- menu:[]
- }
- }
- </script>
需求
当目录条目过多时,需要进行搜索过滤
效果
代码实现
- <a-input-search
- size="small"
- placeholder="文章目录"
- v-model = "searchMenu"
- @search="onSearchMenu"
- ></a-input-search>
- /*onSearchMenu
- 搜索目录,重新生成目录
- */
- onSearchMenu() {
- this.menuTree_json = []
-
- this.menu_init.forEach(item => {
- if (item.title.toLowerCase().indexOf(this.searchMenu.toLowerCase()) != -1) {
- item.child = [] //孩子节点直接去掉
- this.addMenuitem(this.menuTree_json, item)
- }
- })
- },
1. 锚点中文跳转控制台报错问题
中文锚点 #锚点1 被转义为 #%E9%94%9A%E7%82%B91 导致控制台报错,但是能work,正确跳转。。。
2. a标签href跳转发布到IIS后跳转出错
<a :href="getElementmaodian(menuitem)"
解决:
- <a href="javascript:void(0)" @click="goAnchor(getElementmaodian(menuitem))"
-
- goAnchor(selector){ //锚点跳转 document.querySelector(selector).scrollIntoView({ behavior:'smooth' })},
3. 锚点是数字开头会认为不合法
解决方法一:标题字符串处理后再生成锚点id,保证锚点正确。
还存在问题:
1、btoa加密后的字符串后两位是‘==’,也会包锚点不合法错误,临时解决:只提取前20位
2、只提取前20位的话有可能存在相同锚点
- //标题字符串处理,保证锚点正确
-
- var str64 = window.btoa(window.encodeURIComponent(placeholder.firstElementChild.innerHTML)).slice(0,20)
-
- var rep = item.replaceAll('>'+placeholder.firstElementChild.innerHTML+'<', ' id=\'' + str64 + '\'>'+placeholder.firstElementChild.innerHTML+'<') this.addConcept.contents = this.addConcept.contents.replaceAll(item, rep)
解决方法二:
随机数拼接字符串
- //标题字符串处理,保证锚点正确var str64 = window.btoa(window.encodeURIComponent(placeholder.firstElementChild.innerHTML))
- //移除特殊字符
- str64 = str64.replaceAll('=', '')
- //生成随机数转成36进制,再截取后8位
- var str_random = Math.random().toString(36).slice(-8)
-
- str64 = str64 + str_random
- var rep = item.replaceAll('>'+placeholder.firstElementChild.innerHTML+'<', ' id=\'' + str64 + '\'>'+placeholder.firstElementChild.innerHTML+'<')
- this.addConcept.contents = this.addConcept.contents.replace(item, rep)//使用replace而不是replaceAll,否则可能替换所有
解决方法三:
直接生成三个随机数转成36进制,分别截取后8位,再拼接
-
- var str_random1 = Math.random().toString(36).slice(-8)
- var str_random2 = Math.random().toString(36).slice(-8)
- var str_random3 = Math.random().toString(36).slice(-8)var str_random = str_random1 + str_random2 + str_random3
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。