当前位置: 首页 > 工具软件 > markdown-it > 使用案例 >

markdown-it

华凯捷
2023-12-01

markdown-it

base.css

* {
    padding: 0;
    margin: 0;
}

/* 自定义滚动条 */
::-webkit-scrollbar {
    width: 12px;
    height: 12px;
    background-color: transparent;
}
::-webkit-scrollbar-corner {
    background-color: black;
}
::-webkit-scrollbar-thumb {
    background-color: rgba(0, 0, 0, 0.4);
    border-radius: 32px;
}

body {
    overflow: hidden;

    padding: 0;
    margin: 0;

    display: flex;
    justify-content: center;

    background-color: rgb(2, 33, 17);
    color: #dddddd;
}

.container {
    padding: 0;
    /* margin: 10px 0 10px 0; */

    display: flex;
    flex-direction: row;
}

.left {
    overflow: auto;

    margin: 0;
    /* padding: 0 20px 0 20px; */
    /* width: 100px; */

    background-color: rgba(34, 34, 34, 0.8);
}

.main {
    overflow: auto;

    box-sizing: border-box;
    padding: 25px 25px 25px 25px;
    width: 842px; /* A4 */
    height: auto;

    background-color: rgba(51, 51, 51, 1.0);
}

.right {
    overflow: auto;

    margin: 0;
    padding: 0 20px 0 2em;
    width: 300px;

    background-color: rgba(34, 34, 34, 0.8);
}

/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */
/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */

/* 链接 */
.container a {
    color: dodgerblue;
}
.container a:after {
    color: skyblue;
}
.container a:hover {
    color: springgreen;
}

/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */
/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */

/* 段落缩进 */
.main p:not(blockquote p),
ul,
ol,
pre,
table,
blockquote {
    margin-left: 2em;
}

/* 段落间隔 */
.main p:not(blockquote p),
ul,
ol,
li,
pre,
table,
blockquote {
    margin-bottom: 1em;
}

/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */
/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */

/* 标题 */
.main h1 {
    color: #ef7823;
    margin-top: 1em;
    margin-bottom: 1em;
    border-bottom: 1px solid gray;
}
.main h1:before {
    content: "";
}
.main h1 a {
    font-size: 0;
}
/* ---------------- */
.main h2 {
    color: #ff69b4;
    margin-top: 1em;
    margin-bottom: 1em;
    border-bottom: 1px solid gray;
}
.main h2:before {
    content: "";
}
.main h2 a {
    font-size: 0;
}
/* ---------------- */
.main h3 {
    color: #deda00;
    margin-top: 1em;
    margin-bottom: 1em;
    border-bottom: 1px dashed gray;
}
.main h3:before {
    content: "⭐";
}
.main h3 a {
    font-size: 0;
}
/* ---------------- */
.main h4 {
    color: #5cd009;
    margin-top: 1em;
    margin-bottom: 1em;
    border-bottom: 1px dashed gray;
}
.main h4:before {
    content: "";
}
.main h4 a {
    font-size: 0;
}
/* ---------------- */
.main h5 {
    color: #ffffff;
    margin-top: 1em;
    margin-bottom: 1em;
    border-bottom: 1px dashed gray;
}
.main h5:before {
    content: "✿";
}
.main h5 a {
    font-size: 0;
}

/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */
/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */

/* 代码: txt字体修正 */
pre code.language-txt,
code.language-batch {
    font-family: Consolas, "黑体";
}

/* 代码: 行内代码块背景 */
.main code:not(pre code) {
    /* font-family: "monospace", "Consolas", "黑体"; */

    padding: 0.2em 0.5em 0.2em 0.5em;
    border-radius: 6px;

    background-color: #222;
}

/* 代码: 块代码块背景 */
.main pre {
    padding: 1em;
    border-radius: 3px;

    background-color: #222;
}

/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */
/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */

/* 引用 */
.main blockquote {
    border-left: 5px solid;
    padding: 0.5em;
    border-radius: 3px;

    background-color: rgba(100, 100, 100, 0.6);
}

/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */
/* ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ */

/* 表格 */
.main table {
    border-collapse: collapse;
    border: 1px solid lightgray;
}
.main table th,
.main table td {
    border: 1px solid gray;
    padding: 0.5em;
}

demo.md

Mermaid

#    标题1
##   标题2
###  标题3
#### 标题4
##### 标题5

>引用

*斜体*
**粗体**
~~删除线~~
`代码`

*alpha*
0123456789
abcdefghijklmnopqrstuvwxyz

29^th^
H~2~0

==标记==

$E=mc^2$

$$E=mc^2$$

- 无序列表
- 无序列表

1. 有序列表1
2. 有序列表2

[连接](源地址)

![图片](https://pic.rmb.bdstatic.com/bjh/down/bf9dd40c28bf11e87e086d8ceab61dda.jpeg)

| 列1  | 列2  | 列3  |
| :--: | ---: | :--- |
| 居中 | 居右 | 居左 |

` ` `javascript
// A code block
var foo = 'bar';
` ` `

` ` `mermaid
graph TD
    A[Christmas] -->|Get money| B(Go shopping)
    B --> C{Let me think}
    C -->|One| D[Laptop]
    C -->|Two| E[iPhone]
    C -->|Three| F[Car]
` ` `

一个具有注脚的文本。[^1]

[^1]: 注脚的解释

index.js

const fs = require("fs");
const helper = require("./mdit");

const content = fs.readFileSync("Rust笔记.md").toString("utf-8");
const [html, toc] = helper.convertMarkdown2Html(content);

const fd = fs.openSync("./demo.html", "w");
fs.writeSync(fd, html);
fs.closeSync(fd);

mdit.js

/*
    npm init -y

    yarn add mermaid
    yarn add katex
    yarn add highlight.js

    yarn add markdown-it
    yarn add markdown-it-mark
    yarn add markdown-it-sup
    yarn add markdown-it-sub
    yarn add markdown-it-footnote
    yarn add markdown-it-katex
    yarn add markdown-it-toc-and-anchor
 */

// HighlightJs
const hljs = require("highlight.js");

// Markdown
const mdItConfig = {
    // 是否 在源码中启用 HTML 标签
    html: false,

    // 是否 使用 '/' 来闭合单标签(比如 <br />)
    xhtmlOut: false,

    // 是否 '\n' -> <br>
    breaks: false,

    // 代码块的 Class前缀
    langPrefix: "language-",

    // 将类似 URL 的文本自动转换为链接。
    linkify: false,

    // typographer:  false,        // 启用一些语言中立的替换 + 引号美化
    // quotes: '“”‘’',             // 双 + 单引号替换对,当 typographer 启用时。

    // 高亮函数,返回转义的HTML 或 ''
    highlight: function (code, lang, args) {
        if (lang) {
            if ("mermaid" === lang) {
                return `<div class='mermaid'>${code}</div>`;
            } else if (hljs.getLanguage(lang)) {
                try {
                    const highlightCode = hljs.highlight(code, { language: lang, ignoreIllegals: true }).value;
                    return highlightCode;
                } catch (error) {
                    console.log(error);
                }
            }
        }
        return "";
    },
};
let mdToc = {};
const mdIt = require("markdown-it")(mdItConfig)
    .use(require("markdown-it-mark")) // 标记
    .use(require("markdown-it-sup")) // 上标
    .use(require("markdown-it-sub")) // 下标
    .use(require("markdown-it-footnote")) // 脚注
    // 公式
    .use(require("markdown-it-katex"), { throwOnError: false, errorColor: "#CC0000" })
    // 目录
    .use(require("markdown-it-toc-and-anchor").default, {
        tocCallback: function (tocMarkdown, tocArray, tocHtml) {
            mdToc = { tocMarkdown, tocArray, tocHtml };
        },
    });

const mdReader = (mdContent) => {
    const html = mdIt.render(mdContent);
    const template = `<html>
<head>
    <link href="node_modules/katex/dist/katex.min.css" rel="stylesheet" />
    <link href="node_modules/highlight.js/styles/github-dark.css" rel="stylesheet" />
    <script src="node_modules/mermaid/dist/mermaid.min.js"></script>
    <link href="base.css" rel="stylesheet" />
</head>
<body>
    <div class="container">
        <div class="left"></div>
        <div class="main">${html}</div>
        <div class="right">${mdToc.tocHtml}</div>
    </div>
    <script>
        mermaid.initialize({ startOnLoad: true, theme: "dark"});
    </script>
</body>
</html>`;
    return [template, mdToc];
};

module.exports = {
    convertMarkdown2Html: mdReader,
};

自定义扩展

/**
 * @file 自定义规则
 * @example
 *      mdIt.use(require("./YourRule"));
 */

const MarkdownIt = require("./types/markdown-it");
const StateCore = require("./types/markdown-it/rules_core/state_core");
const StateBlock = require("./types/markdown-it/rules_block/state_block");
const StateInline = require("./types/markdown-it/rules_inline/state_inline");
// const CoreRuleNames = ["normalize", "block", "inline", "linkify", "replacements", "smartquotes", "text_join"];
// const BlockRuleNames = ["table", "code", "fence", "blockquote", "hr", "list", "reference", "html_block", "heading", "lheading", "paragraph"];
// const InlineRuleNames = ["text", "linkify", "newline", "escape", "backticks", "strikethrough", "emphasis", "link", "image", "autolink", "html_inline", "entity"];
// const InlineRule2Names = ["balance_pairs", "strikethrough", "emphasis", "fragments_join"];

/**
 * 自定义规则 匹配 {{}}
 * @param {MarkdownIt} md
 * @param {Object} options
 */
function YourRule(md, options) {
    md.inline.ruler.after("emphasis", "test_inline", function (state, silent) {
        const findL = "{{";
        const findR = "}}";
        const posStart = state.pos; // 起点
        const posAvailable = () => state.pos < state.posMax;
        const posRecovery = () => state.pos = posStart;
        const srcPos = (length) => state.src.slice(state.pos, state.pos + (length || state.posMax));
        const srcStartPos = () => state.src.slice(posStart, state.pos);
        const srcFound = () => srcStartPos().slice(findL.length, -findR.length);

        if (findL === srcPos(findL.length)) {
            let found = false;
            state.pos += findL.length;
            while (posAvailable()) {
                if (findR === srcPos(findR.length)) {
                    found = true;
                    state.pos += findR.length;
                    break;
                }
                state.pos += 1;
            }
            if (found) {
                token = state.push("code_open", "code", 1);
                token.markup = findL;
                token = state.push("text", "", 0);
                token.content = srcFound();
                token = state.push("code_close", "code", -1);
                token.markup = findR;
                state.pos += 1;
                return true;
            }
            posRecovery();
            return false;
        }
        return false;
    }); // push
}

module.exports = YourRule;

/*
    【追溯 render 过程】

    // 1 外部调用渲染
    this.render(src, env);
        // 1.1 解析出Token序列
        let tokens = this.parse(src, env)
        // 1.2 Token到Html
        this.renderer.render(tokens, this.options, env)

    // 1.1
    this.parse(src, env)
        // 1.1.1 创建 {StateCore} 对象
        let state = new this.core.State(src, this, env);
        // 1.1.2 处理
        this.core.process(state);
        // 1.1.3 返回
        return state.tokens;

    // 1.1.2
    this.core.process(state);
        // 1.1.2.1 返回全部 {CoreRuleNames} 对应的方法
        let rules = this.ruler.getRules('');
        for (let i = 0; i < rules.length; i++) {
            // 1.1.2.2 执行对应方法
            rules[i](state);
        }

    // 1.1.2.2 以 {core.block} {core.inline} 为例
    function block(state) {
        // 1.1.2.2.1 解析块
        state.md.block.parse(state.src, state.md, state.env, state.tokens);
    };
    function inline(state) {
        for (let i = 0; i < tokens.length; i++) {
            let tok = tokens[i];
            if ('inline' === tok.type) {
                // 1.1.2.2.2 解析行
                state.md.inline.parse(tok.content, state.md, state.env, tok.children);
            }
        }
    };

    // 1.1.2.2.1 解析块
    function (src, md, env, outTokens) {
        // 1.1.2.2.1.1 创建 {StateBlock} 对象
        let state = new this.State(src, md, env, outTokens);
        // 1.1.2.2.1.2 处理
        this.tokenize(state, state.line, state.lineMax);
    };

    // 1.1.2.2.2 解析行
    function (str, md, env, outTokens) {
        // 1.1.2.2.2.1 创建 {StateInline} 对象
        let state = new this.State(str, md, env, outTokens);

        // 1.1.2.2.2.2 按 {InlineRuleNames} 解析
        this.tokenize(state);

        // 1.1.2.2.2.3 按 {InlineRule2Names} 解析
        const rules = this.ruler2.getRules('');
        for (let i = 0; i < rules.length; i++) {
            rules[i](state);
        }
    };

    // 1.1.2.2.2.2 按 {InlineRuleNames} 解析
    function tokenize(state) {
        const rules = this.ruler.getRules('');
        let ok = false;
        // ...
        // 尝试所有可行规则,若成功:
        // - 更新 `state.pos` 和 `state.tokens`
        // - 返回 `true`
        while (state.pos < state.posMax) {
            if (state.level < state.md.options.maxNesting) {
                for (let i = 0; i < rules.length; i++) {
                    ok = rules[i](state, false);
                    if (ok) break;
                }
            }
            if (ok) {
                if (state.pos >= state.posMax) break;
                continue;
            }
            // 匹配失败的就是 普通文本
            state.pending += state.src[state.pos++];
        }
        if (state.pending) {
            // 收集的普通文本转变为 token text
            state.pushPending();
        }
    };

 */

 类似资料: