找回密码
 会员注册
查看: 19|回复: 0

tocbot源码解读

[复制链接]

6

主题

0

回帖

19

积分

新手上路

积分
19
发表于 2024-10-9 18:45:04 | 显示全部楼层 |阅读模式
tocbot源码解读 tocbot源码解读 魏蕊蕊@贝壳找房 贝壳产品技术 贝壳产品技术 “贝壳产品技术公众号”作为贝壳官方产品技术号,致力打造贝壳产品、技术干货分享平台,面向互联网/O2O开发/产品从业者,每周推送优质产品技术文章、技术沙龙活动及招聘信息等。欢迎大家关注我们。 242篇内容 2020年10月29日 14:12 1 tocbot的介绍使用tocbot可以把HTML代码进行解析,生成一个目录添加到一个容器中,并且在每次滚动经过时会更新位置,对于文档网站或Markdown页面很有帮助,tocbot使浏览更加容易。tocbot使用原生DOM方法,没有依赖关系,可以在启用JavaScript的任何浏览器中运行。2 tocbot源码解读源代码地址:https://github.com/tscanlin/tocbot2.1 代码结构├──package.json├──pages│├──_config.js//网页中所需数据│├──index.js//入口文件,Next.js是围绕page的概念构建的,page是在pages目录中的js/jsx/ts/tsx文件导出的React组件。├──server.js////使用express框架,Next.js一个轻量级的React服务端渲染应用框架。├──src│├──components││└──Template////主要结构文件,针对于在浏览器中展示的结构和样式│├──js││├──build-html.js//将数组转为节点更新渲染到目录容器中││├──default-options.js//默认参数数据││├──index.js////主要逻辑文件,包括tocbot的初始化,销毁和刷新││├──parse-content.js//将节点转为嵌套数组││└──scroll-smooth//滚动功能初始化2.2 源码方法解析源码方法解析主要从提取节点,将节点注入到目录容器以及实现滚动三部分讲明。tocbot.init()方法执行后,首先将默认属性对象和传入的参数对象的自身属性合并成一个对象返回保存在options属性中。主要参数包括:tocSelector目录容器,contentSelector抓取的文章容器,headingSelector抓取的元素,ignoreSelector忽略的元素。2.2.1 提取解析节点如果tocbot对象已经存在,就先销毁。然后执行selectHeadings()方法,该方法传入两个参数,分别是文章容器contentSelector和需要解析的headingSelector。排除忽略的元素,使用querySelectorAll在文章容器中提取需要解析的节点,保存在headingsArray变量中。代码如下:functionselectHeadings(contentSelector,headingSelector){varselectors=headingSelectorif(options.ignoreSelector){selectors=headingSelector.split(',').map(functionmapSelectors(selector){returnselector.trim()+':not('+options.ignoreSelector+')'})}try{returndocument.querySelector(contentSelector).querySelectorAll(selectors)}catch(e){console.warn('Elementnotfound:'+contentSelector);//eslint-disable-linereturnnull}}2.2.2 节点注入到目录容器首先将获取到的需要解析的节点转为嵌套数组。接下来执行nestHeadingsArray()函数,参数为获取到的需要解析的节点数据headingsArray,在该方法中,每个节点都调用一次getHeadingObject()函数,参数为当前节点,将节点的id,名称和内容以及几级,子节点等信息转为一个对象返回保存在变量currentHeading中。然后执行addNode()函数,参数为当前节点对象currentHeading和上次结果数组nest,在数组nest中找到当前节点对象对应的位置插入,最后得到一个嵌套数组保存在nestedHeadings变量中。代码如下:functionnestHeadingsArray(headingsArray){returnreduce.call(headingsArray,functionreducer(prev,curr){varcurrentHeading=getHeadingObject(curr)if(currentHeading){addNode(currentHeading,prev.nest)}returnprev},{nest:[]})}接下来,将嵌套数组转为DOM节点,插入到构建目录的容器中。接着,执行buildHtml文件的render()函数,参数为构建目录的容器tocSelector和获取的嵌套数组nestedHeadings,调用createList()函数,根据options.orderedList变量的值创建一个ul或ol元素作为父容器,给这个元素添加样式。遍历嵌套数组,执行createEl()函数分别给对应元素添加子元素,然后把父容器ul或ol元素添加到tocSelector构建目录的容器中。代码实现如下:functionrender(selector,data){varcollapsed=falsevarcontainer=createList(collapsed)data.forEach(function(d){createEl(d,container)})varparent=document.querySelector(selector)//Returnifnoparentisfound.if(parent===null){return}//Removeexistingchildifitexists.if(parent.firstChild){parent.removeChild(parent.firstChild)}//Justreturntheparentanddon'tappendthelistifnolinksarefound.if(data.length===0){returnparent}//AppendtheElementsthathavebeencreatedreturnparent.appendChild(container)}2.2.3 滚动功能通过点击目录滚动到文章相应位置。根据scrollSmooth属性,如果启用滚动功能,就执行initSmoothScrolling()函数初始化滚动功能,添加onClick点击监听事件,当鼠标点击后,执行回调函数中jump()函数,参数为hash值和由滚动持续时间、偏移量和回调函数组成的对象。根据当前高亮的id元素和点击的id元素计算滚动的高度,外加滑动的持续时间和滑动的偏移量,执行requestAnimationFrame()函数,告诉浏览器希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画,滚动到点击元素指定位置,点击的元素获得焦点。代码实现如下:functionjump(target,options){varstart=window.pageYOffsetvaropt={durationptions.duration,offsetptions.offset||0,callbackptions.callback,easingptions.easing||easeInOutQuad}vartgt=document.querySelector('[id="'+decodeURI(target).split('#').join('')+'"]')vardistance=typeoftarget==='string'opt.offset+(target(tgt&tgt.getBoundingClientRect().top)||0//handlenon-existentlinksbetter.:-(document.documentElement.scrollTop||document.body.scrollTop)):targetvarduration=typeofopt.duration==='function'opt.duration(distance)pt.durationvartimeStartvartimeElapsedrequestAnimationFrame(function(time){timeStart=time;loop(time)})functionloop(time){timeElapsed=time-timeStartwindow.scrollTo(0,opt.easing(timeElapsed,start,distance,duration))if(timeElapsed
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-31 06:33 , Processed in 0.537936 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表