js实现文章目录生成
HTML
<!-- 目录块 -->
<div id="directory"></div>
<!-- 文章块 -->
<div id="article">
<h2><a id=\"1_0\"></a>1、前沿</h2>\n<h3><a id=\"11SSR_1\"></a>1.1、什么是SSR</h3>\n<blockquote>\n<p>SSR(服务端渲染)顾名思义就是将页面在服务端渲染完成后在客户端直接展示。</p>\n</blockquote>\n<h3><a id=\"12_4\"></a>1.2、客户端渲染与服务端渲染的区别</h3>\n<h5><a id=\"SPA_5\"></a>传统的SPA模式</h5>\n<blockquote>\n<p>即客户端渲染的模式</p>\n</blockquote>\n<ol>\n<li>\n<p>Vue.js构建的应用程序,默认情况下是有一个html模板页,然后通过webpack打包生成一堆js、css等等资源文件。然后塞到index.html中</p>\n</li>\n<li>\n<p>用户输入url访问页面 -> 先得到一个html模板页 -> 然后通过异步请求服务端数据 -> 得到服务端的数据 -> 渲染成局部页面 -> 用户</p>\n</li>\n</ol>\n<h5><a id=\"SSR_11\"></a>SSR模式</h5>\n<blockquote>\n<p>即服务端渲染模式</p>\n</blockquote>\n<ol>\n<li>用户输入url访问页面 -> 服务端接收到请求 -> 将对应请求的数据渲染完一个网页 -> 返回给用户</li>\n</ol>\n<h3><a id=\"13SSR_16\"></a>1.3、为什么要使用SSR呢?</h3>\n<blockquote>\n<p>ssr的好处<a href=\"https://ssr.vuejs.org/zh/\" target=\"_blank\">官网</a>已经给出,最有意思的两个优点如下:</p>\n</blockquote>\n<ol>\n<li>更有好的SEO。由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。</li>\n<li>更快的内容到达时间(time-to-content)</li>\n</ol>\n<h3><a id=\"14SSR_22\"></a>1.4、SSR原理</h3>\n<p>这是vue.js官方的SSR原理介绍图,从这张图片,我们可以知道:我们需要通过Webpack打包生成两份bundle文件:</p>\n<ul>\n<li>Client Bundle,给浏览器用。和纯Vue前端项目Bundle类似</li>\n<li>Server Bundle,供服务端SSR使用,一个json文件</li>\n</ul>\n<p>不管你项目先前是什么样子,是否是使用vue-cli生成的。都会有这个构建改造过程。在构建改造这里会用到 vue-server-renderer 库,这里要注意的是 vue-server-renderer 版本要与Vue版本一样。</p>\n<p><img src=\"https://user-gold-cdn.xitu.io/2018/9/12/165cd418d72891ad?w=1946&h=892&f=png&s=138551\" alt=\"\" /></p>\n<h2><a id=\"2vuecli3_SSR_33\"></a>2、开始构建基于vue-cli3 的SSR应用程序</h2>\n<blockquote>\n<p>了解ssr原理后,来开始step by step搭建一个自己的SSR应用程序</p>\n</blockquote>\n<ol>\n<li>安装vue-cli3</li>\n</ol>\n<p>全局安装vue-cli脚手架</p>\n<pre><div class=\"hljs\"><code class=\"lang-bash\">npm install @vue/cli -g --registry=https://registry.npm.taobao.org\n</code></div></pre>\n<ol start=\"2\">\n<li>创建一个vue项目</li>\n</ol>\n<pre><div class=\"hljs\"><code class=\"lang-bash\">vue create ssr-example...
CSS
ul li {
list-style: none
}
JavaScript
(function(global) {
// 查找子元素
var children = function children(childNodes, reg) {
var result = [],
isReg = typeof reg === 'object',
isStr = typeof reg === 'string',
node, i, len;
for (i = 0, len = childNodes.length; i < len; i++) {
node = childNodes[i];
if ((node.nodeType === 1 || node.nodeType === 9) &&
(!reg ||
isReg && reg.test(node.tagName.toLowerCase()) ||
isStr && node.tagName.toLowerCase() === reg)) {
result.push(node);
}
}
return result;
},
// 创建目录
createDirectory = function(article, directory, isDirNum) {
var contentArr = [],
titleId = [],
levelArr, root, level,
currentList, list, li, link, i, len;
// 获取标题编号 标题内容
levelArr = (function(article, contentArr, titleId) {
var titleElem = children(article.childNodes, /^h\d$/),
levelArr = [],
lastNum = 1,
lastRevNum = 1,
count = 0,
guid = 1,
id = 'directory' + (Math.random() + '').replace(/\D/, ''),
lastRevNum, num, elem;
while (titleElem.length) {
elem = titleElem.shift();
// 保存标题内容
contentArr.push(elem.innerHTML);
// 当前的标题编号
num = +elem.tagName.match(/\d/)[0];
// 修正
if (num > lastNum) {
levelArr.push(1);
lastRevNum += 1;
} else if (num === lastRevNum ||
num > lastRevNum && num <= lastNum) {
levelArr.push(0);
lastRevNum = lastRevNum;
} else if (num < lastRevNum) {
levelArr.push(num - lastRevNum);
lastRevNum = num;
...