TreeBar - 前端博客目录大纲导航

显示文章目录导航

当前为 2017-10-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name TreeBar - 前端博客目录大纲导航
  3. // @namespace https://github.com/zhilidali/
  4. // @version 0.1
  5. // @description 显示文章目录导航
  6. // @author zhilidali
  7. // @match http://www.jianshu.com/p/*
  8. // @match http*://juejin.im/post/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. var map = {
  16. jianshu: {
  17. tagName: '.show-content',
  18. style: `
  19. .zhilidali {
  20. top: 60px;
  21. right: 0;
  22. border-color: #ea6f5a;
  23. }
  24. .zhilidali-btn {
  25. border-color: #ea6f5a;
  26. background-color: #ea6f5a;
  27. color: #fff;
  28. }
  29. .zhilidali > ul > li a {
  30. color: #ea6f5a;
  31. }
  32. .zhilidali > ul > li a:hover {
  33. color: rgb(236, 97, 73);
  34. }
  35. `
  36. },
  37. juejin: {
  38. tagName: '.post-content-container',
  39. style: `
  40. .zhilidali {
  41. top: 60px;
  42. right: 0;
  43. }
  44. .zhilidali-btn {
  45. border-color: rgba(3, 113, 233, 1);
  46. background-color: rgba(3, 113, 233, 1);
  47. color: #fff;
  48. }
  49. .zhilidali > ul > li a {
  50. color: rgba(20, 20, 20, .8);
  51. }
  52. .zhilidali > ul > li a:hover {
  53. color: rgba(20, 20, 20, 1);
  54. }
  55. `
  56. },
  57. default: {
  58. tagName: 'body',
  59. style: `
  60. .zhilidali {
  61. top: 10%;
  62. right: 1%;
  63. border-color: #555;
  64. }
  65. .zhilidali-btn {
  66. background-color: #fff;
  67. color: #000;
  68. }
  69. .zhilidali > ul > li a {
  70. color: #0366d6;
  71. }
  72. `
  73. }
  74. };
  75. window.zhilidali = {
  76. site: {
  77. name: '',
  78. tagName: '',
  79. },
  80. className: `zhilidali`,
  81. style: `
  82. .zhilidali {
  83. position: fixed;
  84. max-width: 300px;
  85. max-height: 90%;
  86. overflow-y: auto;
  87. padding: 10px;
  88. border: 1px solid #ddd;
  89. background-color: rgba(255, 255, 255, .9);
  90. }
  91. .zhilidali-btn {
  92. display: inline-block;
  93. padding: .3em 1.2em;
  94. border: 1px solid #333;
  95. border-radius: 3px;
  96. text-align: center;
  97. vertical-align: middle;
  98. outline: none;
  99. cursor: pointer;
  100. }
  101. .zhilidali ul {
  102. padding-left: 1em;
  103. margin: 0;
  104. }
  105. .zhilidali > ul > li a {
  106. line-height: 30px;
  107. /*overflow: hidden;
  108. white-space: nowrap;
  109. text-overflow: ellipsis;*/
  110. text-decoration: none;
  111. font-size: 14px;
  112. cursor: pointer;
  113. }
  114. .zhilidali > ul > li a:hover {
  115. text-decoration: underline;
  116. }`,
  117. innerDom: `<div><button class="zhilidali-btn">Toggle</button></div>`
  118. };
  119.  
  120. window.onload = function() {
  121. // 0. 匹配站点
  122. matchSite();
  123. // 1. 获取DOM
  124. var wrap = document.querySelector(zhilidali.site.tagName),
  125. hList = wrap.querySelectorAll('h1, h2, h3, h4, h5, h6');
  126. // 2. 构建数据
  127. var tree = transformTree(Array.from(hList));
  128. // 3. 构建DOM
  129. createDom(zhilidali, tree);
  130. // 4. 定义事件
  131. document.querySelector('.zhilidali-btn').onclick = function () {
  132. var ul = document.querySelector('.zhilidali > ul');
  133. ul.style.display = ul.style.display === 'none' ? 'block' : 'none';
  134. };
  135. console.log('zhilidali');
  136. };
  137.  
  138. /* 匹配站点 */
  139. function matchSite() {
  140. var domain = location.href.match(/([\d\w]+)\.(com|cn|im)/i);
  141. zhilidali.site.name = (domain && domain[1]) || 'default';
  142. var siteInfo = map[zhilidali.site.name];
  143. zhilidali.site.tagName = siteInfo.tagName;
  144. zhilidali.style += siteInfo.style;
  145. }
  146.  
  147. /* 解析DOM,构建树形数据 */
  148. function transformTree(list) {
  149. var result = [];
  150. list.reduce(function (res, cur, index, arr) {
  151. var prev = res[res.length - 1];
  152. if (compare(prev, cur)) {
  153. if (!prev.sub) prev.sub = [];
  154. prev.sub.push(cur);
  155. if (index === arr.length - 1) prev.sub = transformTree(prev.sub);
  156. } else {
  157. construct(res, cur);
  158. if (prev && prev.sub) prev.sub = transformTree(prev.sub);
  159. }
  160. return res;
  161. }, result);
  162.  
  163. // 转为树形结构的条件依据
  164. function compare(prev, cur) {
  165. return prev && cur.tagName.replace(/h/i, '') > prev.tagName.replace(/h/i, '');
  166. }
  167.  
  168. // 转为树形结构后的数据改造
  169. function construct(arr, obj) {
  170. arr.push({
  171. name: obj.innerText,
  172. id: obj.innerText,
  173. tagName: obj.tagName
  174. });
  175. }
  176.  
  177. return result;
  178. }
  179.  
  180. /* 创建DOM */
  181. function createDom(zhilidali, tree) {
  182. var style = document.createElement('style'),
  183. dom = document.createElement('div');
  184. style.innerHTML = zhilidali.style;
  185. document.head.appendChild(style);
  186. dom.className = zhilidali.className;
  187. dom.innerHTML = zhilidali.innerDom + compileList(tree);
  188. document.body.appendChild(dom);
  189. }
  190.  
  191. /* 根据数据构建目录 */
  192. function compileList(tree) {
  193. var list = '';
  194. tree.forEach(function(item) {
  195. var ul = item.sub ? compileList(item.sub) : '';
  196. list +=
  197. `<li>
  198. <a href="#${item.id}" title="${item.name}">${item.name}</a>${ul}
  199. </li>`;
  200. });
  201. return `<ul>${list}</ul>`;
  202. }
  203.  
  204. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址