MarkdownPad2导出HTML支持[TOC]

为什么&效果图

为什么

为什么要吃力不讨好的实现这个功能呢?

[TOC]语法挺有用的,特别是标题较多的时候

百度上并未找到MarkdownPad2导出HTML支持[TOC]的完美方案

顺便锻炼一下JavaScript

效果图

想要实现什么样的效果呢?No picture, no bibi.

impressionDrawing.png

最后测试用的Markdown语法栗子内容如下:

# 《Vue2.0开发去哪儿网App》知识点

[TOC]

## 深入理解Vue组件

### 4-8 动态组件与v-once指令

#### 动态组件

#### v-once指令

## Vue中的动画特效

### 5-1 Vue动画 - Vue中的CSS动画原理

#### 动画原理

### 5-2 在Vue中使用animate.css库

#### keyframes动画

#### 自定义类名

#### animate.css库

动手实现

开始动手实现吧~

实现的HTML效果

等等,莫急,方案都没想好,怎么编码...

例如,Markdown语法如下

# 一

[TOC]

## 二

### 三

## 二

我们期望展示的效果如下图,且发现Markdown语法中的#、##等标题最终转换为HTML中的

等元素。

[TOC]转换为

[TOC]

,显然

[TOC]

无法满足我们的期望,所以这里就是我们需要编码实现的地方。

htmlDom.png

那么,我们要将

[TOC]

,转换成什么样子呢?

为啥要转换成这样子呢?因为这样子就能显示我们想要的效果呀。

为啥ul和li元素有一个data-level属性呢?看名字就知道是为了方便知道目前所在的层级。

那么我们先把上面的理解一下吧

首先,将p元素的[TOC]替换为div元素,且该div元素有一个叫toc的class

接着,要实现层次效果,我们需要用到ul、li元素,搭建一级标题吧

放到chrome中看看效果呢

data-level=1.png

继续搭,不准停...

继续放到chrome中

data-level=2.png

那如果有两个标题二呢?再加个li呗

继续放到chrome中,很棒

data-level=2_2.png

如果又要在第一个标题二下加一个标题三呢?

data-level=3.png

想要的效果就完成啦,棒棒哒~

那么我们通过JavaScript要实现的过程大概也就是酱紫滴

编码

边编码,边讲解方案

初始HTML

MarkdownPad2导出HTML支持[TOC]

[TOC]

引入jquery.js,加入h1、p、h2等元素,效果如下

codeInitial.png

整改p元素

步骤:

创建class为toc的div元素

找到p元素,怎么找通过[TOC]来找p元素

将p元素的文本元素清空,并将步骤1中的div元素append到该p元素上

$(document).ready(function() {

// 创建class为toc的div元素

let $toc = $('

$toc.attr('class', 'toc');

// 清除p元素的文本元素,并将$toc元素append到p元素

$('p:contains([TOC]):first').text('').append($toc);

});

如果Markdown文档中有多个[TOC]语法,我们只取第一个,其余的不做转换,谁没事搞这么多个[TOC]呢,是不?当然有人站出来说,一定要有多个[TOC],行行行,那你把:first出去就行了。

另外,这个代码还有点小缺陷,如果有些人习惯用[toc]呢?发现

[toc]

并没有变化,所以需要整改一下

$(document).ready(function() {

// 新增Contains选择器,:contains的变异版,增加忽略大小写功能

$.expr[':'].Contains = function(a, i, m){

return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;

};

// 创建class为toc的div元素

let $toc = $('

$toc.attr('class', 'toc');

// 清除p元素的文本内容,并将$toc元素append到p元素

$('p:Contains([TOC]):first').text('').append($toc);

});

新增了一个:Contains,与:contains功能一样增加忽略大小写功能,这样就算写成[toc]也是没问题了,效果如下

htmlP.png

实现hx元素转换

下一步当然就是得往

处理第一个hx元素的步骤:

获取Markdown文档中所有hx元素$headers

获取第一个hx元素firstHeader,并获取第一个hx元素的层级firstLevel

对firstLevel循环处理,创建ul、li元素并按层级append

ul、li元素append完成后,找到firstLevel对应的li元素,并append一个a元素用于显示标题内容

// 获取h1-h6元素

let $headers = $('h1,h2,h3,h4,h5,h6');

// 获取第一个hx元素,注意是dom对象,非jQuery对象

let firstHeader = $headers[0];

if (firstHeader) {

// 获取第一个hx元素的层级

let firstLevel = parseInt(firstHeader.tagName.

replace('H', ''), 10);

// 给a元素唯一的href属性值

let id = `${firstHeader.textContent}-0`;

for (let i = 1; i <= firstLevel; i++) {

// 创建ul和li元素,并添加data-level属性

let $ul = $('

$li = $('

');

$li.attr('data-level', i);

$ul.attr('data-level', i).append($li);

// 获取data-level为i-1的li元素

let $pLi = $toc.find(`li[data-level=${i - 1}]`);

if ($pLi.length > 0) {

// 找到data-level为i-1的元素,直接append到该li元素上即可

$pLi.append($ul);

} else {

// 未找到data-level为i-1的元素,说明是顶层的ul,

// 直接append到class为toc的div元素上

$toc.append($ul);

}

}

// 找到所属层级的li元素,并添加a元素

$toc.find(`li[data-level=${firstLevel}]`).append(

$(`${firstHeader.textContent}`));

// 与a元素的href对应,用于文档内跳转

$headers.eq(0).attr('id', id);

}

$headers内容如下:

jqHeaders.png

界面效果如下:

htmlFirstHeader1.png

如果Markdown文档中没有从#开始,直接用了##,那么我们试下效果(相当于把文档中的

删除)

htmlFirstHeader2.png

效果ok,就是有点小问题,a元素在chrome中呈现下划线效果,建议去掉,所以增加以下代码,把原来的

加回来,嗯,现在效果完美了

.toc a {

text-decoration: none;

}

htmlFirstHeader3.png

处理后续hx元素的步骤:

从第二个hx元素开始,循环

获取当前hx的层级以及上一个hx的层级

当当前层级大于上一个层级,则从上一个层级+1到当前层级做循环添加ul和li元素

如果当前层级和上一个层级相等,则找到相同层级的li元素的父元素,创建li元素并添加上去

// 如果当前层级小于上一个层级,则找到最后一个相同层级的li元素的父元素,添加$l

设置hx元素的id,与a的href保持一致

// 从第二个hx元素开始,循环$headers

for (let i = 1; i < $headers.length; i++) {

// 获取当前的hx元素的层级以及上一个hx元素的层级

let curLevel = parseInt($headers[i].tagName.replace('H', ''),

10),

lastLevel = parseInt($headers[i - 1].tagName.

replace('H', ''), 10);

// 当前hx元素的文本元素

let textContent = $headers[i].textContent,

id = `${textContent}-i`;

// 给a元素唯一的href属性值,与hx元素的id对应

let $a = $(`${textContent}`);

if (lastLevel < curLevel) {

// 如果当前层级比上一个层级大,则从上一个层级+1到当前层级循环,

// 循环添加ul和li元素

for (let j = lastLevel + 1; j <= curLevel; j++) {

// 创建ul和li元素,并添加data-level属性

let $u = $('

$l = $('

');

$l.attr('data-level', j);

$u.attr('data-level', j).append($l);

// 找到data-level为j-1的最后一个li元素,并添加$u

$toc.find(`li[data-level=${j - 1}]:last`).append($u);

}

// 找到data-level为curLevel的最后一个li,并添加$a

$toc.find(`li[data-level=${curLevel}]:last`).append($a);

} else if (lastLevel === curLevel) {

// 如果当前层级和上一个层级相等,则找到相同层级的li元素的父元素,

// 创建li元素并添加上去

// 已经存在data-level为curLevel的ul,只需要创建li即可

let $l = $('

');

// 给li元素添加data-level树形,并添加$a

// 找到data-level为curLevel的最后一个li元素的父元素,添加$l

$toc.find(`li[data-level=${curLevel}]:last`).parent().

append($l.attr('data-level', curLevel).append($a));

} else {

// 如果当前层级小于上一个层级,则找到最后一个相同层级的li元素的

// 父元素,添加$l

// 找到data-level为curLevel的最后一个li元素,必然存在

let $sublingLi = $toc.

find(`li[data-level=${curLevel}]:last`);

let $l = $('

');

// 找到$sublingLi的父元素,添加li元素即可

$sublingLi.parent().append($l.attr('data-level', curLevel).

append($a));

}

$headers.eq(i).attr('id', id);

}

全部代码如下:

MarkdownPad2导出HTML支持[TOC]

.toc a {

text-decoration: none;

}

[TOC]

$(document).ready(function() {

// 新增Contains选择器,:contains的变异版,增加忽略大小写功能

$.expr[':'].Contains = function(a, i, m){

return jQuery(a).text().toUpperCase().indexOf(m[3].

toUpperCase()) >= 0;

};

// 创建class为toc的div元素

let $toc = $('

$toc.attr('class', 'toc');

// 获取h1-h6元素

let $headers = $('h1,h2,h3,h4,h5,h6');

// 获取第一个hx元素,注意是dom对象,非jQuery对象

let firstHeader = $headers[0];

if (firstHeader) {

// 获取第一个hx元素的层级

let firstLevel = parseInt(firstHeader.tagName.

replace('H', ''), 10);

// 给a元素唯一的href属性值

let id = `${firstHeader.textContent}-0`;

for (let i = 1; i <= firstLevel; i++) {

// 创建ul和li元素,并添加data-level属性

let $ul = $('

$li = $('

');

$li.attr('data-level', i);

$ul.attr('data-level', i).append($li);

// 获取data-level为i-1的li元素

let $pLi = $toc.find(`li[data-level=${i - 1}]`);

if ($pLi.length > 0) {

// 找到data-level为i-1的元素,直接append到该li元素上即可

$pLi.append($ul);

} else {

// 未找到data-level为i-1的元素,说明是顶层的ul,

// 直接append到class为toc的div元素上

$toc.append($ul);

}

}

// 找到所属层级的li元素,并添加a元素

$toc.find(`li[data-level=${firstLevel}]`).append(

$(`${firstHeader.textContent}`));

// 与a元素的href对应,用于文档内跳转

$headers.eq(0).attr('id', id);

}

// 从第二个hx元素开始,循环$headers

for (let i = 1; i < $headers.length; i++) {

// 获取当前的hx元素的层级以及上一个hx元素的层级

let curLevel = parseInt($headers[i].tagName.replace('H', ''),

10),

lastLevel = parseInt($headers[i - 1].tagName.

replace('H', ''), 10);

// 当前hx元素的文本元素

let textContent = $headers[i].textContent,

id = `${textContent}-i`;

// 给a元素唯一的href属性值,与hx元素的id对应

let $a = $(`${textContent}`);

if (lastLevel < curLevel) {

// 如果当前层级比上一个层级大,则从上一个层级+1到当前层级循环,

// 循环添加ul和li元素

for (let j = lastLevel + 1; j <= curLevel; j++) {

// 创建ul和li元素,并添加data-level属性

let $u = $('

$l = $('

');

$l.attr('data-level', j);

$u.attr('data-level', j).append($l);

// 找到data-level为j-1的最后一个li元素,并添加$u

$toc.find(`li[data-level=${j - 1}]:last`).append($u);

}

// 找到data-level为curLevel的最后一个li,并添加$a

$toc.find(`li[data-level=${curLevel}]:last`).append($a);

} else if (lastLevel === curLevel) {

// 如果当前层级和上一个层级相等,则找到相同层级的li元素的父元素,

// 创建li元素并添加上去

// 已经存在data-level为curLevel的ul,只需要创建li即可

let $l = $('

');

// 给li元素添加data-level树形,并添加$a

// 找到data-level为curLevel的最后一个li元素的父元素,添加$l

$toc.find(`li[data-level=${curLevel}]:last`).parent().

append($l.attr('data-level', curLevel).append($a));

} else {

// 如果当前层级小于上一个层级,则找到最后一个相同层级的li元素的

// 父元素,添加$l

// 找到data-level为curLevel的最后一个li元素,必然存在

let $sublingLi = $toc.

find(`li[data-level=${curLevel}]:last`);

let $l = $('

');

// 找到$sublingLi的父元素,添加li元素即可

$sublingLi.parent().append($l.attr('data-level', curLevel).

append($a));

}

$headers.eq(i).attr('id', id);

}

// 清除p元素的文本内容,并将$toc元素append到p元素

$('p:Contains([TOC]):first').text('').append($toc);

});

效果如下:

htmlHeaders.png

MarkdownPad2效果

以上代码编写完毕,但只是一个demo,我们的目的是为了让MarkdownPad2导出HTML时支持[TOC],所以,先删除不必要的代码

$(document).ready(function() {

// 新增Contains选择器,:contains的变异版,增加忽略大小写功能

$.expr[':'].Contains = function(a, i, m){

return jQuery(a).text().toUpperCase().indexOf(m[3].

toUpperCase()) >= 0;

};

// 创建class为toc的div元素

let $toc = $('

$toc.attr('class', 'toc');

// 获取h1-h6元素

let $headers = $('h1,h2,h3,h4,h5,h6');

// 获取第一个hx元素,注意是dom对象,非jQuery对象

let firstHeader = $headers[0];

if (firstHeader) {

// 获取第一个hx元素的层级

let firstLevel = parseInt(firstHeader.tagName.

replace('H', ''), 10);

// 给a元素唯一的href属性值

let id = `${firstHeader.textContent}-0`;

for (let i = 1; i <= firstLevel; i++) {

// 创建ul和li元素,并添加data-level属性

let $ul = $('

$li = $('

');

$li.attr('data-level', i);

$ul.attr('data-level', i).append($li);

// 获取data-level为i-1的li元素

let $pLi = $toc.find(`li[data-level=${i - 1}]`);

if ($pLi.length > 0) {

// 找到data-level为i-1的元素,直接append到该li元素上即可

$pLi.append($ul);

} else {

// 未找到data-level为i-1的元素,说明是顶层的ul,

// 直接append到class为toc的div元素上

$toc.append($ul);

}

}

// 找到所属层级的li元素,并添加a元素

$toc.find(`li[data-level=${firstLevel}]`).append(

$(`${firstHeader.textContent}`));

// 与a元素的href对应,用于文档内跳转

$headers.eq(0).attr('id', id);

}

// 从第二个hx元素开始,循环$headers

for (let i = 1; i < $headers.length; i++) {

// 获取当前的hx元素的层级以及上一个hx元素的层级

let curLevel = parseInt($headers[i].tagName.replace('H', ''),

10),

lastLevel = parseInt($headers[i - 1].tagName.

replace('H', ''), 10);

// 当前hx元素的文本元素

let textContent = $headers[i].textContent,

id = `${textContent}-i`;

// 给a元素唯一的href属性值,与hx元素的id对应

let $a = $(`${textContent}`);

if (lastLevel < curLevel) {

// 如果当前层级比上一个层级大,则从上一个层级+1到当前层级循环,

// 循环添加ul和li元素

for (let j = lastLevel + 1; j <= curLevel; j++) {

// 创建ul和li元素,并添加data-level属性

let $u = $('

$l = $('

');

$l.attr('data-level', j);

$u.attr('data-level', j).append($l);

// 找到data-level为j-1的最后一个li元素,并添加$u

$toc.find(`li[data-level=${j - 1}]:last`).append($u);

}

// 找到data-level为curLevel的最后一个li,并添加$a

$toc.find(`li[data-level=${curLevel}]:last`).append($a);

} else if (lastLevel === curLevel) {

// 如果当前层级和上一个层级相等,则找到相同层级的li元素的父元素,

// 创建li元素并添加上去

// 已经存在data-level为curLevel的ul,只需要创建li即可

let $l = $('

');

// 给li元素添加data-level树形,并添加$a

// 找到data-level为curLevel的最后一个li元素的父元素,添加$l

$toc.find(`li[data-level=${curLevel}]:last`).parent().

append($l.attr('data-level', curLevel).append($a));

} else {

// 如果当前层级小于上一个层级,则找到最后一个相同层级的li元素的

// 父元素,添加$l

// 找到data-level为curLevel的最后一个li元素,必然存在

let $sublingLi = $toc.

find(`li[data-level=${curLevel}]:last`);

let $l = $('

');

// 找到$sublingLi的父元素,添加li元素即可

$sublingLi.parent().append($l.attr('data-level', curLevel).

append($a));

}

$headers.eq(i).attr('id', id);

}

// 清除p元素的文本内容,并将$toc元素append到p元素

$('p:Contains([TOC]):first').text('').append($toc);

});

然后打开MarkdownPad2,工具-->选项-->高级-->HTML Head编辑器,将上述代码拷贝至代码编辑器中,保存并关闭-->保存并关闭

MarkdownPad2左侧填入一下内容:

# 《Vue2.0开发去哪儿网App》知识点

[TOC]

## 深入理解Vue组件

### 4-8 动态组件与v-once指令

#### 动态组件

#### v-once指令

## Vue中的动画特效

### 5-1 Vue动画 - Vue中的CSS动画原理

#### 动画原理

### 5-2 在Vue中使用animate.css库

#### keyframes动画

#### 自定义类名

#### animate.css库

文件-->导出-->导出HTML,填写文件名,保存,效果如下:

result.png

GitHub项目

html转换markdownpad,MarkdownPad2导出HTML支持[TOC]相关推荐

  1. html转换markdownpad,GitHub - negrochn/markdownpad2_toc: MarkdownPad2导出HTML支持[TOC]

    MarkdownPad2导出HTML支持[TOC] 为什么&效果图 为什么 为什么要吃力不讨好的实现这个功能呢? [TOC]语法挺有用的,特别是标题较多的时候 百度上并未找到MarkdownP ...

  2. sql2java-excel(一):基于apache poi实现数据库表的导出及支持spring web

    sql2java是我几年年开始写的一个sql2java是一个轻量级数据库(SQL)访问代码(java)生成器.这几年一直在根据工作需要维护升级,最近的项目中需要对数据库的记录提供导出excel的功能. ...

  3. ie如何导入html文件类型,Magicodes.IE: 导入导出通用库,支持Dto导入导出以及动态导出,支持Excel、Word、Pdf和Html。...

    Magicodes.IE 导入导出通用库,支持Dto导入导出以及动态导出,支持Excel.Word.Pdf和Html. 疯狂的徽章 GitHub Azure DevOps Build Status: ...

  4. 推荐一个日历转换开源工具库,支持C#、Java、PHP等主流的语言

    更多开源项目请查看:一个专注推荐.Net开源项目的榜单 日历对我们来说,最熟悉的就是阳历和农历,在中国每年都有固定的节日.节气.中国特有传统节日,有些节日是固定的,但是节气这些都需要我们经过一定规则换 ...

  5. gitlab markdown 支持TOC解决办法

    问题分析 1. 标题的锚点会被替换 中文替换为'' 空格等非正常字符替换为'-' 这给自己手动写toc也带来了麻烦,不能直接复制标题作为链接 2. 不能自动生成TOC 目前gitlab不支持TOC功能 ...

  6. 解决markdownPad2导出的pdf显示不出图片问题

    markdown 工具 markdown使用说明: 解决markdownPad2导出的pdf显示不出图片问题: 错误写法: ![Alt text](/pic/webrtc_jiegoutu.png) ...

  7. 深蓝词库转换1.2版本发布——支持紫光拼音和拼音加加

    之前推出了深蓝词库转换工具,受到大家的欢迎,有朋友陆陆续续来信,希望增加一些实用的功能,于是乎今天深蓝词库转换1.2推出.该版本主要实现了3个新功能: 1.支持紫光拼音输入法的词库导入导出. 紫光拼音 ...

  8. itext转换HTML为pdf,支持中文换行

    最近有个需求,OA系统流程走完后,要求将流程导出为pdf供人下载,在网上各种查资料捣鼓了半天,终于算是搞出来了,基本逻辑就是配置好需要显示的布局,然后根据布局生成HTML页面,再导出为pdf. (20 ...

  9. vue如何把html转换word,vue导出html、word和pdf的实现代码

    X-Find迅聘选才 `; return html; } 导出的样式js文件: .page_layout { position: relative; height: 100%; display: fl ...

最新文章

  1. findwindowex子窗口类型有哪几种_SQL-窗口函数
  2. URAL 1993 This cheeseburger you don't need
  3. java高级----Java动态代理的原理
  4. PHP两个字符串比较(人为出错),两字符串类型和数据表面相等,但strcmp()结果不为0...
  5. c mysql存储过程 out_MySQL存储过程带in和out参数
  6. 一个农民父亲令人震撼的力量
  7. 通过管道进行线程间通信
  8. Linux磁盘分区详解(fdisk)
  9. linux报mce清除不良代码,如何分析系统MCE异常?
  10. Android开发笔记(二十九)使用SharedPreferences存取数据
  11. jmeter接口测试json详解
  12. 个人CTF入门训练过程WriteUp
  13. SVN客户端安装教程
  14. mysql输入20万数据_mysql生成20万条数据(连表插入)
  15. LOL盗号PHP源码,说说技术那些事之LOL盗号网站
  16. 19HTML5期末大作业:动画漫影视网站设计——动画漫展学习资料电影模板(6页) HTML+CSS+JavaScript 学生DW网页设计作业成品 课程设计网页规划与设计 计算机毕设网页设计源
  17. [c++] 常成员函数
  18. 关于在VMware上安装Android x86及FTP详细使用
  19. 世界杯电视直播表(及时更新)
  20. android 自定义 snackbar,Android Study Material Design 五 之:自定义Toast以及玩转SnackBar...

热门文章

  1. 字符0、数字0和‘\0’的区别
  2. Eureka注册服务配置info-使用$project.artifactId$无法动态显示artifactId
  3. 房屋安全鉴定报告的有效期及两种鉴定类型
  4. ChatGLM-6B【完全转载】
  5. 超百万人用它生成3D头像,这项技术刚刚中选了SIGGRAPH Asia 2022
  6. 惠州电子计算机职业学校,惠州市十大中专学校排名
  7. unity自定义组件
  8. Docker容器内部无法访问外网原因之一
  9. 在线教育,网校平台,线上平台,线上教育的一些个人理解!
  10. cesium 相机跟随