Markdown
WdMarkdown
Applicable Scenarios
A markdown display component implemented based on markdown-it.
Basic Capabilities Description
- Supports markdown syntax.
- 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.
- Load Mermaid
<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>
- 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.
- Create the method mermaidRun
export default function ({ event, data }) {
setTimeout(() => {
mermaid.run({
querySelector: '.language-mermaid',
});
}, 0);
}
- Call the mermaidRun method in the markdownReady event to render the diagram
- 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] ```
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.
- Load katex
<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>
- 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.
- 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;
}
- Use the plugin to call the method for updating the markdown instance in the markdownReady event
$w.markdown2.markdownInstance?.use($w.page.handler.katex);
- 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?_
Property Introduction
组件接收的外部传入的属性
属性名 | 属性标识 | 类型 | 说明 |
---|
内容 | value | string | 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\n" |
选项 | options | object | markdown的初始化配置 |
Events
组件暴露的事件,可以监听组件的事件来触发一些外部的动作
事件名 | 事件code | 事件出参 event.detail | 适用情况 | 说明 |
---|
markdown Ready | onReady | object
| 兼容三端 | 当前markdown已完成实例初始化,可以调用markdown实例方法 |
Property API
通过属性 API,可以获取组件内部的状态和属性值,可以通过$w.componentId.propertyName
来访问组件内部的值,如 $w.input1.value
,详请请参考 属性 API
只读属性名 | 属性标识 | 类型 | 说明 |
---|
内容 | value | string | markdown的展示内容 |
markdown实例 | markdownInstance | object | 可以通过markdown实例调用markdown实例方法,如:markdownInstance.render("# markdown-it rulezz!")具体内容见markdown-it官方文档 |
Method API
通过方法 API,可以通过程序触发组件内部的方法,比如提交表单,显示弹窗等, 可以通过$w.componentId.methodName
来调用组件方法,如 $w.form1.submit()
方法名 | 方法标识 | 参数 | 方法说明 |
---|
更新markdown实例 | updateMarkdownInstance | object
| 更新markdown实例 |
Style API
通过样式 API,可以覆盖组件中内部元素的样式来实现自定义,例如在低代码编辑器中中通过 #wd-page-root .wd-btn
即可为所有的按钮组件编写样式,通过 :scope
可以控制单个组件样式, 详细说明请参考样式 API
名称 | 类名 | 说明和示例 |
---|
根元素 | .wd-markdown | 链接组件根元素
|
PC 端链接根元素 | .wd-pc-markdown | 可以为 PC 端的链接编写样式
|
H5 端链接根元素 | .wd-h5-markdown | 可以为 H5 端的链接编写样式
|
小程序端链接根元素 | .wd-mp-markdown | 可以为小程序端的链接编写样式
|
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.