Skip to main content

Markdown

WdMarkdown

Applicable Scenarios

A markdown display component implemented based on markdown-it.

Basic Capabilities Description

  1. Supports markdown syntax.
  2. Initialization with presets and options, passing preset options via options.
({
html: false, // Enable HTML tags in the source code
xhtmlOut: false, // Use / to close single tags (e.g., <br />).
// This option is only compatible with the full CommonMark mode.
breaks: false, // Convert line breaks in paragraphs to <br>.
langPrefix: 'language-', // CSS language prefix for fenced code blocks. Useful for additional code highlighting.
linkify: false, // Automatically convert URL-like text into links.

// Enable some language-neutral replacements + quote beautification
typographer: false,

// double + single quotes replacement pairs, when typographer is enabled.
// or smart quotes, etc., can be String or Array.
//
// For example, you can support '«»„"' for Russian, '„"‚‘' for German.
quotes: '""‘’',
});

Extended Scenarios Description

1. How to use Mermaid in Markdown

Mermaid is a JavaScript-based open-source library that allows users to quickly generate various diagrams, including flowcharts, sequence diagrams, Gantt charts, and mind maps, through concise text and code syntax.

    1. Load Mermaid

image

<script src="https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js"></script>

Domestic cdn address:

<script src="https://cdn.staticfile.net/mermaid/10.7.0/mermaid.min.js"></script>
Note
  • Currently, loading external resources is only supported on the Web side and is not available for Mini Programs.
  • In some cases, the script may fail to load properly because the jsdeliver CDN, which hosts the script dependencies, is inaccessible in China under certain circumstances. Consider using an alternative CDN.
    1. Create the method mermaidRun
export default function ({ event, data }) {
setTimeout(() => {
mermaid.run({
querySelector: '.language-mermaid',
});
}, 0);
}
    1. Call the mermaidRun method in the markdownReady event to render the diagram
    1. Write markdown

```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] ```

image

2. How to use katex in Markdown

katex is a fast, easy-to-use JavaScript library for TeX math rendering on the Web. By loading the katex plugin, katex rendering can be supported.

    1. Load katex

image

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css" integrity="sha384-nB0miv6/jRmo5UMMR1wu3Gz6NLsoTkbqJghGIsx//Rlm+ZU03BU6SQNC66uf4l5+" crossorigin="anonymous">
<!-- The loading of KaTeX is deferred to speed up page rendering -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js" integrity="sha384-7zkQWkzuo3B5mTepMUcHkMB5jZaolc2xDwL6VFqjFALcbeS9Ggm/Yr2r3Dy4lfFg" crossorigin="anonymous"></script>
Note
  • Currently, loading external resources is only supported on the Web side and is not available for Mini Programs.
  • In some cases, the script may fail to load properly due to the jsdeliver CDN (which hosts the script) being inaccessible in China under certain circumstances.
    1. Create the plugin method katex
var katex = window.katex;

// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function isValidDelim(state, pos) {
var prevChar,
nextChar,
max = state.posMax,
can_open = true,
can_close = true;

prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;

// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
if (
prevChar === 0x20 /* " " */ ||
prevChar === 0x09 /* \t */ ||
(nextChar >= 0x30 /* "0" */ && nextChar <= 0x39) /* "9" */
) {
can_close = false;
}
if (nextChar === 0x20 /* " " */ || nextChar === 0x09 /* \t */) {
can_open = false;
}

return {
can_open: can_open,
can_close: can_close,
};
}

function math_inline(state, silent) {
var start, match, token, res, pos, esc_count;

if (state.src[state.pos] !== '$') {
return false;
}

res = isValidDelim(state, state.pos);
if (!res.can_open) {
if (!silent) {
state.pending += '$';
}
state.pos += 1;
return true;
}

// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start = state.pos + 1;
match = start;
while ((match = state.src.indexOf('$', match)) !== -1) {
// Found potential $, look for escapes, pos will point to
// first non escape when complete
pos = match - 1;
while (state.src[pos] === '\\') {
pos -= 1;
}

// Even number of escapes, potential closing delimiter found
if ((match - pos) % 2 == 1) {
break;
}
match += 1;
}

// No closing delimter found. Consume $ and continue.
if (match === -1) {
if (!silent) {
state.pending += '$';
}
state.pos = start;
return true;
}

// Check if we have empty content, ie: $$. Do not parse.
if (match - start === 0) {
if (!silent) {
state.pending += '$$';
}
state.pos = start + 1;
return true;
}

// Check for valid closing delimiter
res = isValidDelim(state, match);
if (!res.can_close) {
if (!silent) {
state.pending += '$';
}
state.pos = start;
return true;
}

if (!silent) {
token = state.push('math_inline', 'math', 0);
token.markup = '$';
token.content = state.src.slice(start, match);
}

state.pos = match + 1;
return true;
}

function math_block(state, start, end, silent) {
var firstLine,
lastLine,
next,
lastPos,
found = false,
token,
pos = state.bMarks[start] + state.tShift[start],
max = state.eMarks[start];

if (pos + 2 > max) {
return false;
}
if (state.src.slice(pos, pos + 2) !== '$$') {
return false;
}

pos += 2;
firstLine = state.src.slice(pos, max);

if (silent) {
return true;
}
if (firstLine.trim().slice(-2) === '$$') {
// Single line expression
firstLine = firstLine.trim().slice(0, -2);
found = true;
}

for (next = start; !found; ) {
next++;

if (next >= end) {
break;
}

pos = state.bMarks[next] + state.tShift[next];
max = state.eMarks[next];

if (pos < max && state.tShift[next] < state.blkIndent) {
// non-empty line with negative indent should stop the list:
break;
}

if (state.src.slice(pos, max).trim().slice(-2) === '$$') {
lastPos = state.src.slice(0, max).lastIndexOf('$$');
lastLine = state.src.slice(pos, lastPos);
found = true;
}
}

state.line = next + 1;

token = state.push('math_block', 'math', 0);
token.block = true;
token.content =
(firstLine && firstLine.trim() ? firstLine + '\n' : '') +
state.getLines(start + 1, next, state.tShift[start], true) +
(lastLine && lastLine.trim() ? lastLine : '');
token.map = [start, state.line];
token.markup = '$$';
return true;
}

export default function math_plugin(md, options) {
// Default options

options = options || {};

// set KaTeX as the renderer for markdown-it-simplemath
var katexInline = function (latex) {
options.displayMode = false;
try {
return katex.renderToString(latex, options);
} catch (error) {
if (options.throwOnError) {
console.log(error);
}
return latex;
}
};

var inlineRenderer = function (tokens, idx) {
return katexInline(tokens[idx].content);
};

var katexBlock = function (latex) {
options.displayMode = true;
try {
return '<p>' + katex.renderToString(latex, options) + '</p>';
} catch (error) {
if (options.throwOnError) {
console.log(error);
}
return latex;
}
};

var blockRenderer = function (tokens, idx) {
return katexBlock(tokens[idx].content) + '\n';
};

md.inline.ruler.after('escape', 'math_inline', math_inline);
md.block.ruler.after('blockquote', 'math_block', math_block, {
alt: ['paragraph', 'reference', 'blockquote', 'list'],
});
md.renderer.rules.math_inline = inlineRenderer;
md.renderer.rules.math_block = blockRenderer;
}
    1. Use the plugin to call the method for updating the markdown instance in the markdownReady event
$w.markdown2.markdownInstance?.use($w.page.handler.katex);
    1. Write markdown

# Maxwell's Equations


equation | description
----------|------------
$\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero
$\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$
$\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_

image

Property Introduction

组件接收的外部传入的属性

属性名
属性标识
类型
说明
内容valuestring

markdown的展示内容

示例:"---\n__Advertisement :)__\n\n- __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image\n resize in browser.\n- __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly\n i18n with plurals support and easy syntax.\n\nYou will like those projects!\n\n---\n\n# h1 Heading 8-)\n## h2 Heading\n### h3 Heading\n#### h4 Heading\n##### h5 Heading\n###### h6 Heading\n\n\n## Horizontal Rules\n\n___\n\n---\n\n***\n\n\n## Typographic replacements\n\nEnable typographer option to see result.\n\n(c) (C) (r) (R) (tm) (TM) (p) (P) +-\n\ntest.. test... test..... test?..... test!....\n\n!!!!!! ???? ,, -- ---\n\n\"Smartypants, double quotes\" and 'single quotes'\n\n\n## Emphasis\n\n**This is bold text**\n\n__This is bold text__\n\n*This is italic text*\n\n_This is italic text_\n\n~~Strikethrough~~\n\n\n## Blockquotes\n\n\n> Blockquotes can also be nested...\n>> ...by using additional greater-than signs right next to each other...\n> > > ...or with spaces between arrows.\n\n\n## Lists\n\nUnordered\n\n+ Create a list by starting a line with `+`, `-`, or `*`\n+ Sub-lists are made by indenting 2 spaces:\n - Marker character change forces new list start:\n * Ac tristique libero volutpat at\n + Facilisis in pretium nisl aliquet\n - Nulla volutpat aliquam velit\n+ Very easy!\n\nOrdered\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n\n\n1. You can use sequential numbers...\n1. ...or keep all the numbers as `1.`\n\nStart numbering with offset:\n\n57. foo\n1. bar\n\n\n## Code\n\nInline `code`\n\nIndented code\n\n // Some comments\n line 1 of code\n line 2 of code\n line 3 of code\n\n\nBlock code \"fences\"\n\n```\nSample text here...\n```\n\nSyntax highlighting\n\n``` js\nvar foo = function (bar) {\n return bar++;\n};\n\nconsole.log(foo(5));\n```\n\n## Tables\n\n| Option | Description |\n| ------ | ----------- |\n| data | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext | extension to be used for dest files. |\n\nRight aligned columns\n\n| Option | Description |\n| ------:| -----------:|\n| data | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext | extension to be used for dest files. |\n\n\n## Links\n\n[link text](http://dev.nodeca.com)\n\n[link with title](http://nodeca.github.io/pica/demo/ \"title text!\")\n\nAutoconverted link https://github.com/nodeca/pica (enable linkify to see)\n\n\n## Images\n\n![image](https://octodex.github.com/images/minion.png)\n"

选项optionsobject

markdown的初始化配置

Events

组件暴露的事件,可以监听组件的事件来触发一些外部的动作

事件名
事件code
事件出参 event.detail
适用情况
说明
markdown ReadyonReadyobject
  • markdownInstance: object markdown实例
    兼容三端

    当前markdown已完成实例初始化,可以调用markdown实例方法

    Property API

    通过属性 API,可以获取组件内部的状态和属性值,可以通过$w.componentId.propertyName 来访问组件内部的值,如 $w.input1.value ,详请请参考 属性 API

    只读属性名
    属性标识
    类型
    说明
    内容valuestring

    markdown的展示内容

    markdown实例markdownInstanceobject

    可以通过markdown实例调用markdown实例方法,如:markdownInstance.render("# markdown-it rulezz!")具体内容见markdown-it官方文档

    Method API

    通过方法 API,可以通过程序触发组件内部的方法,比如提交表单,显示弹窗等, 可以通过$w.componentId.methodName来调用组件方法,如 $w.form1.submit()

    方法名
    方法标识
    参数
    方法说明
    更新markdown实例updateMarkdownInstanceobject
    • markdownInstance: object markdown实例

      可以通过markdown实例调用markdown实例方法,如:markdownInstance.render("# markdown-it rulezz!")具体内容见markdown-it官方文档

      更新markdown实例

      Style API

      通过样式 API,可以覆盖组件中内部元素的样式来实现自定义,例如在低代码编辑器中中通过 #wd-page-root .wd-btn 即可为所有的按钮组件编写样式,通过 :scope 可以控制单个组件样式, 详细说明请参考样式 API

      名称
      类名
      说明和示例
      根元素.wd-markdown链接组件根元素
      /* :scope 指的是当前组件元素 */
      /* 具体可参考样式 API 文档 */
      :scope.wd-markdown {
        /* 在这里编写CSS 样式 */
      }
      PC 端链接根元素.wd-pc-markdown可以为 PC 端的链接编写样式
      /* :scope 指的是当前组件元素 */
      /* 具体可参考样式 API 文档 */
      :scope.wd-pc-markdown {
        /* 在这里编写CSS 样式 */
      }
      H5 端链接根元素.wd-h5-markdown可以为 H5 端的链接编写样式
      /* :scope 指的是当前组件元素 */
      /* 具体可参考样式 API 文档 */
      :scope.wd-h5-markdown {
        /* 在这里编写CSS 样式 */
      }
      小程序端链接根元素.wd-mp-markdown可以为小程序端的链接编写样式
      /* :scope 指的是当前组件元素 */
      /* 具体可参考样式 API 文档 */
      :scope.wd-mp-markdown {
        /* 在这里编写CSS 样式 */
      }

      了解样式 API

      Limitation Description

      The display of markdown in Mini Programs is achieved by parsing it into HTML through markdown-it, then rendering it via the Mini Program's rich-text component. Consequently, the markdown rendering capabilities in Mini Programs are limited, with some styling details slightly differing from the web version. Please refer to the actual runtime performance in Mini Programs as the authoritative reference.

      Frequently Asked Questions

      Why are externally linked images displaying abnormally?

      Many websites' images check the page source, possibly because anti-leech protection is enabled. When accessed directly, there is no referrer, but when used in your page, it verifies the page source to block access. You can try using other image resources or check the loading failure information in the F12 developer tools.