简书自动生成目录小工具

作者: 冰川孤辰js | 来源:发表于2017-07-12 10:04 被阅读4362次

    简书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. 掘金博客文章不登录直接显示全文

    相关文章

      网友评论

        本文标题:简书自动生成目录小工具

        本文链接:https://www.haomeiwen.com/subject/odivhxtx.html