自动抽取文章的标题|一键生成文章目录

自动抽取文章的标题, 生成目录树, 可跳转, 可拖拽

  1. // ==UserScript==
  2. // @name 自动抽取文章的标题|一键生成文章目录
  3. // @name:en Auto Extract Article Title|Generate article table of contents with one click
  4. // @namespace http://life666.top/
  5. // @version 0.2
  6. // @description 自动抽取文章的标题, 生成目录树, 可跳转, 可拖拽
  7. // @description:en Automatically extract the title of the article, generate table of content, jump, drag and drop
  8. // @author Nisus Liu
  9. // @license MIT
  10. // @match *://cuiqingcai.com/*
  11. // @match *://juejin.cn/*
  12. // @match *://*.zhihu.com/*
  13. // @match *://*.cnblogs.com/*
  14. // @match *://*.notion.so/*
  15. // @match *://segmentfault.com/*
  16. // @match *://*.csdn.net/*
  17. // @icon https://www.google.com/s2/favicons?sz=64&domain=gf.qytechs.cn
  18. // @grant none
  19. // @require https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/limonte-sweetalert2/11.4.4/sweetalert2.all.min.js
  20. // @require https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js
  21. // ==/UserScript==
  22.  
  23.  
  24. (function () {
  25. 'use strict';
  26. // Your code here...
  27. // console.log('[Auto Extract Article Title] script starting ...')
  28. // Swal.fire('傻子都会计算机')
  29. console.log(`[Auto Extract Article Title] ${document.domain}`)
  30.  
  31. let $tmTocW = $("<div class='TM-AEAT-toc-w'></div>");
  32. let $tocTtn;
  33. let hasExtracted = false;
  34. $tocTtn = $('<button class="TM-AEAT-toc-btn">抽取标题</button>');
  35. $tocTtn.appendTo('body');
  36. $tocTtn.on('click', function () {
  37. if (!hasExtracted) {
  38. extractToc();
  39. } else {
  40. removeToc();
  41. }
  42. })
  43.  
  44. const idGenerater = (() => {
  45. let id = 0;
  46. return function () {
  47. return ++id;
  48. }
  49. })()
  50.  
  51. /**
  52. * 抽取标题, 生成 TOC
  53. */
  54. function extractToc() {
  55. // h1~h6
  56. let $headers = $(":header");
  57. // console.log($headers)
  58. let hs = []
  59. $headers.each((ix, ele) => hs.push(ele))
  60. // console.log(hs)
  61. let $tmToc = $("<div id='TM-AEAT-toc' class='TM-AEAT-toc'></div>");
  62. $tmTocW.appendTo("body");
  63. $tmTocW.append($tmToc);
  64. let tmpLvls = [0, 0, 0, 0, 0, 0]; // 支持6级标题
  65. hs.forEach(h => {
  66. // <p class="h2 TM-AEAT-toc-item"><span class="TM-AEAT-toc-item-seq">序号</span> 标题内容 </p>
  67. let hTitle = h.innerText;
  68. // 这里需要克隆节点, 否则就是'移动'的效果了
  69. // let tocH = h.cloneNode(true);
  70. let tocHName = h.tagName.toLowerCase();
  71. let lvl = parseInt(tocHName.substring(1));
  72. let seq = '';
  73. if (lvl >= 1 && lvl <= 6) {
  74. tmpLvls[lvl - 1] += 1; // 当前级别的标题序号增 1
  75. // 当前层级及之前的序号拼接起来就是需要的序号
  76. seq = tmpLvls.slice(0, lvl).join('.');
  77. }
  78.  
  79. let hId = h.getAttribute('id');
  80. if (hId == null) {
  81. hId = 'TM-AEAT-' + idGenerater();
  82. h.setAttribute('id', hId);
  83. }
  84.  
  85. let $tocItem = $(`<p class="${tocHName} TM-AEAT-toc-item"><span class="TM-AEAT-toc-item-seq">${seq}</span><a href="#${hId}">${hTitle}</a></p>`);
  86. // $(tocH).addClass(`TM-AEAT-toc-header-${lvl}`);
  87. if (lvl > 1) {
  88. $tocItem.css("text-indent", `${lvl - 1}em`);
  89. }
  90. $tmToc.append($tocItem);
  91. })
  92.  
  93. hasExtracted = true;
  94. $tocTtn.text('取消抽取');
  95. $tocTtn.addClass('extracted');
  96.  
  97. listenDrag();
  98. }
  99.  
  100. /**
  101. * 溢出 TOC
  102. */
  103. function removeToc() {
  104. $tmTocW.empty();
  105. $tmTocW.remove();
  106. $tocTtn.text('抽取标题');
  107. $tocTtn.removeClass('extracted');
  108. hasExtracted = false;
  109. }
  110.  
  111. setCustomStyle();
  112.  
  113. function listenDrag() {
  114. // 拖拽能力
  115. // 鼠标的当前位置
  116. let x = 0;
  117. let y = 0;
  118.  
  119. // 找到要拖拽的元素
  120. const ele = document.getElementById('TM-AEAT-toc');
  121.  
  122. // 处理鼠标按下事件
  123. // 用户拖拽时触发
  124. const mouseDownHandler = function (e) {
  125. // 获取到鼠标位置
  126. x = e.clientX;
  127. y = e.clientY;
  128.  
  129. // 对document增加监听鼠标移动事件和鼠标松开事件
  130. document.addEventListener('mousemove', mouseMoveHandler);
  131. document.addEventListener('mouseup', mouseUpHandler);
  132. };
  133.  
  134. const mouseMoveHandler = function (e) {
  135. // 鼠标移动的距离
  136. const dx = e.clientX - x;
  137. const dy = e.clientY - y;
  138.  
  139. // 设置元素的位置
  140. ele.style.top = `${ele.offsetTop + dy}px`;
  141. ele.style.left = `${ele.offsetLeft + dx}px`;
  142.  
  143. // 重新分配鼠标的坐标
  144. x = e.clientX;
  145. y = e.clientY;
  146. };
  147.  
  148. const mouseUpHandler = function () {
  149. // 取消对document对象的事件监听
  150. document.removeEventListener('mousemove', mouseMoveHandler);
  151. document.removeEventListener('mouseup', mouseUpHandler);
  152. };
  153.  
  154. ele.addEventListener('mousedown', mouseDownHandler);
  155. }
  156.  
  157. function setCustomStyle() {
  158. //获取 style 节点
  159. let domStyle = document.createElement('style');
  160. domStyle.type = 'text/css';
  161. domStyle.rel = 'stylesheet';
  162. //追加文本节点, 文本节点里内容就是 css 样式长字符串
  163. domStyle.appendChild(document.createTextNode(`
  164. .TM-AEAT-toc-w {
  165. position:relative;
  166. }
  167. .TM-AEAT-toc {
  168. background: #e8f3ffcc;
  169. position: fixed;
  170. top: 40px;
  171. z-index: 10000;
  172. font-size: 16px;
  173. width: 20vw;
  174. border-radius: 0.3em;
  175. box-shadow: 0 0 10px #a2aab4cc;
  176. }
  177. .TM-AEAT-toc-btn {
  178. position: fixed;
  179. bottom: 40px;
  180. left: 20px;
  181. z-index: 20000;
  182. border: none;
  183. outline: none;
  184. background-color: red;
  185. color: white;
  186. cursor: pointer;
  187. padding: 15px;
  188. border-radius: 50%;
  189. opacity:0.5;
  190. }
  191. .TM-AEAT-toc-item-seq {
  192. color: #ff7f7f;
  193. margin-right: .5em;
  194. }
  195. `));
  196. let domHead = document.getElementsByTagName('head')[0];
  197. domHead.appendChild(domStyle);
  198. }
  199.  
  200.  
  201. })();

QingJ © 2025

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