簡書自動生成目錄小工具

我啥時候說啦jj發表於2017-12-28

簡書MD語法不識別 [TOC] ,也不會根據標題行(#) 來插入目錄,作為每次看資料喜歡先看目錄把握總體的我來說,很不習慣,查詢跳轉也不方便,所以就考慮自己寫個小指令碼來自動識別並生成目錄; 系統: mac 10.12 chrome: 59.0

一年過去了依然不支援.jpg
效果圖.png

簡書目錄指令碼地址

前言

  1. 之前是想參考 Octotree 做個側邊欄目錄, 目錄不隨文章內容滾動而滾動,有點類似ms word的導航窗格,無奈技術不到家,而且要做成 chromeextension 的話還得上架(developer模式載入外掛貌似會提示warning,不喜),感覺有點複雜了,放棄;

  2. 使用使用者指令碼管理器 Tampermonkey , 寫個自動識別標題行並生成有序列表的小工具就好,簡單可行;

指令碼地址 上面已經給出了,這裡順便推薦下這個指令碼 Jianshu MD AUTO Scroll ,寫文章時,會同步滾動編輯區和預覽區;

思路

通過識別 h2,h3,h4,h5,h6 標題行,在文章開頭處插入列表, 按標題層級進行縮排, 點選可進行跳轉; P.S. 由於簡書文章主標題是 h1 , 預設不插入目錄中, 我是從 h2 開始識別的,有需要的話可以自行修改指令碼;

1. html頁面自動跳轉方法

不管哪種方式都得給目標位置標籤新增 id 屬性,而簡書標題行預設都不帶 id 屬性,如下圖:

預設文章結構.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. 功能和程式碼都很簡單,但使用, 另外寫了兩個小指令碼,有需要的也可以安裝下:

  1. CSDN廣告清除請自適應寬度
  2. 掘金部落格文章不登入直接顯示全文

相關文章