// ==UserScript== // @name TreeBar - 前端博客目录大纲导航 // @namespace https://github.com/zhilidali/ // @version 0.1 // @description 显示文章目录导航 // @author zhilidali // @match http://www.jianshu.com/p/* // @match http*://juejin.im/post/* // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; var map = { jianshu: { tagName: '.show-content', style: ` .zhilidali { top: 60px; right: 0; border-color: #ea6f5a; } .zhilidali-btn { border-color: #ea6f5a; background-color: #ea6f5a; color: #fff; } .zhilidali > ul > li a { color: #ea6f5a; } .zhilidali > ul > li a:hover { color: rgb(236, 97, 73); } ` }, juejin: { tagName: '.post-content-container', style: ` .zhilidali { top: 60px; right: 0; } .zhilidali-btn { border-color: rgba(3, 113, 233, 1); background-color: rgba(3, 113, 233, 1); color: #fff; } .zhilidali > ul > li a { color: rgba(20, 20, 20, .8); } .zhilidali > ul > li a:hover { color: rgba(20, 20, 20, 1); } ` }, default: { tagName: 'body', style: ` .zhilidali { top: 10%; right: 1%; border-color: #555; } .zhilidali-btn { background-color: #fff; color: #000; } .zhilidali > ul > li a { color: #0366d6; } ` } }; window.zhilidali = { site: { name: '', tagName: '', }, className: `zhilidali`, style: ` .zhilidali { position: fixed; max-width: 300px; max-height: 90%; overflow-y: auto; padding: 10px; border: 1px solid #ddd; background-color: rgba(255, 255, 255, .9); } .zhilidali-btn { display: inline-block; padding: .3em 1.2em; border: 1px solid #333; border-radius: 3px; text-align: center; vertical-align: middle; outline: none; cursor: pointer; } .zhilidali ul { padding-left: 1em; margin: 0; } .zhilidali > ul > li a { line-height: 30px; /*overflow: hidden; white-space: nowrap; text-overflow: ellipsis;*/ text-decoration: none; font-size: 14px; cursor: pointer; } .zhilidali > ul > li a:hover { text-decoration: underline; }`, innerDom: `
` }; window.onload = function() { // 0. 匹配站点 matchSite(); // 1. 获取DOM var wrap = document.querySelector(zhilidali.site.tagName), hList = wrap.querySelectorAll('h1, h2, h3, h4, h5, h6'); // 2. 构建数据 var tree = transformTree(Array.from(hList)); // 3. 构建DOM createDom(zhilidali, tree); // 4. 定义事件 document.querySelector('.zhilidali-btn').onclick = function () { var ul = document.querySelector('.zhilidali > ul'); ul.style.display = ul.style.display === 'none' ? 'block' : 'none'; }; console.log('zhilidali'); }; /* 匹配站点 */ function matchSite() { var domain = location.href.match(/([\d\w]+)\.(com|cn|im)/i); zhilidali.site.name = (domain && domain[1]) || 'default'; var siteInfo = map[zhilidali.site.name]; zhilidali.site.tagName = siteInfo.tagName; zhilidali.style += siteInfo.style; } /* 解析DOM,构建树形数据 */ function transformTree(list) { var result = []; list.reduce(function (res, cur, index, arr) { var prev = res[res.length - 1]; if (compare(prev, cur)) { if (!prev.sub) prev.sub = []; prev.sub.push(cur); if (index === arr.length - 1) prev.sub = transformTree(prev.sub); } else { construct(res, cur); if (prev && prev.sub) prev.sub = transformTree(prev.sub); } return res; }, result); // 转为树形结构的条件依据 function compare(prev, cur) { return prev && cur.tagName.replace(/h/i, '') > prev.tagName.replace(/h/i, ''); } // 转为树形结构后的数据改造 function construct(arr, obj) { arr.push({ name: obj.innerText, id: obj.innerText, tagName: obj.tagName }); } return result; } /* 创建DOM */ function createDom(zhilidali, tree) { var style = document.createElement('style'), dom = document.createElement('div'); style.innerHTML = zhilidali.style; document.head.appendChild(style); dom.className = zhilidali.className; dom.innerHTML = zhilidali.innerDom + compileList(tree); document.body.appendChild(dom); } /* 根据数据构建目录 */ function compileList(tree) { var list = ''; tree.forEach(function(item) { var ul = item.sub ? compileList(item.sub) : ''; list += `