簡書MD語法不識別 [TOC] ,也不會根據標題行(#) 來插入目錄,作為每次看資料喜歡先看目錄把握總體的我來說,很不習慣,查詢跳轉也不方便,所以就考慮自己寫個小指令碼來自動識別並生成目錄; 系統: mac 10.12 chrome: 59.0
前言
-
之前是想參考 Octotree 做個側邊欄目錄, 目錄不隨文章內容滾動而滾動,有點類似ms word的導航窗格,無奈技術不到家,而且要做成
chrome
的extension
的話還得上架(developer模式載入外掛貌似會提示warning,不喜),感覺有點複雜了,放棄; -
使用使用者指令碼管理器 Tampermonkey , 寫個自動識別標題行並生成有序列表的小工具就好,簡單可行;
指令碼地址 上面已經給出了,這裡順便推薦下這個指令碼 Jianshu MD AUTO Scroll ,寫文章時,會同步滾動編輯區和預覽區;
思路
通過識別 h2,h3,h4,h5,h6
標題行,在文章開頭處插入列表, 按標題層級進行縮排, 點選可進行跳轉;
P.S. 由於簡書文章主標題是 h1
, 預設不插入目錄中, 我是從 h2
開始識別的,有需要的話可以自行修改指令碼;
1. html頁面自動跳轉方法
不管哪種方式都得給目標位置標籤新增 id
屬性,而簡書標題行預設都不帶 id
屬性,如下圖:
![預設文章結構.png](https://i.iter01.com/images/c8ab9056fa17cce7710ea2e0b4e1250f8b2ae5341c099bc889aa5cbc7fe721bd.png)
2. 遍歷並新增 id
屬性
由於簡書自帶jquery了,所以可以直接使用;
var menuIndex = 0;
var firstPaddingOrder = 1; //第一個標題行標籤層級 <h1> -> 1 , <h2> -> 2, 第一個層級不用縮排
let titles = $('body').find('h2,h3,h4,h5,h6');
if(titles.length == 0){
return;
}
// 獲取文章中除標題外的第一個目錄行層級
let firstElement = titles.first();
let firstTagName = firstElement[0].tagName;
firstPaddingOrder = parseInt(firstTagName.substring(1));
// 遍歷文章中的所有標題行, 按需新增id值, 並增加記錄到目錄列表中
titles.each(function(){
let tagName = $(this)[0].tagName.toLocaleLowerCase();
let content = $(this).text(); // 標題內容
// 若標題的id不存在,則使用新id
let newTagId =$(this).attr('id');
if(!$(this).attr('id')){
newTagId = 'id_'+menuIndex;
$(this).attr('id',newTagId);
menuIndex++;
// 將搜尋到的標題行資訊插入到目錄中
appendMenuItem(tagName,newTagId,content);
}
});
複製程式碼
3. 在文章開頭處插入列表
通過 chrome
的開發者工具檢視簡書文章,發現文章內容位於 <div class="show-content">...</div>
中,因此可在該 div
起始處插入一個 <ol>
標籤;
// 在 body 標籤內部新增 aside 側邊欄,用於顯示文件目錄
$('.show-content').prepend('<aside id="sideMenu" style="width: 100%; padding: 0px 15px 5px 15px;margin-bottom:20px;background-color: #dedede">目錄</aside>');
$('#sideMenu').append('<ol id="menu_nav_ol" style="list-style:none;margin:0px;padding:0px;">');// 不顯示 li 項前面預設的點標誌, 也不使用預設縮排
複製程式碼
P.S. 之前想做成側邊欄的,所以用了 aside
,懶得改了,先保留吧;
4. 將搜尋到的標題行資訊插入到目錄列表中
這裡做了點優化,按層級進行了縮排,但文章內容預設的第一級標題(h1
不考慮)不縮排,比如,文章一級標題是 h3
,二級標題是 h4
,則生成目錄項時, 從h4
才開始縮排20px;
function appendMenuItem(tagName,id,content){
let paddingLeft = (tagName.substring(1) - firstPaddingOrder) * 20;
$('#menu_nav_ol').append('<li class="' + id +'" style="padding-left: '+ paddingLeft +'px;">' + content + '</li>');
}
複製程式碼
5. 對目錄列表項進行點選跳轉設定
其實上面一步也可以直接生成 <a>
標籤, 那就不需要再做其他操作了,預設點選就可以跳轉到指定區域:
$('#menu_nav_ol').append('<li class="' + id +'" style="padding-left: '+ paddingLeft +'px;"><a href="#'+id+'">' + content + '</a></li>');`
複製程式碼
但正如最開始說的,這種方式會改變url(其實無關緊要),因此我使用的是第四種方式:
// 繫結目錄li點選事件,點選時跳轉到對應的位置
$('#menu_nav_ol li').on('click', function () {
let targetId = $(this).attr('class');
// document.getElementById(id).scrollIntoView();
$("#" + targetId)[0].scrollIntoView(true);
});
複製程式碼
完整指令碼
// ==UserScript==
// @name Jianshu side menu
// @name:zh-CN 簡書目錄
// @description:zh-CN 自動插入目錄
// @namespace https://github.com/lucid-lynxz
// @version 0.1
// @description try to take over the world!
// @author Lynxz
// @match http://www.jianshu.com/p/*
//// @require http://code.jquery.com/jquery-latest.js
// @grant none
// ==/UserScript==
// 簡書文章自動插入目錄的指令碼,用於tampermonkey
// 簡書已自帶jquery了,不需要新增此依賴
var menuIndex = 0;
var firstPaddingOrder = 1; //第一個標題行標籤層級 <h1> -> 1 , <h2> -> 2, 第一個層級不用縮排
function scrollToView(id) {
var element = $("#" + id)[0];
console.log(id + " \n" + element);
// document.getElementById(id).scrollIntoView();
element.scrollIntoView();
}
// 在側邊欄中新增目錄項
function appendMenuItem(tagName, id, content) {
let paddingLeft = (tagName.substring(1) - firstPaddingOrder) * 20;
//$('#menu_nav_ol').append('<li class="' + id + '" style="list-style:none;padding-left: '+ paddingLeft +'px;">' + content + '</li>');
$('#menu_nav_ol').append('<li class="' + id + '" style="padding-left: ' + paddingLeft + 'px;">' + content + '</li>');
//$('#menu_nav_ol').append('<li class="' + id +'" style="padding-left: '+ paddingLeft +'px;"><a href="#'+id+'">' + content + '</a></li>');
}
(function () {
'use strict';
let titles = $('body').find('h2,h3,h4,h5,h6');
if (titles.length == 0) {
return;
}
// 在 body 標籤內部新增 aside 側邊欄,用於顯示文件目錄
$('.show-content').prepend('<aside id="sideMenu" style="width: 100%; padding: 0px 15px 5px 15px;margin-bottom:20px;background-color: #dedede">目錄</aside>');
$('#sideMenu').append('<ol id="menu_nav_ol" style="list-style:none;margin:0px;padding:0px;">');// 不顯示 li 項前面預設的點標誌, 也不使用預設縮排
// 獲取文章中除標題外的第一個目錄行層級
let firstElement = titles.first();
let firstTagName = firstElement[0].tagName;
firstPaddingOrder = parseInt(firstTagName.substring(1));
// 遍歷文章中的所有標題行, 按需新增id值, 並增加記錄到目錄列表中
titles.each(function () {
let tagName = $(this)[0].tagName.toLocaleLowerCase();
let content = $(this).text();
// console.log('oriId = '+$(this).attr('id') + '\t menuIndex = ' + menuIndex);
// 若標題的id不存在,則使用新id
let newTagId = $(this).attr('id');
if (!$(this).attr('id')) {
newTagId = 'id_' + menuIndex;
$(this).attr('id', newTagId);
menuIndex++;
}
// console.log('newId = ' +newTagId);
appendMenuItem(tagName, newTagId, content);
});
$('#sideMenu').append('</ol>');
// 繫結目錄li點選事件,點選時跳轉到對應的位置
$('#menu_nav_ol li').on('click', function () {
let targetId = $(this).attr('class');
// document.getElementById(id).scrollIntoView();
$("#" + targetId)[0].scrollIntoView(true);
});
})();
複製程式碼
P.S. 功能和程式碼都很簡單,但使用, 另外寫了兩個小指令碼,有需要的也可以安裝下: